/// <summary> /// copy the response data /// </summary> /// <param name="response">response object</param> private void HandleOperationResponseData(IODataResponseMessage response) { Debug.Assert(response != null, "response != null"); using (Stream stream = response.GetStream()) { if (stream != null) { // we need to check for whether the incoming stream was data or not. Hence we need to copy it to a temporary memory stream using (MemoryStream memoryStream = new MemoryStream()) { if (WebUtil.CopyStream(stream, memoryStream, ref this.buildBatchBuffer) != 0) { // set the memory stream position to zero again. memoryStream.Position = 0; this.HandleOperationResponseData(response, memoryStream); } else { this.HandleOperationResponseData(response, null); } } } } }
public Task SerializeToStreamAsync(Stream stream) { // how to dispose it? IODataResponseMessage responseMessage = ODataMessageWrapperHelper.Create(stream, Headers, _requestContainer); return(WriteToResponseMessageAsync(responseMessage)); }
public async Task WriteMessageAsync_AsynchronouslyWritesResponseMessage() { // Arrange HeaderDictionary headers = new HeaderDictionary { { "Content-Type", $"multipart/mixed;charset=utf-8;boundary={Guid.NewGuid()}" }, }; MemoryStream ms = new MemoryStream(); IODataResponseMessage odataResponse = ODataMessageWrapperHelper.Create(ms, headers); HeaderDictionary responseHeaders = new HeaderDictionary { { "customHeader", "bar" } }; HttpResponse response = CreateResponse("example content", responseHeaders, "text/example"); // Act ODataBatchWriter batchWriter = await new ODataMessageWriter(odataResponse).CreateODataBatchWriterAsync(); await batchWriter.WriteStartBatchAsync(); await ODataBatchResponseItem.WriteMessageAsync(batchWriter, response.HttpContext); await batchWriter.WriteEndBatchAsync(); ms.Position = 0; string result = new StreamReader(ms).ReadToEnd(); // Assert Assert.Contains("example content", result); Assert.Contains("text/example", result); Assert.Contains("customHeader", result); Assert.Contains("bar", result); }
public async Task WriteMessageAsync_WritesResponseMessage() { MemoryStream ms = new MemoryStream(); HttpContent content = new StringContent(String.Empty, Encoding.UTF8, "multipart/mixed"); content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("boundary", Guid.NewGuid().ToString())); IODataResponseMessage odataResponse = ODataMessageWrapperHelper.Create(ms, content.Headers); var batchWriter = new ODataMessageWriter(odataResponse).CreateODataBatchWriter(); HttpResponseMessage response = new HttpResponseMessage() { Content = new StringContent("example content", Encoding.UTF8, "text/example") }; response.Headers.Add("customHeader", "bar"); batchWriter.WriteStartBatch(); await ODataBatchResponseItem.WriteMessageAsync(batchWriter, response, CancellationToken.None); batchWriter.WriteEndBatch(); ms.Position = 0; string result = new StreamReader(ms).ReadToEnd(); Assert.Contains("example content", result); Assert.Contains("text/example", result); Assert.Contains("customHeader", result); Assert.Contains("bar", result); }
public void WriteMessageAsync_SynchronousResponseContainsContentId_IfHasContentIdInRequestChangeSet() { // Arrange HeaderDictionary headers = new HeaderDictionary { { "Content-Type", $"multipart/mixed;charset=utf-8;boundary={Guid.NewGuid()}" }, }; MemoryStream ms = new MemoryStream(); IODataResponseMessage odataResponse = ODataMessageWrapperHelper.Create(ms, headers); string contentId = Guid.NewGuid().ToString(); HttpResponse httpResponse = CreateResponse("any", new HeaderDictionary(), "text/example;charset=utf-8"); httpResponse.HttpContext.Request.SetODataContentId(contentId); // Act ODataBatchWriter batchWriter = new ODataMessageWriter(odataResponse).CreateODataBatchWriter(); batchWriter.WriteStartBatch(); batchWriter.WriteStartChangeset(); // Assert Action test = () => ODataBatchResponseItem.WriteMessageAsync(batchWriter, httpResponse.HttpContext).Wait(); ODataException exception = ExceptionAssert.Throws <ODataException>(test); Assert.Equal("An asynchronous operation was called on a synchronous batch writer. Calls on a batch writer instance must be either all synchronous or all asynchronous.", exception.Message); }
public void WriteMessage_SynchronouslyWritesResponseMessage_Throws() { HeaderDictionary headers = new HeaderDictionary { { "Content-Type", $"multipart/mixed;charset=utf-8;boundary={Guid.NewGuid()}" }, }; MemoryStream ms = new MemoryStream(); IODataResponseMessage odataResponse = ODataMessageWrapperHelper.Create(ms, headers); HeaderDictionary responseHeaders = new HeaderDictionary { { "customHeader", "bar" } }; HttpResponse response = CreateResponse("example content", responseHeaders, "text/example"); // Act ODataBatchWriter batchWriter = new ODataMessageWriter(odataResponse).CreateODataBatchWriter(); batchWriter.WriteStartBatch(); // Assert Action test = () => ODataBatchResponseItem.WriteMessageAsync(batchWriter, response.HttpContext).Wait(); ODataException exception = ExceptionAssert.Throws <ODataException>(test); Assert.Equal("An asynchronous operation was called on a synchronous batch writer. Calls on a batch writer instance must be either all synchronous or all asynchronous.", exception.Message); }
internal static IODataResponseMessage PrepareResponseMessage(IWebApiRequestMessage internalRequest, IWebApiHeaders internalRequestHeaders, Func <IServiceProvider, ODataMessageWrapper> getODataMessageWrapper) { string preferHeader = RequestPreferenceHelpers.GetRequestPreferHeader(internalRequestHeaders); string annotationFilter = null; string omitValues = null; int? maxPageSize = null; if (!String.IsNullOrEmpty(preferHeader)) { ODataMessageWrapper messageWrapper = getODataMessageWrapper(null); messageWrapper.SetHeader(RequestPreferenceHelpers.PreferHeaderName, preferHeader); annotationFilter = messageWrapper.PreferHeader().AnnotationFilter; omitValues = messageWrapper.PreferHeader().OmitValues; maxPageSize = messageWrapper.PreferHeader().MaxPageSize; } IODataResponseMessage responseMessage = getODataMessageWrapper(internalRequest.RequestContainer); if (annotationFilter != null) { responseMessage.PreferenceAppliedHeader().AnnotationFilter = annotationFilter; } if (omitValues != null) { responseMessage.PreferenceAppliedHeader().OmitValues = omitValues; } if (maxPageSize != null) { responseMessage.PreferenceAppliedHeader().MaxPageSize = maxPageSize; } return(responseMessage); }
public async Task WriteMessageAsync_ResponseContainsContentId_IfHasContentIdInRequestChangeSet() { MemoryStream ms = new MemoryStream(); HttpContent content = new StringContent(String.Empty, Encoding.UTF8, "multipart/mixed"); content.Headers.ContentType.Parameters.Add(new NameValueHeaderValue("boundary", Guid.NewGuid().ToString())); IODataResponseMessage odataResponse = ODataMessageWrapperHelper.Create(ms, content.Headers); var batchWriter = new ODataMessageWriter(odataResponse).CreateODataBatchWriter(); HttpResponseMessage response = new HttpResponseMessage { Content = new StringContent("any", Encoding.UTF8, "text/example") }; var request = new HttpRequestMessage(); var contentId = Guid.NewGuid().ToString(); request.SetODataContentId(contentId); response.RequestMessage = request; batchWriter.WriteStartBatch(); batchWriter.WriteStartChangeset(); await ODataBatchResponseItem.WriteMessageAsync(batchWriter, response, CancellationToken.None); batchWriter.WriteEndChangeset(); batchWriter.WriteEndBatch(); ms.Position = 0; string result = new StreamReader(ms).ReadToEnd(); Assert.Contains("any", result); Assert.Contains("text/example", result); Assert.Contains("Content-ID", result); Assert.Contains(contentId, result); }
private void ProcessUpsertEntity(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage, ODataPath odataPath) { if (this.QueryContext.Target.TypeKind == EdmTypeKind.Entity && !this.QueryContext.Target.IsReference) { Uri parentUri = this.QueryContext.Target.BuildContainerUri(this.ServiceRootUri); QueryContext parentContext = new QueryContext(this.ServiceRootUri, parentUri, this.DataSource.Model); if (parentContext.Target.IsEntitySet) { // Update a entity under a entity set => Upsert // TODO: Do we need to preserver the key value? new CreateHandler(this, parentContext.QueryUri).Process(requestMessage, responseMessage); } else { // Update Singleton or single value entity from null value. var parent = parentContext.ResolveQuery(this.DataSource); // TODO: It might not correct here, since the last segment could be type segment. NavigationPropertySegment navSegment = (NavigationPropertySegment)odataPath.LastSegment; var targetObject = Utility.CreateResource(this.QueryContext.Target.Type); parent.GetType().GetProperty(navSegment.NavigationProperty.Name).SetValue(parent, targetObject, null); ProcessUpdateRequestBody(requestMessage, responseMessage, targetObject, true); } } else { throw Utility.BuildException(HttpStatusCode.NotFound); } }
/// <summary> /// Constructs an internal wrapper around the <paramref name="responseMessage"/> /// that isolates the internal implementation of the ODataLib from the interface. /// </summary> /// <param name="responseMessage">The response message to wrap.</param> internal ODataResponseMessage(IODataResponseMessage responseMessage) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(responseMessage != null, "responseMessage != null"); this.responseMessage = responseMessage; }
public void ResponseMessageHeaderTest() { const bool useMimeWriterAsListener = true; Func <bool, bool, IODataResponseMessage>[] responseMessageFuncs = new Func <bool, bool, IODataResponseMessage>[] { (writing, mimeWriterAsListener) => CreateBatchOperationResponseMessage(writing, mimeWriterAsListener), (writing, notUsed) => new ODataResponseMessageWrapper(new TestResponseMessage(new TestStream()), writing, false) }; // ODataMultipartMixedBatchWriter as listener this.CombinatorialEngineProvider.RunCombinations( new bool[] { true, false }, responseMessageFuncs, (writing, func) => { IODataResponseMessage responseMessage = func(writing, useMimeWriterAsListener); RunHeaderTest(() => responseMessage.Headers, writing, responseMessage.GetHeader, responseMessage.SetHeader, this.Assert, this.ExceptionVerifier); }); // ODataJsonLightBatchWriter as listener this.CombinatorialEngineProvider.RunCombinations( new bool[] { true, false }, responseMessageFuncs, (writing, func) => { IODataResponseMessage responseMessage = func(writing, !useMimeWriterAsListener); RunHeaderTest(() => responseMessage.Headers, writing, responseMessage.GetHeader, responseMessage.SetHeader, this.Assert, this.ExceptionVerifier); }); }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { string asyncToken = this.QueryContext.AsyncToken; AsyncTask asyncTask = AsyncTask.GetTask(asyncToken); if (asyncTask == null) { // token is invalid or expired. throw Utility.BuildException(HttpStatusCode.NotFound); } else { if (!asyncTask.Ready) { ResponseWriter.WriteAsyncPendingResponse(responseMessage, asyncToken); } else { responseMessage.SetHeader(ServiceConstants.HttpHeaders.ContentType, "application/http"); responseMessage.SetHeader(ServiceConstants.HttpHeaders.ContentTransferEncoding, ServiceConstants.HttpHeaderValues.Binary); using (var messageWriter = this.CreateMessageWriter(responseMessage)) { var asyncWriter = messageWriter.CreateODataAsynchronousWriter(); var innerResponse = asyncWriter.CreateResponseMessage(); asyncTask.Execute(innerResponse); } } } }
/// <summary> /// Internal constructor to instantiate an <see cref="ODataPreferenceHeader"/> from an <see cref="IODataResponseMessage"/>. /// </summary> /// <param name="responseMessage">The response message to get and set the "Preference-Applied" header.</param> internal ODataPreferenceHeader(IODataResponseMessage responseMessage) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(responseMessage != null, "responseMessage != null"); this.message = new ODataResponseMessage(responseMessage, /*writing*/ true, /*disableMessageStreamDisposal*/ false, /*maxMessageSize*/ -1); this.preferenceHeaderName = PreferenceAppliedHeaderName; }
/// <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> /// Constructs a new instance of DataServiceTransportException. /// </summary> /// <param name="response">ResponseMessage from the exception so that the error payload can be read.</param> /// <param name="innerException">Actual exception that this exception is wrapping.</param> public DataServiceTransportException(IODataResponseMessage response, Exception innerException) : base(innerException.Message, innerException) { Util.CheckArgumentNull(innerException, "innerException"); this.ResponseMessage = response; }
internal static MaterializerEntry ParseSingleEntityPayload(IODataResponseMessage message, ResponseInfo responseInfo, Type expectedType) { ODataPayloadKind payloadKind = ODataPayloadKind.Entry; using (ODataMessageReader reader = ODataMaterializer.CreateODataMessageReader(message, responseInfo, false, ref payloadKind)) { IEdmType orCreateEdmType = ClientEdmModel.GetModel(responseInfo.MaxProtocolVersion).GetOrCreateEdmType(expectedType); ODataReader reader2 = ODataMaterializer.CreateODataReader(reader, payloadKind, orCreateEdmType, responseInfo.MaxProtocolVersion); ODataFeedOrEntryReader reader3 = new ODataFeedOrEntryReader(reader2, responseInfo); ODataEntry currentEntry = null; bool flag = false; while (reader3.Read()) { flag |= reader3.CurrentFeed != null; if (reader3.CurrentEntry != null) { if (currentEntry != null) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomParser_SingleEntry_MultipleFound); } currentEntry = reader3.CurrentEntry; } } if (currentEntry == null) { if (flag) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomParser_SingleEntry_NoneFound); } throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomParser_SingleEntry_ExpectedFeedOrEntry); } return MaterializerEntry.GetEntry(currentEntry); } }
internal override IEnumerable<ODataPayloadKind> DetectPayloadKind(IODataResponseMessage responseMessage, ODataPayloadKindDetectionInfo detectionInfo) { ExceptionUtils.CheckArgumentNotNull<IODataResponseMessage>(responseMessage, "responseMessage"); ExceptionUtils.CheckArgumentNotNull<ODataPayloadKindDetectionInfo>(detectionInfo, "detectionInfo"); Stream messageStream = ((ODataMessage) responseMessage).GetStream(); return this.DetectPayloadKindImplementation(messageStream, true, true, detectionInfo); }
protected virtual ODataMessageWriter CreateMessageWriter(IODataResponseMessage message) { return(new ODataMessageWriter( message, this.GetWriterSettings(), this.DataSource.Model)); }
internal void HandleResponse(object response) { ExceptionUtilities.CheckArgumentNotNull(response, "response"); ExceptionUtilities.Assert(this.CurrentResponse == null, "Current response was not null"); this.CurrentResponse = new HttpResponseData(); HttpStatusCode statusCode; string statusCodeString = null; IODataResponseMessage odataResponse = response as IODataResponseMessage; if (odataResponse != null) { statusCodeString = odataResponse.StatusCode.ToString(); } else { HttpWebResponse httpWebRespnse = (HttpWebResponse)response; statusCodeString = httpWebRespnse.StatusCode.ToString(); } ExceptionUtilities.Assert(Enum.TryParse <HttpStatusCode>(statusCodeString, false, out statusCode), "Unrecognized status code '{0}'", statusCodeString); this.CurrentResponse.StatusCode = statusCode; PopulateHeaders(response, this.CurrentResponse.Headers); }
private void ProcessUpdateEntityReference(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage, ODataPath odataPath) { // This is for change the reference in single-valued navigation property // PUT ~/Person(0)/Parent/$ref // { // "@odata.context": "http://host/service/$metadata#$ref", // "@odata.id": "Orders(10643)" // } if (this.HttpMethod == HttpMethod.PATCH) { throw Utility.BuildException(HttpStatusCode.MethodNotAllowed, "PATCH on a reference link is not supported.", null); } // Get the parent first var level = this.QueryContext.QueryPath.Count - 2; var parent = this.QueryContext.ResolveQuery(this.DataSource, level); var navigationPropertyName = ((NavigationPropertyLinkSegment)odataPath.LastSegment).NavigationProperty.Name; using (var messageReader = new ODataMessageReader(requestMessage, this.GetReaderSettings(), this.DataSource.Model)) { var referenceLink = messageReader.ReadEntityReferenceLink(); var queryContext = new QueryContext(this.ServiceRootUri, referenceLink.Url, this.DataSource.Model); var target = queryContext.ResolveQuery(this.DataSource); this.DataSource.UpdateProvider.UpdateLink(parent, navigationPropertyName, target); this.DataSource.UpdateProvider.SaveChanges(); } ResponseWriter.WriteEmptyResponse(responseMessage); }
private void ProcessDeleteLink(IODataResponseMessage responseMessage) { var segment = (NavigationPropertyLinkSegment)this.QueryContext.QueryPath.LastSegment; var propertyName = segment.NavigationProperty.Name; var parent = default(object); var target = default(object); if (this.QueryContext.QueryEntityIdSegment == null) { // single-valued navigation property parent = this.QueryContext.ResolveQuery(this.DataSource, this.QueryContext.QueryPath.Count - 2); } else { // collection-valued navigation property var queryUri = this.QueryContext.QueryUri; var parentUri = queryUri.AbsoluteUri.Substring(0, queryUri.AbsoluteUri.Length - queryUri.Query.Length); var parentContext = new QueryContext(this.ServiceRootUri, new Uri(parentUri, UriKind.Absolute), this.DataSource.Model); parent = parentContext.ResolveQuery(this.DataSource, parentContext.QueryPath.Count - 2); target = this.QueryContext.ResolveQuery(this.DataSource); } this.DataSource.UpdateProvider.DeleteLink(parent, propertyName, target); this.DataSource.UpdateProvider.SaveChanges(); ResponseWriter.WriteEmptyResponse(responseMessage); }
internal static MaterializerEntry ParseSingleEntityPayload(IODataResponseMessage message, ResponseInfo responseInfo, Type expectedType) { ODataPayloadKind payloadKind = ODataPayloadKind.Entry; using (ODataMessageReader reader = ODataMaterializer.CreateODataMessageReader(message, responseInfo, false, ref payloadKind)) { IEdmType orCreateEdmType = ClientEdmModel.GetModel(responseInfo.MaxProtocolVersion).GetOrCreateEdmType(expectedType); ODataReader reader2 = ODataMaterializer.CreateODataReader(reader, payloadKind, orCreateEdmType, responseInfo.MaxProtocolVersion); ODataFeedOrEntryReader reader3 = new ODataFeedOrEntryReader(reader2, responseInfo); ODataEntry currentEntry = null; bool flag = false; while (reader3.Read()) { flag |= reader3.CurrentFeed != null; if (reader3.CurrentEntry != null) { if (currentEntry != null) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomParser_SingleEntry_MultipleFound); } currentEntry = reader3.CurrentEntry; } } if (currentEntry == null) { if (flag) { throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomParser_SingleEntry_NoneFound); } throw new InvalidOperationException(System.Data.Services.Client.Strings.AtomParser_SingleEntry_ExpectedFeedOrEntry); } return(MaterializerEntry.GetEntry(currentEntry)); } }
internal DataServiceStreamResponse Execute() { try { this.responseMessage = this.requestInfo.GetSyncronousResponse(this.requestMessage, true); Debug.Assert(this.responseMessage != null, "Can't set a null response."); } catch (Exception e) { this.HandleFailure(e); throw; } finally { this.SetCompleted(); this.CompletedRequest(); } if (null != this.Failure) { throw this.Failure; } return(this.End()); }
/// <summary> /// Constructs an internal wrapper around the <paramref name="responseMessage"/> /// that isolates the internal implementation of the ODataLib from the interface. /// </summary> /// <param name="responseMessage">The response message to wrap.</param> /// <param name="writing">true if the message is being written; false when it is read.</param> /// <param name="enableMessageStreamDisposal">true if the stream returned should be disposed calls.</param> /// <param name="maxMessageSize">The maximum size of the message in bytes (or a negative number if no maximum applies).</param> internal ODataResponseMessage(IODataResponseMessage responseMessage, bool writing, bool enableMessageStreamDisposal, long maxMessageSize) : base(writing, enableMessageStreamDisposal, maxMessageSize) { Debug.Assert(responseMessage != null, "responseMessage != null"); this.responseMessage = responseMessage; }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { responseMessage.SetStatusCode(HttpStatusCode.OK); using (var writer = this.CreateMessageWriter(responseMessage)) { writer.WriteServiceDocument(this.GenerateServiceDocument()); } }
private void ProcessDelete(object target, IODataResponseMessage responseMessage) { this.DataSource.UpdateProvider.Delete(target); // Protocol 11.4.5 Delete an Entity // On successful completion of the delete, the response MUST be 204 No Content and contain an empty body. ResponseWriter.WriteEmptyResponse(responseMessage); }
public static void InitClass(TestContext testContext) { RequestWithApplicationJson = new ODataRequestMessageSimulator(); RequestWithApplicationJson.SetHeader(XmlConstants.HttpContentType, "aPPlicaTion/jSoN"); ResponseWithApplicationJson = new ODataResponseMessageSimulator(); ResponseWithApplicationJson.SetHeader(XmlConstants.HttpContentType, "aPPlicaTion/jSoN"); }
/// <summary> /// Initializes a new instance of <see cref="HeaderCollection"/>. /// </summary> /// <param name="responseMessage">The response message to pull the headers from.</param> internal HeaderCollection(IODataResponseMessage responseMessage) : this() { if (responseMessage != null) { this.SetHeaders(responseMessage.Headers); } }
internal override IEnumerable <ODataPayloadKind> DetectPayloadKind(IODataResponseMessage responseMessage, ODataPayloadKindDetectionInfo detectionInfo) { ExceptionUtils.CheckArgumentNotNull <IODataResponseMessage>(responseMessage, "responseMessage"); ExceptionUtils.CheckArgumentNotNull <ODataPayloadKindDetectionInfo>(detectionInfo, "detectionInfo"); Stream messageStream = ((ODataMessage)responseMessage).GetStream(); return(this.DetectPayloadKindImplementation(messageStream, true, true, detectionInfo)); }
private ODataAsynchronousWriter TestInit() { responseMessage = new InMemoryMessage { Stream = responseStream }; messageWriter = new ODataMessageWriter(responseMessage); return(messageWriter.CreateODataAsynchronousWriter()); }
/// <summary> /// Constructs an internal wrapper around the <paramref name="responseMessage"/> /// that isolates the internal implementation of the ODataLib from the interface. /// </summary> /// <param name="responseMessage">The response message to wrap.</param> /// <param name="writing">true if the message is being written; false when it is read.</param> /// <param name="disableMessageStreamDisposal">true if the stream returned should ignore dispose calls.</param> /// <param name="maxMessageSize">The maximum size of the message in bytes (or a negative number if no maximum applies).</param> internal ODataResponseMessage(IODataResponseMessage responseMessage, bool writing, bool disableMessageStreamDisposal, long maxMessageSize) : base(writing, disableMessageStreamDisposal, maxMessageSize) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(responseMessage != null, "responseMessage != null"); this.responseMessage = responseMessage; }
/// <summary> /// Create a new feed generator /// </summary> /// <param name="requestMessage">The OData request message that was received</param> /// <param name="responseMessage">The OData response message to be populated by the generator</param> /// <param name="entityMap">The map to use to map RDF URIs to OData types and properties</param> /// <param name="baseUri">The base URI for the OData feed</param> /// <param name="messageWriterSettings">Additional settings to apply to the generated OData output</param> public ODataFeedGenerator(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage, SparqlMap entityMap, string baseUri, ODataMessageWriterSettings messageWriterSettings) { _request = requestMessage; _response = responseMessage; _map = entityMap; _baseUri = baseUri; _writerSettings = messageWriterSettings; }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { responseMessage.SetStatusCode(HttpStatusCode.OK); using (var writer = this.CreateMessageWriter(responseMessage)) { writer.WriteMetadataDocument(); } }
/// <summary> /// Applies headers in the dictionary to a response message. /// </summary> /// <param name="headers">The dictionary with the headers to apply.</param> /// <param name="responseMessage">The request message to apply the headers to.</param> private static void ApplyHeadersToResponse(HeaderCollection headers, IODataResponseMessage responseMessage) { // NetCF bug with how the enumerators for dictionaries work. foreach (KeyValuePair <string, string> header in headers.AsEnumerable().ToList()) { responseMessage.SetHeader(header.Key, header.Value); } }
/// <summary> /// Creates a new the reader for the given response message and settings. /// </summary> /// <param name="responseMessage">The response message.</param> /// <param name="settings">The settings.</param> /// <returns>Newly created message reader.</returns> internal ODataMessageReader CreateReader(IODataResponseMessage responseMessage, ODataMessageReaderSettings settings) { Debug.Assert(responseMessage != null, "responseMessage != null"); Debug.Assert(settings != null, "settings != null"); this.responseInfo.Context.Format.ValidateCanReadResponseFormat(responseMessage); return new ODataMessageReader(responseMessage, settings, this.responseInfo.TypeResolver.ReaderModel); }
/// <summary> /// Creates a new the reader for the given response message and settings. /// </summary> /// <param name="responseMessage">The response message.</param> /// <param name="settings">The settings.</param> /// <returns>Newly created message reader.</returns> internal ODataMessageReader CreateReader(IODataResponseMessage responseMessage, ODataMessageReaderSettings settings) { Debug.Assert(responseMessage != null, "responseMessage != null"); Debug.Assert(settings != null, "settings != null"); this.responseInfo.Context.Format.ValidateCanReadResponseFormat(responseMessage); return(new ODataMessageReader(responseMessage, settings, this.responseInfo.TypeResolver.ReaderModel)); }
internal ResponseBodyWriter(bool hasMoved, IDataService service, IEnumerator queryResults, RequestDescription requestDescription, IODataResponseMessage responseMessage, ODataPayloadKind payloadKind) { this.hasMoved = hasMoved; this.service = service; this.queryResults = queryResults; this.requestDescription = requestDescription; this.responseMessage = responseMessage; this.payloadKind = payloadKind; this.encoding = HttpProcessUtility.EncodingFromAcceptCharset(this.service.OperationContext.Host.RequestAcceptCharSet); if ((((payloadKind == ODataPayloadKind.Entry) || (payloadKind == ODataPayloadKind.Feed)) || ((payloadKind == ODataPayloadKind.Property) || (payloadKind == ODataPayloadKind.Collection))) || (((payloadKind == ODataPayloadKind.EntityReferenceLink) || (payloadKind == ODataPayloadKind.EntityReferenceLinks)) || (((payloadKind == ODataPayloadKind.Error) || (payloadKind == ODataPayloadKind.ServiceDocument)) || (payloadKind == ODataPayloadKind.Parameter)))) { DataServiceHostWrapper host = service.OperationContext.Host; if (WebUtil.GetEffectiveMaxResponseVersion(service.Configuration.DataServiceBehavior.MaxProtocolVersion, host.RequestMaxVersion) > RequestDescription.Version2Dot0) { bool isEntityOrFeed = (payloadKind == ODataPayloadKind.Entry) || (payloadKind == ODataPayloadKind.Feed); if (WebUtil.ResponseMediaTypeWouldBeJsonLight(host.RequestAccept, isEntityOrFeed)) { requestDescription.VerifyAndRaiseResponseVersion(RequestDescription.Version3Dot0, service); host.ResponseVersion = RequestDescription.Version3Dot0.ToString() + ";"; } } } if (this.requestDescription.TargetKind == RequestTargetKind.MediaResource) { this.mediaResourceStream = service.StreamProvider.GetReadStream(this.queryResults.Current, RequestDescription.GetStreamProperty(this.requestDescription), this.service.OperationContext); } else if (payloadKind != ODataPayloadKind.BinaryValue) { string requestAcceptCharSet = this.service.OperationContext.Host.RequestAcceptCharSet; if (string.IsNullOrEmpty(requestAcceptCharSet) || (requestAcceptCharSet == "*")) { requestAcceptCharSet = "UTF-8"; } if ((payloadKind == ODataPayloadKind.Value) && !string.IsNullOrEmpty(this.requestDescription.MimeType)) { this.messageWriter = CreateMessageWriter(this.AbsoluteServiceUri, this.service, this.requestDescription.ActualResponseVersion, responseMessage, ODataFormat.RawValue); } else { this.messageWriter = CreateMessageWriter(this.AbsoluteServiceUri, this.service, this.requestDescription.ActualResponseVersion, responseMessage, this.service.OperationContext.Host.RequestAccept, requestAcceptCharSet); } try { this.contentFormat = ODataUtils.SetHeadersForPayload(this.messageWriter, payloadKind); if ((payloadKind == ODataPayloadKind.Value) && !string.IsNullOrEmpty(this.requestDescription.MimeType)) { responseMessage.SetHeader("Content-Type", this.requestDescription.MimeType); } } catch (ODataContentTypeException exception) { throw new DataServiceException(0x19f, null, System.Data.Services.Strings.DataServiceException_UnsupportedMediaType, null, exception); } string headerValue = this.requestDescription.ResponseVersion.ToString() + ";"; responseMessage.SetHeader("DataServiceVersion", headerValue); } }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { if (this.TryDispatch(requestMessage, responseMessage)) { return; } if (this.QueryContext.Target.TypeKind != EdmTypeKind.Collection) { throw Utility.BuildException(HttpStatusCode.BadRequest, "The new resource can only be created under collection resource.", null); } if (this.QueryContext.Target.IsReference) { this.ProcessCreateLink(requestMessage, responseMessage); return; } try { var targetEntitySet = (IEdmEntitySetBase)this.QueryContext.Target.NavigationSource; // TODO: [lianw] Try to remove "targetEntitySet" later. var queryResults = this.QueryContext.ResolveQuery(this.DataSource); if (!IsAllowInsert(targetEntitySet as IEdmEntitySet)) { throw new ODataServiceException(HttpStatusCode.BadRequest, "The insert request is not allowed.", null); } var bodyObject = ProcessPostBody(requestMessage, targetEntitySet, queryResults); using (var messageWriter = this.CreateMessageWriter(responseMessage)) { this.DataSource.UpdateProvider.SaveChanges(); // 11.4.2 Create an Entity // Upon successful completion the service MUST respond with either 201 Created, or 204 No Content if the request included a return Prefer header with a value of return=minimal. responseMessage.SetStatusCode(HttpStatusCode.Created); responseMessage.SetHeader(ServiceConstants.HttpHeaders.Location, Utility.BuildLocationUri(this.QueryContext, bodyObject).OriginalString); var currentETag = Utility.GetETagValue(bodyObject); // if the current entity has ETag field if (currentETag != null) { responseMessage.SetHeader(ServiceConstants.HttpHeaders.ETag, currentETag); } ResponseWriter.WriteEntry(messageWriter.CreateODataEntryWriter(targetEntitySet), bodyObject, targetEntitySet, ODataVersion.V4, null); } } catch { this.DataSource.UpdateProvider.ClearChanges(); throw; } }
/// <summary> /// Prevents a default instance of the <see cref="MessageWriterBuilder"/> class from being created. /// </summary> /// <param name="serviceUri">The service URI.</param> /// <param name="responseVersion">The response version.</param> /// <param name="dataService">The data service.</param> /// <param name="responseMessage">The response message.</param> /// <param name="model">The model to provide to the message writer.</param> private MessageWriterBuilder(Uri serviceUri, Version responseVersion, IDataService dataService, IODataResponseMessage responseMessage, IEdmModel model) { this.writerSettings = CreateMessageWriterSettings(); ApplyCommonSettings(this.writerSettings, serviceUri, responseVersion, dataService, responseMessage); Debug.Assert(responseMessage != null, "responseMessage != null"); this.responseMessage = responseMessage; this.model = model; }
internal MaterializeAtom(ResponseInfo responseInfo, QueryComponents queryComponents, ProjectionPlan plan, IODataResponseMessage responseMessage, ODataPayloadKind payloadKind) { Type type; this.responseInfo = responseInfo; this.elementType = queryComponents.LastSegmentType; this.MergeOptionValue = responseInfo.MergeOption; this.expectingPrimitiveValue = PrimitiveType.IsKnownNullableType(this.elementType); Type materializerType = GetTypeForMaterializer(this.expectingPrimitiveValue, this.elementType, responseInfo.MaxProtocolVersion, out type); this.materializer = ODataMaterializer.CreateMaterializerForMessage(responseMessage, responseInfo, materializerType, queryComponents, plan, payloadKind); }
/// <summary> /// Detects the payload kinds supported by this format for the specified message payload. /// </summary> /// <param name="responseMessage">The response message with the payload stream.</param> /// <param name="detectionInfo">Additional information available for the payload kind detection.</param> /// <returns>The set of <see cref="ODataPayloadKind"/>s that are supported with the specified payload.</returns> internal override IEnumerable<ODataPayloadKind> DetectPayloadKind( IODataResponseMessage responseMessage, ODataPayloadKindDetectionInfo detectionInfo) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(responseMessage, "responseMessage"); ExceptionUtils.CheckArgumentNotNull(detectionInfo, "detectionInfo"); return DetectPayloadKindImplementation(detectionInfo.ContentType); }
/// <summary> /// Constructs a new instance of DataServiceTransportException. /// </summary> /// <param name="response">ResponseMessage from the exception so that the error payload can be read.</param> /// <param name="innerException">Actual exception that this exception is wrapping.</param> public DataServiceTransportException(IODataResponseMessage response, Exception innerException) : base(innerException.Message, innerException) { Util.CheckArgumentNull(innerException, "innerException"); this.state.ResponseMessage = response; #if !PORTABLELIB this.SerializeObjectState += (sender, e) => e.AddSerializedState(this.state); #endif }
/// <summary> /// Detects the payload kinds supported by this format for the specified message payload. /// </summary> /// <param name="responseMessage">The response message with the payload stream.</param> /// <param name="detectionInfo">Additional information available for the payload kind detection.</param> /// <returns>The set of <see cref="ODataPayloadKind"/>s that are supported with the specified payload.</returns> internal override IEnumerable<ODataPayloadKind> DetectPayloadKind( IODataResponseMessage responseMessage, ODataPayloadKindDetectionInfo detectionInfo) { DebugUtils.CheckNoExternalCallers(); ExceptionUtils.CheckArgumentNotNull(responseMessage, "responseMessage"); ExceptionUtils.CheckArgumentNotNull(detectionInfo, "detectionInfo"); Stream messageStream = ((ODataMessage)responseMessage).GetStream(); return this.DetectPayloadKindImplementation(messageStream, /*readingResponse*/ true, /*synchronous*/ true, detectionInfo); }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { switch (this.HttpMethod) { case HttpMethod.POST: this.ProcessCreate(requestMessage.GetStream(), responseMessage); break; case HttpMethod.PUT: this.ProcessUpdate(requestMessage.GetStream(), responseMessage); break; } }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { using (var messageWriter = this.CreateMessageWriter(responseMessage)) { ODataError error; HttpStatusCode statusCode; this.BuildODataError(out error, out statusCode); responseMessage.SetStatusCode(statusCode); messageWriter.WriteError(error, true); } }
/// <summary> /// Create a new instance of ODataMessageWriterSettings for normal requests. /// </summary> /// <param name="dataService">Data service instance.</param> /// <param name="requestDescription">The current request description.</param> /// <param name="responseMessage">IODataResponseMessage implementation.</param> /// <param name="model">The model to provide to the message writer.</param> /// <returns>An instance of a message writer with the appropriate settings.</returns> internal static MessageWriterBuilder ForNormalRequest(IDataService dataService, RequestDescription requestDescription, IODataResponseMessage responseMessage, IEdmModel model) { Debug.Assert(dataService != null, "dataService != null"); Debug.Assert(dataService.OperationContext != null, "dataService.OperationContext != null"); Debug.Assert(requestDescription != null, "requestDescription != null"); Debug.Assert(dataService.OperationContext.RequestMessage != null, "dataService.OperationContext.RequestMessage != null"); Debug.Assert(responseMessage != null, "responseMessage != null"); Uri serviceUri = dataService.OperationContext.AbsoluteServiceUri; Version responseVersion = requestDescription.ActualResponseVersion; MessageWriterBuilder messageWriterBuilder = new MessageWriterBuilder(serviceUri, responseVersion, dataService, responseMessage, model); // ODataLib doesn't allow custom MIME types on raw values (must be text/plain for non-binary, and application/octet for binary values). // To maintain existing V1/V2 behavior, work around this by setting the format as RawValue (we handle conneg ourself for this, so don't make ODL do its own), // and then later manually override the content type header. Conneg is done by Astoria in DataService.CreateResponseBodyWriter. if (requestDescription.ResponsePayloadKind == ODataPayloadKind.Value && !string.IsNullOrEmpty(requestDescription.MimeType)) { messageWriterBuilder.WriterSettings.SetContentType(ODataFormat.RawValue); } else { string acceptHeaderValue = dataService.OperationContext.RequestMessage.GetAcceptableContentTypes(); // In V1/V2 we defaulted to charset=utf-8 for the response when there was no specific Accept-Charset. // ODataMessageWriter uses a different default in some cases depending on the media type, so we need to override that here. string requestAcceptCharSet = dataService.OperationContext.RequestMessage.GetRequestAcceptCharsetHeader(); if (string.IsNullOrEmpty(requestAcceptCharSet) || requestAcceptCharSet == "*") { requestAcceptCharSet = XmlConstants.Utf8Encoding; } messageWriterBuilder.WriterSettings.SetContentType(acceptHeaderValue, requestAcceptCharSet); } // always set the metadata document URI. ODataLib will decide whether or not to write it. messageWriterBuilder.WriterSettings.ODataUri = new ODataUri() { ServiceRoot = serviceUri, SelectAndExpand = requestDescription.ExpandAndSelect.Clause, Path = requestDescription.Path }; messageWriterBuilder.WriterSettings.JsonPCallback = requestDescription.JsonPaddingFunctionName; return messageWriterBuilder; }
private ODataAsynchronousWriter TestInit() { this.userModel = new EdmModel(); testType = new EdmEntityType("NS", "Test"); testType.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32); this.userModel.AddElement(testType); var defaultContainer = new EdmEntityContainer("NS", "DefaultContainer"); this.userModel.AddElement(defaultContainer); this.singleton = new EdmSingleton(defaultContainer, "MySingleton", this.testType); defaultContainer.AddElement(this.singleton); responseStream = new MemoryStream(); responseMessage = new InMemoryMessage { Stream = responseStream }; messageWriter = new ODataMessageWriter(responseMessage); return messageWriter.CreateODataAsynchronousWriter(); }
private void ProcessCreate(Stream requestStream, IODataResponseMessage responseMessage) { try { // handle insert annotation if (!this.IsAllowInsert(this.QueryContext.Target.NavigationSource as IEdmEntitySet)) { throw new ODataServiceException(HttpStatusCode.BadRequest, "The insert request is not allowed.", null); } // handle content type var contentType = this.HandleContentType((IEdmEntityType)this.QueryContext.Target.ElementType); // handle entity var entities = this.QueryContext.ResolveQuery(this.DataSource); var entity = this.DataSource.UpdateProvider.Create(this.QueryContext.Target.ElementType.FullTypeName(), entities); this.DataSource.StreamProvider.CreateStream(entity, requestStream, contentType); this.DataSource.UpdateProvider.SaveChanges(); using (var messageWriter = this.CreateMessageWriter(responseMessage)) { responseMessage.SetHeader(ServiceConstants.HttpHeaders.Location, Utility.BuildLocationUri(this.QueryContext, entity).OriginalString); if (this.PreferenceContext.Return == ServiceConstants.PreferenceValue_Return_Minimal) { responseMessage.SetStatusCode(HttpStatusCode.NoContent); } else { responseMessage.SetStatusCode(HttpStatusCode.Created); var edmEntitySet = (IEdmEntitySetBase)this.QueryContext.Target.NavigationSource; ResponseWriter.WriteEntry(messageWriter.CreateODataEntryWriter(edmEntitySet), entity, edmEntitySet, ODataVersion.V4, null); } } } catch { this.DataSource.UpdateProvider.ClearChanges(); throw; } }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { try { var odataPath = this.QueryContext.QueryPath; if (this.QueryContext.Target.IsReference && this.QueryContext.Target.TypeKind != EdmTypeKind.Collection) { ProcessUpdateEntityReference(requestMessage, responseMessage, odataPath); } else { ProcessUpdateOrUpsertEntity(requestMessage, responseMessage, odataPath); } } catch { this.DataSource.UpdateProvider.ClearChanges(); throw; } }
public override void Process(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage) { // TODO: we will need to add server-driven paging for delta link object queryResults = this.QueryContext.ResolveQuery(this.DataSource); using (var messageWriter = this.CreateMessageWriter(responseMessage)) { IEdmNavigationSource navigationSource = this.QueryContext.Target.NavigationSource; IEnumerable iEnumerableResults = queryResults as IEnumerable; if (this.QueryContext.Target.NavigationSource != null && this.QueryContext.Target.TypeKind == EdmTypeKind.Collection) { IEdmEntitySetBase entitySet = navigationSource as IEdmEntitySetBase; IEdmEntityType entityType = this.QueryContext.Target.ElementType as IEdmEntityType; if (entitySet == null || entityType == null) { throw new InvalidOperationException("Invalid target when query feed."); } GenerateDeltaItemsFromFeed(iEnumerableResults, entitySet, ODataVersion.V4, this.QueryContext.QuerySelectExpandClause); Uri newDeltaLink = null; if (this.PreferenceContext.TrackingChanges) { var newDeltaToken = DeltaContext.GenerateDeltaToken(this.QueryContext.QueryUri, iEnumerableResults, entitySet, this.QueryContext.QuerySelectExpandClause); newDeltaLink = new Uri(string.Format("{0}?{1}={2}", this.ServiceRootUri, ServiceConstants.QueryOption_Delta, newDeltaToken)); responseMessage.AddPreferenceApplied(ServiceConstants.Preference_TrackChanging); } ODataDeltaWriter resultWriter = messageWriter.CreateODataDeltaWriter(entitySet, entityType); ResponseWriter.WriteDeltaFeed(resultWriter, this.DeltaItems, this.QueryContext.CountOption, newDeltaLink); resultWriter.Flush(); } else { throw Utility.BuildException(HttpStatusCode.Gone); } } }
/// <summary> /// Initializes a new instance of ODataResponseContext with the specified responseMessage, /// baseAddress and serviceOperationName. /// </summary> /// <param name="responseMessage">An instance of the IODataResponseMessage.</param> /// <param name="format">ODataFormat to be used.</param> /// <param name="version">DataServiceversion to be used</param> /// <param name="baseAddress">The baseAddress to be used while serializing feed/entry.</param> /// <param name="serviceOperationName">The serviceOperationName to use while serializing primitives and complex types.</param> public ODataResponseContext(IODataResponseMessage responseMessage, ODataFormat format, ODataVersion version, Uri baseAddress, string serviceOperationName) { if (responseMessage == null) { throw Error.ArgumentNull("responseMessage"); } if (baseAddress == null) { throw Error.ArgumentNull("baseAddress"); } if (String.IsNullOrEmpty(serviceOperationName)) { throw Error.ArgumentNullOrEmpty("serviceOperationName"); } _responseMessage = responseMessage; ODataFormat = format; ODataVersion = version; _baseAddress = baseAddress; _serviceOperationName = serviceOperationName; IsIndented = true; }
private void ProcessUpdateOrUpsertEntity(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage, ODataPath odataPath) { var targetObject = this.QueryContext.ResolveQuery(this.DataSource); string targetETag = null; if (targetObject != null) { targetETag = Utility.GetETagValue(targetObject); } var requestETagKind = RequestETagKind.None; string requestETag; if (Utility.TryGetIfMatch(this.RequestHeaders, out requestETag)) { requestETagKind = RequestETagKind.IfMatch; } else if (Utility.TryGetIfNoneMatch(this.RequestHeaders, out requestETag)) { requestETagKind = RequestETagKind.IfNoneMatch; } switch (requestETagKind) { case RequestETagKind.None: { if (targetETag == null) { if (targetObject == null) { ProcessUpsertEntity(requestMessage, responseMessage, odataPath); } else { ProcessUpdateRequestBody(requestMessage, responseMessage, targetObject, false); } } else { ResponseWriter.WriteEmptyResponse(responseMessage, (HttpStatusCode)428); } break; } case RequestETagKind.IfMatch: { if (requestETag == ServiceConstants.ETagValueAsterisk || requestETag == targetETag) { if (targetObject == null) { throw Utility.BuildException(HttpStatusCode.NotFound); } ProcessUpdateRequestBody(requestMessage, responseMessage, targetObject, false); } else { ResponseWriter.WriteEmptyResponse(responseMessage, HttpStatusCode.PreconditionFailed); } break; } case RequestETagKind.IfNoneMatch: { if (requestETag == ServiceConstants.ETagValueAsterisk) { ProcessUpsertEntity(requestMessage, responseMessage, odataPath); } else if (requestETag != targetETag) { if (targetObject == null) { throw Utility.BuildException(HttpStatusCode.NotFound); } ProcessUpdateRequestBody(requestMessage, responseMessage, targetObject, false); } else { ResponseWriter.WriteEmptyResponse(responseMessage, HttpStatusCode.PreconditionFailed); } break; } } }
private void ProcessUpdateRequestBody(IODataRequestMessage requestMessage, IODataResponseMessage responseMessage, object targetObject, bool isUpsert) { if (this.QueryContext.Target.NavigationSource != null && this.QueryContext.Target.TypeKind == EdmTypeKind.Entity) { using (var messageReader = new ODataMessageReader(requestMessage, this.GetReaderSettings(), this.DataSource.Model)) { var entryReader = messageReader.CreateODataEntryReader(this.QueryContext.Target.NavigationSource, (IEdmEntityType)this.QueryContext.Target.Type); while (entryReader.Read()) { switch (entryReader.State) { case ODataReaderState.EntryEnd: var entry = (ODataEntry)entryReader.Item; foreach (var property in entry.Properties) { if (Utility.IsETagProperty(targetObject, property.Name)) continue; // the property might be an open property, so test null first var propertyInfo = targetObject.GetType().GetProperty(property.Name); if (propertyInfo != null) { if (!isUpsert && Utility.IsReadOnly(propertyInfo)) continue; } this.DataSource.UpdateProvider.Update(targetObject, property.Name, property.Value); } break; } } } } else if (this.QueryContext.Target.Property != null && this.QueryContext.Target.TypeKind == EdmTypeKind.Complex) { using (var messageReader = new ODataMessageReader(requestMessage, this.GetReaderSettings(), this.DataSource.Model)) { var property = messageReader.ReadProperty(this.QueryContext.Target.Property); ODataComplexValue complexValue = property.Value as ODataComplexValue; foreach (var p in complexValue.Properties) { if (Utility.IsETagProperty(targetObject, property.Name)) continue; this.DataSource.UpdateProvider.Update(targetObject, p.Name, p.Value); } } } else { throw Utility.BuildException( HttpStatusCode.NotImplemented, string.Format("PATCH/PUT for '{0}' type is not supported.", this.QueryContext.Target.TypeKind), null); } var currentETag = Utility.GetETagValue(targetObject); // if the current entity has ETag field if (currentETag != null) { if (!isUpsert) { this.DataSource.UpdateProvider.UpdateETagValue(targetObject); } this.DataSource.UpdateProvider.SaveChanges(); currentETag = Utility.GetETagValue(targetObject); responseMessage.SetHeader(ServiceConstants.HttpHeaders.ETag, currentETag); } else { this.DataSource.UpdateProvider.SaveChanges(); } ResponseWriter.WriteEmptyResponse(responseMessage); }
private void ProcessUpdate(Stream requestStream, IODataResponseMessage responseMessage) { // handle entity var entity = this.HandleEntity(); // handle content type var parentUri = this.QueryContext.Target.BuildContainerUri(this.ServiceRootUri); var parentContext = new QueryContext(this.ServiceRootUri, parentUri, this.DataSource.Model); var contentType = this.HandleContentType((IEdmEntityType)parentContext.Target.ElementType); // handle ETag this.HandleETag(entity, true); // handle update this.DataSource.StreamProvider.UpdateStream(entity, requestStream, contentType); using (var messageWriter = this.CreateMessageWriter(responseMessage)) { responseMessage.SetStatusCode(HttpStatusCode.OK); var edmEntitySet = (IEdmEntitySetBase)parentContext.Target.NavigationSource; ResponseWriter.WriteEntry(messageWriter.CreateODataEntryWriter(edmEntitySet), entity, edmEntitySet, ODataVersion.V4, null); } }