/// <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; }
/// <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; }