/// <summary>constructor</summary> /// <param name="source">source object of async request</param> /// <param name="method">async method name on source object</param> /// <param name="serviceRequest">Originating serviceRequest</param> /// <param name="request">Originating WebRequest</param> /// <param name="requestInfo">The request info of the originating request.</param> /// <param name="callback">user callback</param> /// <param name="state">user state</param> internal QueryResult(object source, string method, DataServiceRequest serviceRequest, ODataRequestMessageWrapper request, RequestInfo requestInfo, AsyncCallback callback, object state) : base(source, method, callback, state) { Debug.Assert(null != request, "null request"); this.ServiceRequest = serviceRequest; this.Request = request; this.RequestInfo = requestInfo; this.Abortable = request; }
/// <summary> /// Synchronously executes the query and returns the value. /// </summary> /// <param name="context">The context.</param> /// <param name="parseQueryResultFunc">A function to process the query result.</param> /// <returns>The query result</returns> internal TElement GetValue <TElement>(DataServiceContext context, Func <QueryResult, TElement> parseQueryResultFunc) { Debug.Assert(context != null, "context is null"); QueryComponents queryComponents = this.QueryComponents(context.Model); Version requestVersion = queryComponents.Version; if (requestVersion == null) { requestVersion = Util.ODataVersion4; } Uri requestUri = queryComponents.Uri; DataServiceRequest <TElement> serviceRequest = new DataServiceRequest <TElement>(requestUri, queryComponents, null); HeaderCollection headers = new HeaderCollection(); // Validate and set the request DSV header headers.SetRequestVersion(requestVersion, context.MaxProtocolVersionAsVersion); context.Format.SetRequestAcceptHeaderForCount(headers); string httpMethod = XmlConstants.HttpMethodGet; ODataRequestMessageWrapper request = context.CreateODataRequestMessage( context.CreateRequestArgsAndFireBuildingRequest(httpMethod, requestUri, headers, context.HttpStack, null /*descriptor*/), null /*descriptor*/); QueryResult queryResult = new QueryResult(this, Util.ExecuteMethodName, serviceRequest, request, new RequestInfo(context), null, null); try { queryResult.ExecuteQuery(); if (HttpStatusCode.NoContent != queryResult.StatusCode) { TElement parsedResult = parseQueryResultFunc(queryResult); return(parsedResult); } else { throw new DataServiceQueryException(Strings.DataServiceRequest_FailGetValue, queryResult.Failure); } } catch (InvalidOperationException ex) { QueryOperationResponse operationResponse; operationResponse = queryResult.GetResponse <TElement>(MaterializeAtom.EmptyResults); if (operationResponse != null) { operationResponse.Error = ex; throw new DataServiceQueryException(Strings.DataServiceException_GeneralError, ex, operationResponse); } throw; } }
/// <summary>Ends an asynchronous query request to a data service.</summary> /// <returns>Returns an <see cref="T:System.Collections.Generic.IEnumerable`1" /> that contains the results of the query operation.</returns> /// <param name="asyncResult">The pending asynchronous query request.</param> /// <exception cref="T:Microsoft.OData.Client.DataServiceQueryException">When the data service returns an HTTP 404: Resource Not Found error.</exception> public new IEnumerable <TElement> EndExecute(IAsyncResult asyncResult) { if (this.IsFunction) { return(this.Context.EndExecute <TElement>(asyncResult)); } else { return(DataServiceRequest.EndExecute <TElement>(this, this.Context, Util.ExecuteMethodName, asyncResult)); } }
/// <summary> /// execute uri and materialize result /// </summary> /// <typeparam name="TElement">element type</typeparam> /// <param name="context">context</param> /// <param name="queryComponents">query components for request to execute</param> /// <returns>enumerable of results</returns> internal QueryOperationResponse <TElement> Execute <TElement>(DataServiceContext context, QueryComponents queryComponents) { QueryResult result = null; try { Uri requestUri = queryComponents.Uri; DataServiceRequest <TElement> serviceRequest = new DataServiceRequest <TElement>(requestUri, queryComponents, this.Plan); result = serviceRequest.CreateExecuteResult(this, context, null, null, Util.ExecuteMethodName); result.ExecuteQuery(); return(result.ProcessResult <TElement>(this.Plan)); } catch (InvalidOperationException ex) { if (result != null) { QueryOperationResponse operationResponse = result.GetResponse <TElement>(MaterializeAtom.EmptyResults); if (null != operationResponse) { if (context.IgnoreResourceNotFoundException) { DataServiceClientException cex = ex as DataServiceClientException; if (cex != null && cex.StatusCode == (int)HttpStatusCode.NotFound) { // don't throw return((QueryOperationResponse <TElement>)operationResponse); } } operationResponse.Error = ex; throw new DataServiceQueryException(Strings.DataServiceException_GeneralError, ex, operationResponse); } } throw; } }
/// <summary> /// Creates an instance of <see cref="MaterializeAtom"/> for the given plan. /// </summary> /// <param name="plan">The projection plan.</param> /// <param name="payloadKind">expected payload kind.</param> /// <returns>A new materializer instance</returns> private MaterializeAtom CreateMaterializer(ProjectionPlan plan, ODataPayloadKind payloadKind) { QueryComponents queryComponents = this.ServiceRequest.QueryComponents(this.responseInfo.Model); // In V2, in projection path, we did not check for assignability between the expected type and the type returned by the type resolver. if (plan != null || queryComponents.Projection != null) { this.RequestInfo.TypeResolver.IsProjectionRequest(); } var responseMessageWrapper = new HttpWebResponseMessage( new HeaderCollection(this.responseMessage), this.responseMessage.StatusCode, this.GetResponseStream); return(DataServiceRequest.Materialize( this.responseInfo, queryComponents, plan, this.ContentType, responseMessageWrapper, payloadKind)); }
/// <summary> /// process the batch response /// </summary> /// <param name="batchReader">The batch reader to use for reading the batch response.</param> /// <returns>enumerable of QueryResponse or null</returns> /// <remarks> /// The batch message reader for the entire batch response is stored in this.batchMessageReader. /// Note that this method takes over the ownership of this reader and must Dispose it if it successfully returns. /// </remarks> private IEnumerable <OperationResponse> HandleBatchResponse(ODataBatchReader batchReader) { try { if (this.batchMessageReader == null) { // The enumerable returned by this method can be enumerated multiple times. // In that case it looks like if the method is called multiple times. // This didn't fail in previous versions, it simply returned no results, so we need to do the same. yield break; } Debug.Assert(batchReader != null, "batchReader != null"); bool changesetFound = false; bool insideChangeset = false; int queryCount = 0; int operationCount = 0; this.entryIndex = 0; while (batchReader.Read()) { switch (batchReader.State) { #region ChangesetStart case ODataBatchReaderState.ChangesetStart: if ((Util.IsBatchWithSingleChangeset(this.Options) && changesetFound) || (operationCount != 0)) { // Throw if we encounter multiple changesets when running in batch with single changeset mode // or if we encounter operations outside of a changeset. Error.ThrowBatchUnexpectedContent(InternalError.UnexpectedBeginChangeSet); } insideChangeset = true; break; #endregion #region ChangesetEnd case ODataBatchReaderState.ChangesetEnd: changesetFound = true; operationCount = 0; insideChangeset = false; break; #endregion #region Operation case ODataBatchReaderState.Operation: Exception exception = this.ProcessCurrentOperationResponse(batchReader, insideChangeset); if (!insideChangeset) { #region Get response Debug.Assert(operationCount == 0, "missing an EndChangeSet 2"); QueryOperationResponse qresponse = null; try { if (exception == null) { DataServiceRequest query = this.Queries[queryCount]; ResponseInfo responseInfo = this.RequestInfo.GetDeserializationInfo(null /*mergeOption*/); MaterializeAtom materializer = DataServiceRequest.Materialize( responseInfo, query.QueryComponents(this.RequestInfo.Model), null, this.currentOperationResponse.Headers.GetHeader(XmlConstants.HttpContentType), this.currentOperationResponse.CreateResponseMessage(), query.PayloadKind); qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, materializer); } } catch (ArgumentException e) { exception = e; } catch (FormatException e) { exception = e; } catch (InvalidOperationException e) { exception = e; } if (qresponse == null) { if (this.Queries != null) { // this is the normal ExecuteBatch response DataServiceRequest query = this.Queries[queryCount]; if (this.RequestInfo.IgnoreResourceNotFoundException && this.currentOperationResponse.StatusCode == HttpStatusCode.NotFound) { qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, MaterializeAtom.EmptyResults); } else { qresponse = QueryOperationResponse.GetInstance(query.ElementType, this.currentOperationResponse.Headers, query, MaterializeAtom.EmptyResults); qresponse.Error = exception; } } else { // This is top-level failure for SaveChanges(SaveChangesOptions.BatchWithSingleChangeset) or SaveChanges(SaveChangesOptions.BatchWithIndependentOperations) operations. // example: server doesn't support batching or number of batch objects exceeded an allowed limit. // ex could be null if the server responded to SaveChanges with an unexpected success with // response of batched GETS that did not correspond the original POST/PATCH/PUT/DELETE requests. // we expect non-null since server should have failed with a non-success code // and HandleResponse(status, ...) should generate the exception object throw exception; } } qresponse.StatusCode = (int)this.currentOperationResponse.StatusCode; queryCount++; yield return(qresponse); #endregion } else { #region Update response try { Descriptor descriptor = this.ChangedEntries[this.entryIndex]; operationCount += this.SaveResultProcessed(descriptor); if (exception != null) { throw exception; } this.HandleOperationResponseHeaders(this.currentOperationResponse.StatusCode, this.currentOperationResponse.Headers); #if DEBUG this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers, this.currentOperationResponse.StatusCode); #else this.HandleOperationResponse(descriptor, this.currentOperationResponse.Headers); #endif } catch (Exception e) { this.ChangedEntries[this.entryIndex].SaveError = e; exception = e; if (!CommonUtil.IsCatchableExceptionType(e)) { throw; } } ChangeOperationResponse changeOperationResponse = new ChangeOperationResponse(this.currentOperationResponse.Headers, this.ChangedEntries[this.entryIndex]); changeOperationResponse.StatusCode = (int)this.currentOperationResponse.StatusCode; if (exception != null) { changeOperationResponse.Error = exception; } operationCount++; this.entryIndex++; yield return(changeOperationResponse); #endregion } break; #endregion default: Error.ThrowBatchExpectedResponse(InternalError.UnexpectedBatchState); break; } } Debug.Assert(batchReader.State == ODataBatchReaderState.Completed, "unexpected batch state"); // Check for a changeset without response (first line) or GET request without response (second line). // either all saved entries must be processed or it was a batch and one of the entries has the error if ((this.Queries == null && (!changesetFound || 0 < queryCount || this.ChangedEntries.Any(o => o.ContentGeneratedForSave && o.SaveResultWasProcessed == 0) && (!this.IsBatchRequest || this.ChangedEntries.FirstOrDefault(o => o.SaveError != null) == null))) || (this.Queries != null && queryCount != this.Queries.Length)) { throw Error.InvalidOperation(Strings.Batch_IncompleteResponseCount); } } finally { // Note that this will be called only once the enumeration of all responses is finished and the Dispose // was called on the IEnumerator used for that enumeration. It is not called when the method returns, // since the compiler change this method to return the compiler-generated IEnumerable. Util.Dispose(ref this.batchMessageReader); } }
/// <summary> /// Synchronizely get the query set count from the server by executing the $count=value query /// </summary> /// <param name="context">The context</param> /// <returns>The server side count of the query set</returns> internal long GetQuerySetCount(DataServiceContext context) { Debug.Assert(null != context, "context is null"); Version requestVersion = this.QueryComponents(context.Model).Version; if (requestVersion == null) { requestVersion = Util.ODataVersion4; } QueryResult response = null; QueryComponents qc = this.QueryComponents(context.Model); Uri requestUri = qc.Uri; DataServiceRequest <long> serviceRequest = new DataServiceRequest <long>(requestUri, qc, null); HeaderCollection headers = new HeaderCollection(); // Validate and set the request DSV header headers.SetRequestVersion(requestVersion, context.MaxProtocolVersionAsVersion); context.Format.SetRequestAcceptHeaderForCount(headers); string httpMethod = XmlConstants.HttpMethodGet; ODataRequestMessageWrapper request = context.CreateODataRequestMessage( context.CreateRequestArgsAndFireBuildingRequest(httpMethod, requestUri, headers, context.HttpStack, null /*descriptor*/), null /*descriptor*/); response = new QueryResult(this, Util.ExecuteMethodName, serviceRequest, request, new RequestInfo(context), null, null); try { response.ExecuteQuery(); if (HttpStatusCode.NoContent != response.StatusCode) { StreamReader sr = new StreamReader(response.GetResponseStream()); long r = -1; try { r = XmlConvert.ToInt64(sr.ReadToEnd()); } finally { sr.Close(); } return(r); } else { throw new DataServiceQueryException(Strings.DataServiceRequest_FailGetCount, response.Failure); } } catch (InvalidOperationException ex) { QueryOperationResponse operationResponse = null; operationResponse = response.GetResponse <long>(MaterializeAtom.EmptyResults); if (null != operationResponse) { operationResponse.Error = ex; throw new DataServiceQueryException(Strings.DataServiceException_GeneralError, ex, operationResponse); } throw; } }
/// <summary>constructor</summary> /// <param name="source">source object of async request</param> /// <param name="method">async method name on source object</param> /// <param name="serviceRequest">Originating serviceRequest</param> /// <param name="request">Originating WebRequest</param> /// <param name="requestInfo">The request info of the originating request.</param> /// <param name="callback">user callback</param> /// <param name="state">user state</param> /// <param name="requestContentStream">the stream containing the request data.</param> internal QueryResult(object source, string method, DataServiceRequest serviceRequest, ODataRequestMessageWrapper request, RequestInfo requestInfo, AsyncCallback callback, object state, ContentStream requestContentStream) : this(source, method, serviceRequest, request, requestInfo, callback, state) { Debug.Assert(null != requestContentStream, "null requestContentStream"); this.requestContentStream = requestContentStream; }
/// <summary>constructor</summary> /// <param name="entity">entity</param> /// <param name="propertyName">name of collection or reference property to load</param> /// <param name="context">Originating context</param> /// <param name="request">Originating WebRequest</param> /// <param name="callback">user callback</param> /// <param name="state">user state</param> /// <param name="dataServiceRequest">request object.</param> /// <param name="plan">Projection plan for materialization; possibly null.</param> /// <param name="isContinuation">Whether this request is a continuation request.</param> internal LoadPropertyResult(object entity, string propertyName, DataServiceContext context, ODataRequestMessageWrapper request, AsyncCallback callback, object state, DataServiceRequest dataServiceRequest, ProjectionPlan plan, bool isContinuation) : base(context, Util.LoadPropertyMethodName, dataServiceRequest, request, new RequestInfo(context, isContinuation), callback, state) { this.entity = entity; this.propertyName = propertyName; this.plan = plan; }
/// <summary> /// constructor /// </summary> /// <param name="headers">HTTP headers</param> /// <param name="query">original query</param> /// <param name="results">retrieved objects</param> internal QueryOperationResponse(HeaderCollection headers, DataServiceRequest query, MaterializeAtom results) : base(headers, query, results) { }
/// <summary> /// constructor /// </summary> /// <param name="headers">HTTP headers</param> /// <param name="query">original query</param> /// <param name="results">retrieved objects</param> internal QueryOperationResponse(HeaderCollection headers, DataServiceRequest query, MaterializeAtom results) : base(headers) { this.query = query; this.results = results; }
internal static QueryOperationResponse GetInstance(Type elementType, HeaderCollection headers, DataServiceRequest query, MaterializeAtom results) { Type genericType = typeof(QueryOperationResponse <>).MakeGenericType(elementType); #if !ASTORIA_LIGHT && !PORTABLELIB return((QueryOperationResponse)Activator.CreateInstance( genericType, BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { headers, query, results }, System.Globalization.CultureInfo.InvariantCulture)); #else ConstructorInfo info = genericType.GetInstanceConstructors(false /*isPublic*/).Single(); return((QueryOperationResponse)Util.ConstructorInvoke(info, new object[] { headers, query, results })); #endif }
internal static QueryOperationResponse GetInstance(Type elementType, HeaderCollection headers, DataServiceRequest query, MaterializeAtom results) { Type genericType = typeof(QueryOperationResponse <>).MakeGenericType(elementType); return((QueryOperationResponse)Activator.CreateInstance( genericType, BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Instance, null, new object[] { headers, query, results }, System.Globalization.CultureInfo.InvariantCulture)); }