/// <summary> /// Updates the current payload kind from the given query results if needed. This is to account for open-property values /// being either 'value' or 'binaryvalue' depending on the instance type. /// </summary> /// <param name="queryResults">The query results.</param> /// <param name="provider">The provider.</param> internal void UpdatePayloadKindFromValueIfNeeded(QueryResultInfo queryResults, DataServiceProviderWrapper provider) { // now determine the payload kind if (this.TargetKind == RequestTargetKind.OpenPropertyValue) { object element = queryResults.Current; ResourceType resourceType = WebUtil.GetResourceType(provider, element); Debug.Assert(resourceType != null, "resourceType != null, WebUtil.GetResourceType() should throw if it fails to resolve the resource type."); if (WebUtil.IsBinaryResourceType(resourceType)) { this.responsePayloadKind = ODataPayloadKind.BinaryValue; } else { this.responsePayloadKind = ODataPayloadKind.Value; } } }
/// <summary> /// Creates a new instance of QueryResultInfo. /// For performance reasons we reuse results from existing query to read a projected value. We create an enumerator /// containing the projected value but must not dispose the original query until later. This wrapper allows us to /// pass the created enumerator and dispose the query at the right time. /// </summary> /// <param name="queryResults">Query results that we need to enumerate and serialize.</param> /// <param name="originalResults">Actual query that we need to dispose.</param> internal QueryResultInfo(IEnumerable queryResults, QueryResultInfo originalResults) : this(queryResults) { this.originalQueryResults = originalResults; }
/// <summary>Initializes a new <see cref="ResponseBodyWriter"/> that can write the body of a response.</summary> /// <param name="service">Service for the request being processed.</param> /// <param name="queryResults">Enumerator for results.</param> /// <param name="requestDescription">Description of request made to the system.</param> /// <param name="actualResponseMessageWhoseHeadersMayBeOverridden">IODataResponseMessage instance for the response.</param> internal ResponseBodyWriter( IDataService service, QueryResultInfo queryResults, RequestDescription requestDescription, IODataResponseMessage actualResponseMessageWhoseHeadersMayBeOverridden) { Debug.Assert(service != null, "service != null"); Debug.Assert(requestDescription != null, "requestDescription != null"); Debug.Assert(actualResponseMessageWhoseHeadersMayBeOverridden != null, "actualResponseMessageWhoseHeadersMayBeOverridden != null"); this.service = service; this.queryResults = queryResults; this.requestDescription = requestDescription; this.actualResponseMessageWhoseHeadersMayBeOverridden = actualResponseMessageWhoseHeadersMayBeOverridden; Debug.Assert(this.PayloadKind != ODataPayloadKind.Unsupported, "payloadKind != ODataPayloadKind.Unsupported"); this.encoding = ContentTypeUtil.EncodingFromAcceptCharset(this.service.OperationContext.RequestMessage.GetRequestAcceptCharsetHeader()); if (this.PayloadKind == ODataPayloadKind.Entry || this.PayloadKind == ODataPayloadKind.Feed || this.PayloadKind == ODataPayloadKind.Property || this.PayloadKind == ODataPayloadKind.Collection || this.PayloadKind == ODataPayloadKind.EntityReferenceLink || this.PayloadKind == ODataPayloadKind.EntityReferenceLinks || this.PayloadKind == ODataPayloadKind.Error || this.PayloadKind == ODataPayloadKind.ServiceDocument || this.PayloadKind == ODataPayloadKind.Parameter) { AstoriaRequestMessage requestMessage = service.OperationContext.RequestMessage; IODataResponseMessage responseMessageOnOperationContext = service.OperationContext.ResponseMessage; Version effectiveMaxResponseVersion = VersionUtil.GetEffectiveMaxResponseVersion(service.Configuration.DataServiceBehavior.MaxProtocolVersion.ToVersion(), requestMessage.RequestMaxVersion); bool isEntityOrFeed = this.PayloadKind == ODataPayloadKind.Entry || this.PayloadKind == ODataPayloadKind.Feed; if (ContentTypeUtil.IsResponseMediaTypeJsonLight(requestMessage.GetAcceptableContentTypes(), isEntityOrFeed, effectiveMaxResponseVersion)) { // If JSON light 'wins', then bump the version to V3. requestDescription.VerifyAndRaiseResponseVersion(VersionUtil.Version4Dot0, service); responseMessageOnOperationContext.SetHeader(XmlConstants.HttpODataVersion, XmlConstants.ODataVersion4Dot0 + ";"); } } if (this.requestDescription.TargetKind == RequestTargetKind.MediaResource) { Debug.Assert(this.PayloadKind == ODataPayloadKind.BinaryValue, "payloadKind == ODataPayloadKind.BinaryValue"); // Note that GetReadStream will set the ResponseETag before it returns this.mediaResourceStream = service.StreamProvider.GetReadStream( this.queryResults.Current, this.requestDescription.StreamProperty, this.service.OperationContext); } else if (this.PayloadKind != ODataPayloadKind.BinaryValue) { IEdmModel model; if (this.PayloadKind == ODataPayloadKind.MetadataDocument) { model = MetadataSerializer.PrepareModelForSerialization(this.service.Provider, this.service.Configuration); } else { model = this.GetModelFromService(); } // Create the message writer using which the response needs to be written. this.messageWriterBuilder = MessageWriterBuilder.ForNormalRequest( this.service, this.requestDescription, this.actualResponseMessageWhoseHeadersMayBeOverridden, model); this.messageWriter = this.messageWriterBuilder.CreateWriter(); try { // Make sure all the headers are written before the method returns. this.contentFormat = ODataUtils.SetHeadersForPayload(this.messageWriter, this.PayloadKind); } catch (ODataContentTypeException contentTypeException) { throw new DataServiceException(415, null, Strings.DataServiceException_UnsupportedMediaType, null, contentTypeException); } Debug.Assert(requestDescription.ResponseFormat != null, "Response format should already have been determined."); Debug.Assert(ReferenceEquals(this.contentFormat, requestDescription.ResponseFormat.Format), "Response format in request description did not match format when writing."); if (this.PayloadKind == ODataPayloadKind.Value && !String.IsNullOrEmpty(this.requestDescription.MimeType)) { this.actualResponseMessageWhoseHeadersMayBeOverridden.SetHeader(XmlConstants.HttpContentType, this.requestDescription.MimeType); } // EPM is currently removed, but this doesn't seem to be used for EPM only. The old comment was saying: // In astoria, there is a bug in V1/V2 that while computing response version, we did not take // epm into account. Hence while creating the writer, we need to pass the RequestDescription.ActualResponseVersion // so that ODataLib can do the correct payload validation. But we need to write the response version without // the epm into the response headers because of backward-compat issue. Hence over-writing the response version // header with the wrong version value. string responseVersion = this.requestDescription.ResponseVersion.ToString() + ";"; this.actualResponseMessageWhoseHeadersMayBeOverridden.SetHeader(XmlConstants.HttpODataVersion, responseVersion); } }