public static void AddPreferenceApplied(this IODataResponseMessage message, string appliedPref) { if (!string.IsNullOrEmpty(appliedPref)) { if (string.IsNullOrEmpty(message.GetHeader(ServiceConstants.HttpHeaders.PreferenceApplied))) { message.SetHeader(ServiceConstants.HttpHeaders.PreferenceApplied, appliedPref); } else { message.SetHeader(ServiceConstants.HttpHeaders.PreferenceApplied, string.Format("{0};{1}", message.GetHeader(ServiceConstants.HttpHeaders.PreferenceApplied), appliedPref)); } } }
/// <summary>set the http web response</summary> /// <param name="response">response object</param> protected virtual void SetHttpWebResponse(IODataResponseMessage response) { this.responseMessage = response; this.statusCode = (HttpStatusCode)response.StatusCode; string stringContentLength = response.GetHeader(XmlConstants.HttpContentLength); if (stringContentLength != null) { this.contentLength = int.Parse(stringContentLength, CultureInfo.InvariantCulture); } else { // Since the unintialized value of ContentLength header is -1, we need to return // -1 if the content length header is not present this.contentLength = -1; } this.contentType = response.GetHeader(XmlConstants.HttpContentType); }
/// <summary>operation with exception</summary> /// <param name="e">exception object</param> /// <param name="response">response object</param> private void HandleOperationException(InvalidOperationException e, IODataResponseMessage response) { Debug.Assert(this.entryIndex >= 0 && this.entryIndex < this.ChangedEntries.Count, string.Format(System.Globalization.CultureInfo.InvariantCulture, "this.entryIndex = '{0}', this.ChangedEntries.Count = '{1}'", this.entryIndex, this.ChangedEntries.Count)); Descriptor current = this.ChangedEntries[this.entryIndex]; HeaderCollection headers = null; HttpStatusCode statusCode = HttpStatusCode.InternalServerError; Version responseVersion = null; if (response != null) { headers = new HeaderCollection(response); statusCode = (HttpStatusCode)response.StatusCode; this.HandleOperationResponseHeaders(statusCode, headers); e = BaseSaveResult.HandleResponse( this.RequestInfo, statusCode, response.GetHeader(XmlConstants.HttpODataVersion), response.GetStream, false /*throwOnFailure*/, out responseVersion); } else { headers = new HeaderCollection(); headers.SetHeader(XmlConstants.HttpContentType, XmlConstants.MimeTextPlain); // In V2 we used to merge individual responses from a call to SaveChanges() into a single batch response payload and then process that. // When we encounter an exception at this point in V2, we used to write the exception to the batch response payload and later on when we // process through the batch response, we create a DataServiceClientException for each failed operation. // For backcompat reason, we will always convert the exception type to DataServiceClientException here. Debug.Assert(e != null, "e != null"); if (e.GetType() != typeof(DataServiceClientException)) { e = new DataServiceClientException(e.Message, e); } } // For error scenarios, we never invoke the ReadingEntity event. this.cachedResponses.Add(new CachedResponse(current, headers, statusCode, responseVersion, null, e)); this.perRequest = null; this.CheckContinueOnError(); }
/// <summary> /// Handles an exception that occurred while writing a response. /// </summary> /// <param name="service">Data service doing the processing.</param> /// <param name="exception">The exception that was thrown.</param> /// <param name="responseMessage">The response message.</param> /// <param name="messageWriter">The message writer, if null this will fall back to writing a raw XML error to the stream.</param> /// <param name="encoding">The encoding to while writing the error.</param> /// <param name="responseStream">The response stream to write the error to.</param> /// <param name="messageWriterBuilder">MessageWriterBuilder to use in case a new ODataMessageWriter needs to be constructed.</param> internal static void HandleExceptionWhileWriting(IDataService service, Exception exception, IODataResponseMessage responseMessage, ODataMessageWriter messageWriter, Encoding encoding, Stream responseStream, MessageWriterBuilder messageWriterBuilder) { Debug.Assert(service != null, "service != null"); Debug.Assert(service.Configuration != null, "service.Configuration != null"); Debug.Assert(exception != null, "exception != null"); Debug.Assert(CommonUtil.IsCatchableExceptionType(exception), "CommonUtil.IsCatchableExceptionType(exception)"); Debug.Assert(responseMessage != null, "responseMessage != null"); string contentType = responseMessage.GetHeader(XmlConstants.HttpContentType); HandleExceptionArgs args = new HandleExceptionArgs(exception, true, contentType, service.Configuration.UseVerboseErrors); service.InternalHandleException(args); service.OperationContext.RequestMessage.ProcessException(args); ODataError error = args.CreateODataError(); WriteErrorWithFallbackForXml(messageWriter, encoding, responseStream, args, error, messageWriterBuilder); }
/// <summary> /// Creates an <see cref="ODataMessageReader"/> for a given message and context using /// WCF DS client settings. /// </summary> /// <param name="responseMessage">The response message</param> /// <param name="responseInfo">The response context</param> /// <param name="payloadKind">Type of the message.</param> /// <returns>The message reader.</returns> protected static ODataMessageReader CreateODataMessageReader(IODataResponseMessage responseMessage, ResponseInfo responseInfo, ref ODataPayloadKind payloadKind) { ODataMessageReaderSettings settings = responseInfo.ReadHelper.CreateSettings(); ODataMessageReader odataMessageReader = responseInfo.ReadHelper.CreateReader(responseMessage, settings); if (payloadKind == ODataPayloadKind.Unsupported) { var payloadKinds = odataMessageReader.DetectPayloadKind().ToList(); if (payloadKinds.Count == 0) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidResponsePayload(XmlConstants.DataWebNamespace)); } // Pick the first payload kind detected by ODataLib and use that to parse the exception. // The only exception being payload with entity reference link(s). If one of the payload kinds // is reference links, then we need to give preference to reference link payloads. ODataPayloadKindDetectionResult detectionResult = payloadKinds.FirstOrDefault(k => k.PayloadKind == ODataPayloadKind.EntityReferenceLink || k.PayloadKind == ODataPayloadKind.EntityReferenceLinks); if (detectionResult == null) { detectionResult = payloadKinds.First(); } if (detectionResult.Format != ODataFormat.Json && detectionResult.Format != ODataFormat.RawValue) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidContentTypeEncountered(responseMessage.GetHeader(XmlConstants.HttpContentType))); } payloadKind = detectionResult.PayloadKind; } return(odataMessageReader); }
/// <summary> /// Validates that we can read the response format. /// </summary> /// <param name="responseMessage">The response message to get the format from.</param> internal void ValidateCanReadResponseFormat(IODataResponseMessage responseMessage) { string contentType = responseMessage.GetHeader(XmlConstants.HttpContentType); this.ValidateContentType(contentType, false /*isParameterPayload*/, true /*isResponse*/); }
protected static ODataMessageReader CreateODataMessageReader(IODataResponseMessage responseMessage, ResponseInfo responseInfo, ref ODataPayloadKind payloadKind) { ODataMessageReaderSettings settings = responseInfo.ReadHelper.CreateSettings(ReadingEntityInfo.BufferAndCacheEntryPayload); ODataMessageReader odataMessageReader = responseInfo.ReadHelper.CreateReader(responseMessage, settings); if (payloadKind == ODataPayloadKind.Unsupported) { var payloadKinds = odataMessageReader.DetectPayloadKind().ToList(); if (payloadKinds.Count == 0) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidResponsePayload(responseInfo.DataNamespace)); } // Pick the first payload kind detected by ODataLib and use that to parse the exception. // The only exception being payload with entity reference link(s). If one of the payload kinds // is reference links, then we need to give preference to reference link payloads. ODataPayloadKindDetectionResult detectionResult = payloadKinds.FirstOrDefault(k => k.PayloadKind == ODataPayloadKind.EntityReferenceLink || k.PayloadKind == ODataPayloadKind.EntityReferenceLinks); if (detectionResult == null) { ODataVersion dataServiceVersion = responseMessage.GetDataServiceVersion(CommonUtil.ConvertToODataVersion(responseInfo.MaxProtocolVersion)); // if its a collection or a Property we should choose collection if its less than V3, this enables older service operations on Execute if (dataServiceVersion < ODataVersion.V3 && payloadKinds.Any(pk => pk.PayloadKind == ODataPayloadKind.Property) && payloadKinds.Any(pk => pk.PayloadKind == ODataPayloadKind.Collection)) { detectionResult = payloadKinds.Single(pk => pk.PayloadKind == ODataPayloadKind.Collection); } else { detectionResult = payloadKinds.First(); } } // Astoria client only supports atom, jsonverbose, jsonlight and raw value payloads. if (detectionResult.Format != ODataFormat.Atom && detectionResult.Format != ODataFormat.VerboseJson && detectionResult.Format != ODataFormat.Json && detectionResult.Format != ODataFormat.RawValue) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidContentTypeEncountered(responseMessage.GetHeader(XmlConstants.HttpContentType))); } payloadKind = detectionResult.PayloadKind; } return(odataMessageReader); }
/// <summary> /// Validates that we can read the response format. /// </summary> /// <param name="responseMessage">The response message to get the format from.</param> internal static void ValidateCanReadResponseFormat(IODataResponseMessage responseMessage) { string contentType = responseMessage.GetHeader(XmlConstants.HttpContentType); ValidateContentType(contentType); }
private void HandleOperationResponseData(IODataResponseMessage responseMsg, Stream responseStream) { Debug.Assert(this.entryIndex >= 0 && this.entryIndex < this.ChangedEntries.Count(), string.Format(System.Globalization.CultureInfo.InvariantCulture, "this.entryIndex = '{0}', this.ChangedEntries.Count() = '{1}'", this.entryIndex, this.ChangedEntries.Count())); // Parse the response Descriptor current = this.ChangedEntries[this.entryIndex]; MaterializerEntry entry = default(MaterializerEntry); Version responseVersion; Exception exception = BaseSaveResult.HandleResponse(this.RequestInfo, (HttpStatusCode)responseMsg.StatusCode, responseMsg.GetHeader(XmlConstants.HttpODataVersion), () => { return responseStream; }, false/*throwOnFailure*/, out responseVersion); var headers = new HeaderCollection(responseMsg); if (responseStream != null && current.DescriptorKind == DescriptorKind.Entity && exception == null) { // Only process the response if the current resource is an entity and it's an insert or update scenario EntityDescriptor entityDescriptor = (EntityDescriptor)current; // We were ignoring the payload for non-insert and non-update scenarios. We need to keep doing that. if (entityDescriptor.State == EntityStates.Added || entityDescriptor.StreamState == EntityStates.Added || entityDescriptor.State == EntityStates.Modified || entityDescriptor.StreamState == EntityStates.Modified) { try { ResponseInfo responseInfo = this.CreateResponseInfo(entityDescriptor); var responseMessageWrapper = new HttpWebResponseMessage( headers, responseMsg.StatusCode, () => responseStream); entry = ODataReaderEntityMaterializer.ParseSingleEntityPayload(responseMessageWrapper, responseInfo, entityDescriptor.Entity.GetType()); entityDescriptor.TransientEntityDescriptor = entry.EntityDescriptor; } catch (Exception ex) { exception = ex; if (!CommonUtil.IsCatchableExceptionType(ex)) { throw; } } } } this.cachedResponses.Add(new CachedResponse( current, headers, (HttpStatusCode)responseMsg.StatusCode, responseVersion, entry, exception)); if (exception != null) { current.SaveError = exception; // DEVNOTE(pqian): // There are two possible scenario here: // 1. We are in the sync code path, and there's an in stream error on the server side, or there are bad xml thrown // 2. We are in the async code path, there's a error thrown on the server side (any error) // Ideally, we need to check whether we want to continue to the next changeset. (Call this.CheckContinueOnError) // However, in V1/V2, we did not do this. Thus we will always continue on error on these scenarios } }
/// <summary> /// Handle the response payload. /// </summary> /// <param name="responseMsg">httpwebresponse instance.</param> /// <param name="responseStream">stream containing the response payload.</param> private void HandleOperationResponseData(IODataResponseMessage responseMsg, Stream responseStream) { Debug.Assert(this.entryIndex >= 0 && this.entryIndex < this.ChangedEntries.Count, string.Format(System.Globalization.CultureInfo.InvariantCulture, "this.entryIndex = '{0}', this.ChangedEntries.Count() = '{1}'", this.entryIndex, this.ChangedEntries.Count)); // Parse the response Descriptor current = this.ChangedEntries[this.entryIndex]; MaterializerEntry entry = default(MaterializerEntry); Version responseVersion; Exception exception = BaseSaveResult.HandleResponse(this.RequestInfo, (HttpStatusCode)responseMsg.StatusCode, responseMsg.GetHeader(XmlConstants.HttpODataVersion), () => { return(responseStream); }, false /*throwOnFailure*/, out responseVersion); var headers = new HeaderCollection(responseMsg); if (responseStream != null && current.DescriptorKind == DescriptorKind.Entity && exception == null) { // Only process the response if the current resource is an entity and it's an insert or update scenario EntityDescriptor entityDescriptor = (EntityDescriptor)current; // We were ignoring the payload for non-insert and non-update scenarios. We need to keep doing that. if (entityDescriptor.State == EntityStates.Added || entityDescriptor.StreamState == EntityStates.Added || entityDescriptor.State == EntityStates.Modified || entityDescriptor.StreamState == EntityStates.Modified) { try { ResponseInfo responseInfo = this.CreateResponseInfo(entityDescriptor); var responseMessageWrapper = new HttpWebResponseMessage( headers, responseMsg.StatusCode, () => responseStream); entry = ODataReaderEntityMaterializer.ParseSingleEntityPayload(responseMessageWrapper, responseInfo, entityDescriptor.Entity.GetType()); entityDescriptor.TransientEntityDescriptor = entry.EntityDescriptor; } catch (Exception ex) { exception = ex; if (!CommonUtil.IsCatchableExceptionType(ex)) { throw; } } } } this.cachedResponses.Add(new CachedResponse( current, headers, (HttpStatusCode)responseMsg.StatusCode, responseVersion, entry, exception)); if (exception != null) { current.SaveError = exception; // DEVNOTE(pqian): // There are two possible scenario here: // 1. We are in the sync code path, and there's an in stream error on the server side, or there are bad xml thrown // 2. We are in the async code path, there's a error thrown on the server side (any error) // Ideally, we need to check whether we want to continue to the next changeset. (Call this.CheckContinueOnError) // However, in V1/V2, we did not do this. Thus we will always continue on error on these scenarios } }
protected static ODataMessageReader CreateODataMessageReader(IODataResponseMessage responseMessage, ResponseInfo responseInfo, ref ODataPayloadKind payloadKind) { ODataMessageReaderSettings settings = responseInfo.ReadHelper.CreateSettings(); ODataMessageReader odataMessageReader = responseInfo.ReadHelper.CreateReader(responseMessage, settings); if (payloadKind == ODataPayloadKind.Unsupported) { var payloadKinds = odataMessageReader.DetectPayloadKind().ToList(); if (payloadKinds.Count == 0) { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidResponsePayload(XmlConstants.DataWebNamespace)); } // Pick the first payload kind detected by ODataLib and use that to parse the exception. // The only exception being payload with entity reference link(s). If one of the payload kinds // is reference links, then we need to give preference to reference link payloads. ODataPayloadKindDetectionResult detectionResult = payloadKinds.FirstOrDefault(k => k.PayloadKind == ODataPayloadKind.EntityReferenceLink || k.PayloadKind == ODataPayloadKind.EntityReferenceLinks); if (detectionResult == null) { detectionResult = payloadKinds.First(); } // Astoria client only supports atom, jsonlight and raw value payloads. #pragma warning disable 618 if (detectionResult.Format != ODataFormat.Atom && detectionResult.Format != ODataFormat.Json && detectionResult.Format != ODataFormat.RawValue) #pragma warning restore 618 { throw DSClient.Error.InvalidOperation(DSClient.Strings.AtomMaterializer_InvalidContentTypeEncountered(responseMessage.GetHeader(XmlConstants.HttpContentType))); } payloadKind = detectionResult.PayloadKind; } return odataMessageReader; }
protected static ODataMessageReader CreateODataMessageReader(IODataResponseMessage responseMessage, System.Data.Services.Client.ResponseInfo responseInfo, bool projectionQuery, ref ODataPayloadKind payloadKind) { Func<ODataEntry, XmlReader, Uri, XmlReader> entryXmlCustomizer = null; if (responseInfo.HasReadingEntityHandlers) { entryXmlCustomizer = new Func<ODataEntry, XmlReader, Uri, XmlReader>(ODataMaterializer.EntryXmlCustomizer); } ODataMessageReaderSettings settings = WebUtil.CreateODataMessageReaderSettings(responseInfo, entryXmlCustomizer, projectionQuery); ODataMessageReader reader = new ODataMessageReader(responseMessage, settings, ClientEdmModel.GetModel(responseInfo.MaxProtocolVersion)); if (payloadKind == ODataPayloadKind.Unsupported) { List<ODataPayloadKindDetectionResult> source = reader.DetectPayloadKind().ToList<ODataPayloadKindDetectionResult>(); if (source.Count == 0) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidResponsePayload(responseInfo.DataNamespace)); } ODataPayloadKindDetectionResult result = source.FirstOrDefault<ODataPayloadKindDetectionResult>(delegate (ODataPayloadKindDetectionResult k) { if (k.PayloadKind != ODataPayloadKind.EntityReferenceLink) { return k.PayloadKind == ODataPayloadKind.EntityReferenceLinks; } return true; }); if (result == null) { result = source.First<ODataPayloadKindDetectionResult>(); } if ((result.Format != ODataFormat.Atom) && (result.Format != ODataFormat.RawValue)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidContentTypeEncountered(responseMessage.GetHeader("Content-Type"))); } payloadKind = result.PayloadKind; } return reader; }
protected static ODataMessageReader CreateODataMessageReader(IODataResponseMessage responseMessage, System.Data.Services.Client.ResponseInfo responseInfo, bool projectionQuery, ref ODataPayloadKind payloadKind) { Func <ODataEntry, XmlReader, Uri, XmlReader> entryXmlCustomizer = null; if (responseInfo.HasReadingEntityHandlers) { entryXmlCustomizer = new Func <ODataEntry, XmlReader, Uri, XmlReader>(ODataMaterializer.EntryXmlCustomizer); } ODataMessageReaderSettings settings = WebUtil.CreateODataMessageReaderSettings(responseInfo, entryXmlCustomizer, projectionQuery); ODataMessageReader reader = new ODataMessageReader(responseMessage, settings, ClientEdmModel.GetModel(responseInfo.MaxProtocolVersion)); if (payloadKind == ODataPayloadKind.Unsupported) { List <ODataPayloadKindDetectionResult> source = reader.DetectPayloadKind().ToList <ODataPayloadKindDetectionResult>(); if (source.Count == 0) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidResponsePayload(responseInfo.DataNamespace)); } ODataPayloadKindDetectionResult result = source.FirstOrDefault <ODataPayloadKindDetectionResult>(delegate(ODataPayloadKindDetectionResult k) { if (k.PayloadKind != ODataPayloadKind.EntityReferenceLink) { return(k.PayloadKind == ODataPayloadKind.EntityReferenceLinks); } return(true); }); if (result == null) { result = source.First <ODataPayloadKindDetectionResult>(); } if ((result.Format != ODataFormat.Atom) && (result.Format != ODataFormat.RawValue)) { throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.AtomMaterializer_InvalidContentTypeEncountered(responseMessage.GetHeader("Content-Type"))); } payloadKind = result.PayloadKind; } return(reader); }
private static void VerifyHeader(IODataResponseMessage message, string headerName, string expectedValue) { message.GetHeader(headerName).Should().Be(expectedValue); }
/// <summary>operation with exception</summary> /// <param name="e">exception object</param> /// <param name="response">response object</param> private void HandleOperationException(InvalidOperationException e, IODataResponseMessage response) { Debug.Assert(this.entryIndex >= 0 && this.entryIndex < this.ChangedEntries.Count(), string.Format(System.Globalization.CultureInfo.InvariantCulture, "this.entryIndex = '{0}', this.ChangedEntries.Count = '{1}'", this.entryIndex, this.ChangedEntries.Count())); Descriptor current = this.ChangedEntries[this.entryIndex]; HeaderCollection headers = null; HttpStatusCode statusCode = HttpStatusCode.InternalServerError; Version responseVersion = null; if (null != response) { headers = new HeaderCollection(response); statusCode = (HttpStatusCode)response.StatusCode; this.HandleOperationResponseHeaders(statusCode, headers); e = BaseSaveResult.HandleResponse( this.RequestInfo, statusCode, response.GetHeader(XmlConstants.HttpODataVersion), response.GetStream, false/*throwOnFailure*/, out responseVersion); } else { headers = new HeaderCollection(); headers.SetHeader(XmlConstants.HttpContentType, XmlConstants.MimeTextPlain); // In V2 we used to merge individual responses from a call to SaveChanges() into a single batch response payload and then process that. // When we encounter an exception at this point in V2, we used to write the exception to the batch response payload and later on when we // process through the batch response, we create a DataServiceClientException for each failed operation. // For backcompat reason, we will always convert the exception type to DataServiceClientException here. Debug.Assert(e != null, "e != null"); if (e.GetType() != typeof(DataServiceClientException)) { e = new DataServiceClientException(e.Message, e); } } // For error scenarios, we never invoke the ReadingEntity event. this.cachedResponses.Add(new CachedResponse(current, headers, statusCode, responseVersion, null, e)); this.perRequest = null; this.CheckContinueOnError(); }