Beispiel #1
0
 /// <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;
 }
Beispiel #2
0
        /// <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;
            }
        }
Beispiel #3
0
 /// <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));
     }
 }
Beispiel #4
0
        /// <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;
            }
        }
Beispiel #5
0
        /// <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));
        }
Beispiel #6
0
        /// <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);
            }
        }
Beispiel #7
0
        /// <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;
            }
        }
Beispiel #8
0
 /// <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;
 }
Beispiel #9
0
 /// <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;
 }
Beispiel #10
0
 /// <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
        }
Beispiel #13
0
        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));
        }