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