Example #1
0
        /// <summary>
        /// Gets the expected payload type for a request to the given uri
        /// </summary>
        /// <param name="requestUri">The request uri</param>
        /// <returns>The expected payload type</returns>
        public static ODataPayloadElementType GetExpectedPayloadType(this ODataUri requestUri)
        {
            if (requestUri.Segments.OfType <UnrecognizedSegment>().Any())
            {
                return(ODataPayloadElementType.Unknown);
            }

            if (requestUri.IsMetadata())
            {
                return(ODataPayloadElementType.MetadataPayloadElement);
            }

            if (requestUri.IsBatch())
            {
                return(ODataPayloadElementType.BatchResponsePayload);
            }

            if (requestUri.IsCount() || requestUri.IsPropertyValue() || requestUri.IsMediaResource() || requestUri.IsNamedStream())
            {
                return(ODataPayloadElementType.PrimitiveValue);
            }

            if (requestUri.IsEntity())
            {
                return(ODataPayloadElementType.EntityInstance);
            }

            if (requestUri.IsEntitySet())
            {
                return(ODataPayloadElementType.EntitySetInstance);
            }

            if (requestUri.IsEntityReferenceLink())
            {
                return(requestUri.GetExpectedLinkPayloadType());
            }

            if (requestUri.IsProperty())
            {
                var property = requestUri.Segments.OfType <PropertySegment>().Last();
                return(property.Property.GetExpectedPayloadType());
            }

            if (requestUri.IsServiceOperation() || requestUri.IsAction())
            {
                var serviceOp = requestUri.Segments.OfType <FunctionSegment>().Last();
                return(serviceOp.Function.GetExpectedPayloadType());
            }

            return(ODataPayloadElementType.Unknown);
        }
        /// <summary>
        /// Returns the strategy to use for serializing/deserialzing the given content type
        /// </summary>
        /// <param name="contentType">The content type</param>
        /// <param name="uri">The request uri</param>
        /// <returns>A serialization strategy</returns>
        public virtual IProtocolFormatStrategy GetStrategy(string contentType, ODataUri uri)
        {
            if (uri != null)
            {
                // if its a named stream or an MLE, handle the returned payload as a binary stream
                if (uri.IsNamedStream() || uri.IsMediaResource())
                {
                    return this.BinaryValueStrategy;
                }

                // if its a raw $count request, we need to use a different strategy
                if (uri.IsCount() && IsPlainTextMimeType(contentType))
                {
                    return this.CountStrategy;
                }
            }

            if (IsXmlMimeType(contentType))
            {
                return this.XmlStrategy;
            }
            
            if (IsJsonMimeType(contentType))
            {
                return this.JsonStrategy;
            }

            if (IsTextBasedMimeType(contentType))
            {
                return this.TextValueStrategy;
            }

            if (IsHtmlFormMimeType(contentType))
            {
                return this.HtmlFormStrategy;
            }

            return this.BinaryValueStrategy;
        }
        internal static string DetermineAcceptType(ODataUri uri, string defaultAcceptType)
        {
            if (uri.IsNamedStream() || uri.IsMediaResource())
            {
                return MimeTypes.Any;
            }

            if (uri.IsCount())
            {
                return MimeTypes.TextPlain;
            }

            if (uri.IsPropertyValue())
            {
                string propertyAcceptType = MimeTypes.Any;
                var propertySegment = uri.Segments[uri.Segments.Count - 2] as PropertySegment;
                ExceptionUtilities.CheckObjectNotNull(propertySegment, "Cannot get Property segment from uri");
                var mimeTypeAnnotation = propertySegment.Property.Annotations.OfType<MimeTypeAnnotation>().SingleOrDefault();
                if (mimeTypeAnnotation != null)
                {
                    propertyAcceptType = mimeTypeAnnotation.MimeTypeValue;
                }

                return propertyAcceptType;
            }

            return defaultAcceptType;
        }
        /// <summary>
        /// Calculates the protocol version based on the ODataUri provided
        /// </summary>
        /// <param name="uri">OData Uri to analyze</param>
        /// <param name="contentType">Content Type</param>
        /// <param name="maxProtocolVersion">The max protocol version</param>
        /// <param name="dataServiceVersion">The data service version of the request</param>
        /// <param name="maxDataServiceVersion">The max data service version of the request</param>
        /// <returns>Data Service Protocol Version</returns>
        public DataServiceProtocolVersion CalculateProtocolVersion(ODataUri uri, string contentType, DataServiceProtocolVersion maxProtocolVersion, DataServiceProtocolVersion dataServiceVersion, DataServiceProtocolVersion maxDataServiceVersion)
        {
            ExceptionUtilities.CheckArgumentNotNull(uri, "uri");
            ExceptionUtilities.Assert(maxProtocolVersion != DataServiceProtocolVersion.Unspecified, "Max protocol version cannot be unspecified");

            if (uri.IsMetadata())
            {
                throw new TaupoNotSupportedException("Context uri should be processed by Entity Model Version Calculator instead");
            }

            DataServiceProtocolVersion expectedVersion = DataServiceProtocolVersion.V4;

            if (uri.IncludesInlineCountAllPages())
            {
                expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, DataServiceProtocolVersion.V4);
            }

            if (uri.IsCount())
            {
                expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, DataServiceProtocolVersion.V4);
            }
            else if (uri.IsEntityReferenceLink() || uri.IsNamedStream() || uri.IsPropertyValue())
            {
                // If the uri points to a Link, $value or a named stream their response DSV's are V1 because their payloads are understood by V1
                expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, DataServiceProtocolVersion.V4);
            }
            else if (uri.HasOpenProperties())
            {
                expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, VersionHelper.GetMinimumVersion(maxProtocolVersion, maxDataServiceVersion));
            }
            else if (uri.IsProperty())
            {
                var propertySegment = (PropertySegment)uri.LastSegment;
                expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, VersionHelper.CalculateProtocolVersion(propertySegment.Property));
            }
            else if (uri.IsAction())
            {
                var action = (FunctionSegment)uri.LastSegment;
                if (action.Function.ReturnType != null)
                {
                    var collectionReturnType = action.Function.ReturnType as CollectionDataType;

                    // If its a collection this doesn't bump things to V3 as this is normal behavior from ServiceOperations V1, so only determining version based on non data type
                    DataType versionType = action.Function.ReturnType;
                    
                    var entityVersionType = action.Function.ReturnType as EntityDataType;
                    if (collectionReturnType != null)
                    {
                        entityVersionType = collectionReturnType.ElementDataType as EntityDataType;
                        if (entityVersionType != null)
                        {
                            versionType = entityVersionType;
                        }
                    }

                    // Bump if its an open type
                    if (entityVersionType != null && entityVersionType.Definition.IsOpen)
                    {
                        expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, VersionHelper.GetMinimumVersion(maxProtocolVersion, maxDataServiceVersion));
                    }

                    expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, VersionHelper.CalculateDataTypeVersion(versionType));
                }
            }
            else
            {
                ExceptionUtilities.CheckArgumentNotNull(contentType, "contentType");
                List<DataServiceProtocolVersion> dataServiceProtocolVersions = uri.GetAllEntitySetsIncludingExpands().Select(es => es.CalculateEntitySetProtocolVersion(contentType, VersionCalculationType.Response, maxProtocolVersion, maxDataServiceVersion)).ToList();
                dataServiceProtocolVersions.Add(expectedVersion);
                expectedVersion = VersionHelper.GetMaximumVersion(dataServiceProtocolVersions.ToArray());
            }

            // determine if the uri MIGHT result in there being a next link, and increase version if so
            expectedVersion = VersionHelper.IncreaseVersionIfTrue(ResponseMightIncludeNextLink(uri), expectedVersion, DataServiceProtocolVersion.V4);

            return expectedVersion;
        }
