Ejemplo n.º 1
0
        public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage)
        {
            object result;

            if (this.HttpMethod == HttpMethod.GET)
            {
                // we cannot invoke same action request multiple times, so only Functions are allowed to do the server-driven paging
                this.QueryContext.InitializeServerDrivenPaging(this.PreferenceContext);

                result = this.ProcessFunction();

                if (this.PreferenceContext.MaxPageSize.HasValue)
                {
                    responseMessage.AddPreferenceApplied(string.Format("{0}={1}", ServiceConstants.Preference_MaxPageSize, this.QueryContext.appliedPageSize.Value));
                }
            }
            else
            {
                // TODO: currently ETag feature does not support action operation

                result = this.ProcessAction(requestMessage);
            }

            if (result == null)
            {
                // Protocol 9.1.4 Response Code 204 No Content
                // A request returns 204 No Content if the requested resource has the null value,
                // or if the service applies a return=minimal preference. In this case, the response body MUST be empty.
                ResponseWriter.WriteEmptyResponse(responseMessage);

                return;
            }

            using (var messageWriter = this.CreateMessageWriter(responseMessage))
            {
                if (this.QueryContext.Target.TypeKind == EdmTypeKind.None ||
                    this.QueryContext.Target.TypeKind == EdmTypeKind.EntityReference ||
                    this.QueryContext.Target.ElementTypeKind == EdmTypeKind.EntityReference)
                {
                    throw Utility.BuildException(HttpStatusCode.NotImplemented, "Unsupported return type in operation.", null);
                }
                else if (this.QueryContext.Target.TypeKind == EdmTypeKind.Entity || this.QueryContext.Target.ElementTypeKind == EdmTypeKind.Entity ||
                         this.QueryContext.Target.TypeKind == EdmTypeKind.Complex || this.QueryContext.Target.ElementTypeKind == EdmTypeKind.Complex)
                {
                    ODataWriter resultWriter;

                    IEdmNavigationSource entitySource = this.QueryContext.OperationResultSource ?? this.QueryContext.Target.NavigationSource;

                    if (this.QueryContext.Target.TypeKind == EdmTypeKind.Collection)
                    {
                        IEdmEntitySetBase entitySet = (IEdmEntitySetBase)entitySource;

                        resultWriter = messageWriter.CreateODataResourceSetWriter(entitySet, (IEdmStructuredType)this.QueryContext.Target.ElementType);
                        ResponseWriter.WriteFeed(resultWriter, (IEdmStructuredType)this.QueryContext.Target.ElementType, result as IEnumerable, entitySet, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause, this.QueryContext.TotalCount, null, this.QueryContext.NextLink, this.RequestHeaders);
                    }
                    else
                    {
                        if (this.HttpMethod == HttpMethod.GET)
                        {
                            var currentETag = Utility.GetETagValue(result);
                            // if the current entity has ETag field
                            if (currentETag != null)
                            {
                                string requestETag;
                                if (Utility.TryGetIfNoneMatch(this.RequestHeaders, out requestETag) && (requestETag == ServiceConstants.ETagValueAsterisk || requestETag == currentETag))
                                {
                                    ResponseWriter.WriteEmptyResponse(responseMessage, HttpStatusCode.NotModified);
                                    return;
                                }

                                responseMessage.SetHeader(ServiceConstants.HttpHeaders.ETag, currentETag);
                            }
                        }

                        resultWriter = messageWriter.CreateODataResourceWriter(entitySource, (IEdmStructuredType)this.QueryContext.Target.Type);
                        ResponseWriter.WriteEntry(resultWriter, result, entitySource, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause, this.RequestHeaders);
                    }
                }
                else
                {
                    ODataProperty property = new ODataProperty()
                    {
                        Name = "value", Value = ODataObjectModelConverter.CreateODataValue(result)
                    };
                    messageWriter.WriteProperty(property);
                }
            }
        }
Ejemplo n.º 2
0
        public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage)
        {
            if (this.TryDispatch(requestMessage, responseMessage))
            {
                return;
            }

            this.QueryContext.InitializeServerDrivenPaging(this.PreferenceContext);
            this.QueryContext.InitializeTrackingChanges(this.PreferenceContext);

            object queryResults = this.QueryContext.ResolveQuery(this.DataSource);

            if (queryResults == null)
            {
                // For individual property or $value
                if (this.QueryContext.Target.Property != null)
                {
                    // Protocol 9.1.4 Response Code 204 No Content
                    // A request returns 204 No Content if the requested resource has the null value,
                    // or if the service applies a return=minimal preference. In this case, the response body MUST be empty.
                    ResponseWriter.WriteEmptyResponse(responseMessage);

                    return;
                }
                else
                {
                    throw Utility.BuildException(HttpStatusCode.NotFound);
                }
            }

            // Handle the prefer of "odata.include-annotations", including it in response header
            if (!string.IsNullOrEmpty(this.PreferenceContext.IncludeAnnotations))
            {
                responseMessage.AddPreferenceApplied(string.Format("{0}={1}",
                                                                   ServiceConstants.Preference_IncludeAnnotations, this.PreferenceContext.IncludeAnnotations));
            }

            if (this.PreferenceContext.MaxPageSize.HasValue)
            {
                responseMessage.AddPreferenceApplied(string.Format("{0}={1}", ServiceConstants.Preference_MaxPageSize, this.QueryContext.appliedPageSize.Value));
            }

            if (this.PreferenceContext.TrackingChanges)
            {
                responseMessage.AddPreferenceApplied(ServiceConstants.Preference_TrackChanging);
            }

            responseMessage.SetStatusCode(HttpStatusCode.OK);

            using (var messageWriter = this.CreateMessageWriter(responseMessage))
            {
                IEdmNavigationSource navigationSource   = this.QueryContext.Target.NavigationSource;
                IEnumerable          iEnumerableResults = queryResults as IEnumerable;

                if (this.QueryContext.Target.IsReference && this.QueryContext.Target.TypeKind == EdmTypeKind.Collection)
                {
                    // Query a $ref collection
                    IList <ODataEntityReferenceLink> links = new List <ODataEntityReferenceLink>();

                    foreach (var iEnumerableResult in iEnumerableResults)
                    {
                        var link = new ODataEntityReferenceLink
                        {
                            Url = Utility.BuildLocationUri(this.QueryContext, iEnumerableResult),
                        };
                        links.Add(link);
                    }

                    ODataEntityReferenceLinks linksCollection = new ODataEntityReferenceLinks()
                    {
                        Links = links, NextPageLink = this.QueryContext.NextLink
                    };
                    linksCollection.InstanceAnnotations.Add(new ODataInstanceAnnotation("Links.Annotation", new ODataPrimitiveValue(true)));
                    messageWriter.WriteEntityReferenceLinks(linksCollection);
                }
                else if (this.QueryContext.Target.IsReference && this.QueryContext.Target.TypeKind == EdmTypeKind.Entity)
                {
                    // Query a $ref
                    var link = new ODataEntityReferenceLink
                    {
                        Url = Utility.BuildLocationUri(this.QueryContext, queryResults),
                    };
                    link.InstanceAnnotations.Add(new ODataInstanceAnnotation("Link.Annotation", new ODataPrimitiveValue(true)));

                    messageWriter.WriteEntityReferenceLink(link);
                }
                else if (this.QueryContext.Target.NavigationSource != null && this.QueryContext.Target.TypeKind == EdmTypeKind.Collection)
                {
                    // Query a feed
                    IEdmEntitySetBase entitySet  = navigationSource as IEdmEntitySetBase;
                    IEdmEntityType    entityType = this.QueryContext.Target.ElementType as IEdmEntityType;

                    if (entitySet == null || entityType == null)
                    {
                        throw new InvalidOperationException("Invalid target when query feed.");
                    }

                    ODataWriter resultWriter = messageWriter.CreateODataFeedWriter(entitySet, entityType);

                    ResponseWriter.WriteFeed(resultWriter, iEnumerableResults, entitySet, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause, this.QueryContext.TotalCount, this.QueryContext.DeltaLink, this.QueryContext.NextLink, this.RequestHeaders);
                    resultWriter.Flush();
                }
                else if (this.QueryContext.Target.NavigationSource != null && this.QueryContext.Target.TypeKind == EdmTypeKind.Entity)
                {
                    var currentETag = Utility.GetETagValue(queryResults);
                    // if the current entity has ETag field
                    if (currentETag != null)
                    {
                        string requestETag;
                        if (Utility.TryGetIfNoneMatch(this.RequestHeaders, out requestETag) && (requestETag == ServiceConstants.ETagValueAsterisk || requestETag == currentETag))
                        {
                            ResponseWriter.WriteEmptyResponse(responseMessage, HttpStatusCode.NotModified);
                            return;
                        }

                        responseMessage.SetHeader(ServiceConstants.HttpHeaders.ETag, currentETag);
                    }

                    // Query a single entity
                    IEdmEntityType entityType = this.QueryContext.Target.Type as IEdmEntityType;

                    ODataWriter resultWriter = messageWriter.CreateODataEntryWriter(navigationSource, entityType);
                    ResponseWriter.WriteEntry(resultWriter, queryResults, navigationSource, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause, this.RequestHeaders);
                    resultWriter.Flush();
                }
                else if (this.QueryContext.Target.Property != null && !this.QueryContext.Target.IsRawValue)
                {
                    // Query a individual property
                    ODataProperty property = ODataObjectModelConverter.CreateODataProperty(queryResults, this.QueryContext.Target.Property.Name);
                    messageWriter.WriteProperty(property);
                }
                else if (this.QueryContext.Target.IsRawValue)
                {
                    // Query a $value or $count
                    var propertyValue = ODataObjectModelConverter.CreateODataValue(queryResults);
                    messageWriter.WriteValue(propertyValue);
                }
                else
                {
                    throw Utility.BuildException(HttpStatusCode.NotImplemented);
                }
            }
        }