Example #5
0
        /// <summary>
        /// Processes the given uri and produces an expected value according to the conventions of an OData server implementation
        /// </summary>
        /// <param name="uri">The uri to process</param>
        /// <param name="applySelectAndExpand">A value indicating whether or not $select and $expand should be applied to the query values</param>
        /// <param name="applyPaging">A value indicating whether server-driven paging should be applied to the query values</param>
        /// <returns>The value resulting from processing the uri</returns>
        public QueryValue Evaluate(ODataUri uri, bool applySelectAndExpand, bool applyPaging)
        {
            this.applyPagingInExpands = applyPaging;
            ExceptionUtilities.CheckArgumentNotNull(uri, "uri");
            ExceptionUtilities.CheckCollectionNotEmpty(uri.Segments, "uri.Segments");
            ExceptionUtilities.CheckAllRequiredDependencies(this);

            this.currentUri = uri;
            this.shouldLastSegmentBeSingleton = false;

            applyPaging &= uri.TryGetExpectedEntitySet(out this.expectedEntitySet);

            if (applyPaging)
            {
                // compute the expected page size for this request based on the existence of a universal page size or set-specific page size
                this.expectedPageSize = this.expectedEntitySet.GetEffectivePageSize();
            }
            else
            {
                this.expectedPageSize = null;
            }

            var query = this.BuildQueryFromSegments();
            ExceptionUtilities.CheckObjectNotNull(query, "Could not build query from uri '{0}'", uri);

            // we explicitly do not process expand or select here because they do not affect the number of rows returned or their ordering
            query = this.ProcessFilter(query);
            ExceptionUtilities.CheckObjectNotNull(query, "Could not build query from uri '{0}'", uri);

            if (uri.IsEntitySet())
            {
                // TODO: skip-token processing should happen before ordering
                query = this.ProcessOrderBy(query);
                ExceptionUtilities.CheckObjectNotNull(query, "Could not build query from uri '{0}'", uri);

                query = this.ProcessSkipAndTop(query);
                ExceptionUtilities.CheckObjectNotNull(query, "Could not build query from uri '{0}'", uri);
            }

            // handle $count requests
            if (uri.IsCount())
            {
                query = query.LongCount();
            }

            // need to resolve types since we constructed new QueryExpression tree
            var resolvedQuery = this.QueryResolver.Resolve(query);

            var value = this.Evaluator.Evaluate(resolvedQuery);
            ExceptionUtilities.CheckObjectNotNull(value, "Could not evaluate query '{0}'", query);
            ExceptionUtilities.Assert(value.EvaluationError == null, "Query evaluation produced an error: {0}", value.EvaluationError);

            // post-process the result to defer properties that were not expanded
            if (applySelectAndExpand)
            {
                value = this.ApplySelectAndExpand(uri, value);
            }

            // fixup for key expressions that should return singletons
            if (this.shouldLastSegmentBeSingleton)
            {
                value = EnsureLastSegmentIsSingletonOrNull(value);
            }

            this.currentUri = null;
            this.expectedEntitySet = null;
            this.expectedPageSize = null;

            return value;
        }