/// <summary>
        /// Wraps the specified product. If product is a DataServiceContext then registeres it for tracking.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="product">The product.</param>
        /// <returns>The wrapper for the product instance.</returns>
        public TResult Wrap <TResult>(object product) where TResult : IWrappedObject
        {
            if (product == null)
            {
                return(default(TResult));
            }

            Type[] argTypes   = new Type[] { typeof(IWrapperScope), typeof(object) };
            Type   resultType = typeof(TResult);

            ConstructorInfo ctor = resultType.GetInstanceConstructor(true, argTypes);

            ExceptionUtilities.CheckObjectNotNull(ctor, "Cannot find constructor: {0}(IWrapperScope, object)", typeof(TResult).Name);

            DSClient.DataServiceContext context = product as DSClient.DataServiceContext;

            if (context != null)
            {
                DataServiceProtocolVersion maxProtocolVersion = DataServiceProtocolVersion.Unspecified;
#if !WINDOWS_PHONE
                maxProtocolVersion = context.MaxProtocolVersion.ToTestEnum();
#endif
                var contextData = DataServiceContextData.CreateDataServiceContextDataFromDataServiceContext(context, maxProtocolVersion);

                this.contextDatas.Add(context, contextData);
            }

            return((TResult)ctor.Invoke(new object[] { this, product }));
        }
        /// <summary>
        /// Traces the exception which occured durion a call.
        /// </summary>
        /// <param name="callId">The call id (returned by BeginTraceCall).</param>
        /// <param name="methodInfo">The method info that is being invoked.</param>
        /// <param name="instance">The object instance.</param>
        /// <param name="exception">The exception which occured.</param>
        void IWrapperScope.TraceException(int callId, MethodBase methodInfo, object instance, Exception exception)
        {
            DSClient.DataServiceContext context = instance as DSClient.DataServiceContext;
            if (context != null)
            {
                if (methodInfo.Name == "LoadProperty" || methodInfo.Name == "EndLoadProperty")
                {
                }
                else if (methodInfo.Name == "EndGetReadStream")
                {
                    this.getReadStreamInfos.Remove(context);
                }
                else if (methodInfo.Name.EndsWith("SaveChanges", StringComparison.Ordinal))
                {
                    ExceptionUtilities.CheckObjectNotNull(this.DescriptorDataChangeTracker, "Cannot track SaveChanges without descriptor change tracker");
                    ExceptionUtilities.Assert(!this.DescriptorDataChangeTracker.ApplyUpdatesImmediately, "ApplyUpdatesImmediately unexpectedly true after SaveChanges call");
                    this.DescriptorDataChangeTracker.ApplyPendingUpdates();
                    this.DescriptorDataChangeTracker.ApplyUpdatesImmediately = true;
                    this.saveChangesInfos.Remove(context);
                }
#if !WINDOWS_PHONE
                this.HttpTracker.TryCompleteCurrentRequest(context);
#endif
            }
        }
        /// <summary>
        /// Traces the result of a call.
        /// </summary>
        /// <param name="callId">The call id (returned by BeginTraceCall).</param>
        /// <param name="methodInfo">The method info that is being invoked.</param>
        /// <param name="instance">The object instance.</param>
        /// <param name="parameterValues">The parameter values.</param>
        /// <param name="returnValue">The return value.</param>
        void IWrapperScope.TraceResult(int callId, MethodBase methodInfo, object instance, object[] parameterValues, ref object returnValue)
        {
            DSClient.DataServiceContext context = instance as DSClient.DataServiceContext;
            DataServiceContextData      data;

            if (context != null)
            {
                if (this.contextDatas.TryGetValue(context, out data))
                {
                    this.TrackDataServiceContext(data, context, methodInfo, returnValue, parameterValues);
                }

                if (methodInfo.Name == "LoadProperty" || methodInfo.Name == "EndLoadProperty")
                {
                }

                if (methodInfo.Name == "EndGetReadStream")
                {
                    this.getReadStreamInfos.Remove(context);
                }

                if (methodInfo.Name == "SaveChanges" || methodInfo.Name == "EndSaveChanges")
                {
                    this.saveChangesInfos.Remove(context);
                }

                if (methodInfo.Name == "CreateQuery")
                {
                    this.querysCreated.Add(((DSClient.DataServiceQuery)returnValue).Provider, context);
                }

                if (ContextMethodsThatSendRequests.Contains(methodInfo.Name))
                {
#if !WINDOWS_PHONE
                    this.HttpTracker.TryCompleteCurrentRequest(context);
#endif
                }
            }

            var query = instance as DSClient.DataServiceQuery;
            if (query != null)
            {
                if (this.querysCreated.TryGetValue(query.Provider, out context))
                {
                    if (QueryMethodsThatSendRequests.Contains(methodInfo.Name))
                    {
#if !WINDOWS_PHONE
                        this.HttpTracker.TryCompleteCurrentRequest(context);
#endif
                    }
                }
            }

            if (this.OnCurrentMethodReturn != null)
            {
                this.OnCurrentMethodReturn();
                this.OnCurrentMethodReturn = null;
            }
        }
        private static void SetExpectedPreferHeader(HttpRequestData request, DSClient.DataServiceContext contextData)
        {
#if !SILVERLIGHT || WIN8
            SetExpectedPreferHeader(request, contextData.AddAndUpdateResponsePreference.ToTestEnum());
#else
            SetUnexpectedPreferHeader(request);
#endif
        }
        public DataServiceContextData GetDataServiceContextData(WrappedDataServiceContext context)
        {
            DSClient.DataServiceContext unwrappedContext = (DSClient.DataServiceContext)context.Product;
            DataServiceContextData      data;

            if (!this.contextDatas.TryGetValue(unwrappedContext, out data))
            {
                throw new TaupoInvalidOperationException("Given data service context is not tracked in this scope.");
            }

            return(data);
        }
        /// <summary>
        /// Begins tracing of the call.
        /// </summary>
        /// <param name="methodInfo">The method info that is being invoked.</param>
        /// <param name="instance">The object instance.</param>
        /// <param name="parameterValues">The parameter values.</param>
        /// <returns>
        /// Call handle which is used to correlate parameters with result values.
        /// </returns>
        /// <remarks>
        /// If the call handle is 0, the wrapper will not call TraceResult() or TraceException()
        /// </remarks>
        int IWrapperScope.BeginTraceCall(MethodBase methodInfo, object instance, object[] parameterValues)
        {
            DSClient.DataServiceContext context = instance as DSClient.DataServiceContext;
            if (context != null)
            {
                if (methodInfo.Name == "LoadProperty" || methodInfo.Name == "BeginLoadProperty")
                {
                }
                else if (methodInfo.Name == "BeginGetReadStream")
                {
                    GetReadStreamInfo info = new GetReadStreamInfo()
                    {
                        Entity = parameterValues[0]
                    };
                    if (parameterValues.Length > 1)
                    {
                        info.StreamName = parameterValues[1] as string;
                    }

                    this.getReadStreamInfos[context] = info;
                }
                else if (methodInfo.Name == "SaveChanges" || methodInfo.Name == "BeginSaveChanges")
                {
                    ExceptionUtilities.CheckObjectNotNull(this.DescriptorDataChangeTracker, "Cannot track SaveChanges without descriptor change tracker");
                    ExceptionUtilities.Assert(this.DescriptorDataChangeTracker.ApplyUpdatesImmediately, "ApplyUpdatesImmediately unexpectedly false before SaveChanges call");
                    this.DescriptorDataChangeTracker.ApplyUpdatesImmediately = false;

                    var info = new SaveChangesInfo();
                    this.saveChangesInfos[context] = info;
                    info.Options = context.SaveChangesDefaultOptions.ToTestEnum();
                    if (methodInfo.Name == "BeginSaveChanges")
                    {
                        if (parameterValues.Length > 2)
                        {
                            info.Options = (SaveChangesOptions)parameterValues[0];
                        }
                    }
                    else if (parameterValues.Length > 0)
                    {
                        info.Options = (SaveChangesOptions)parameterValues[0];
                    }
                }
                else if (methodInfo.Name == "SetSaveStream")
                {
                    this.WrapSetSaveStreamArguments(methodInfo, parameterValues);
                }
            }

            return(1);
        }
        private static int GetStatusCodeForUpdate(DSClient.DataServiceContext context)
        {
            DataServiceResponsePreference preference = DataServiceResponsePreference.Unspecified;

            preference = context.AddAndUpdateResponsePreference.ToTestEnum();

            if (preference == DataServiceResponsePreference.IncludeContent)
            {
                return((int)HttpStatusCode.OK);
            }
            else
            {
                return((int)HttpStatusCode.NoContent);
            }
        }
Beispiel #8
0
        private static int GetStatusCodeForInsert(DSClient.DataServiceContext context)
        {
            DataServiceResponsePreference preference = DataServiceResponsePreference.Unspecified;

#if !WINDOWS_PHONE
            preference = context.AddAndUpdateResponsePreference.ToTestEnum();
#endif
            if (preference == DataServiceResponsePreference.NoContent)
            {
                return((int)HttpStatusCode.NoContent);
            }
            else
            {
                return((int)HttpStatusCode.Created);
            }
        }
        /// <summary>
        /// Executes SaveChanges method on the specified context and verifies the results.
        /// </summary>
        /// <param name="continuation">The async continuation</param>
        /// <param name="contextData">The context data.</param>
        /// <param name="context">The context to verify SaveChanges.</param>
        /// <param name="options">The options for saving changes. Passing null will use the context's default.</param>
        /// <param name="onCompletion">callback for when save changes verification completes</param>
        public virtual void VerifySaveChanges(IAsyncContinuation continuation, DataServiceContextData contextData, DSClient.DataServiceContext context, SaveChangesOptions?options, Action <IAsyncContinuation, DSClient.DataServiceResponse> onCompletion)
        {
            ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");
            ExceptionUtilities.CheckArgumentNotNull(onCompletion, "onCompletion");
            ExceptionUtilities.CheckAllRequiredDependencies(this);

            // ensure that two calls are not being processed in parallel
            ExceptionUtilities.Assert(this.Input == null, "Input was not null, possibly due to simultaneous calls or using the wrong async continuation");
            ExceptionUtilities.Assert(this.State == null, "State was not null, possibly due to simultaneous calls or using the wrong async continuation");
            continuation = continuation.OnContinueOrFail(
                () =>
            {
                this.Input = null;
                this.State = null;
            });

            this.Input = new VerifierInput()
            {
                ContextData  = contextData,
                Context      = context,
                Options      = options,
                OnCompletion = onCompletion,
            };

            AsyncHelpers.RunActionSequence(
                continuation,
                this.InitializeState,
                this.VerifyContextState,
                this.CallProductApi,
                this.VerifyRequests,
                this.VerifyResponse,
                this.VerifyContextState,
                this.VerifyServerState,
                this.Complete);
        }
Beispiel #10
0
        /// <summary>
        /// Executes SaveChanges on the specified context and with specified options and verifies the results.
        /// </summary>
        /// <param name="verifier">The verifier to use for verification.</param>
        /// <param name="contextData">The data for the context.</param>
        /// <param name="context">The context to verify SaveChanges on.</param>
        /// <param name="options">The options for saving changes.</param>
        /// <returns>The response from SaveChanges</returns>
        public static DSClient.DataServiceResponse VerifySaveChanges(this ISaveChangesVerifier verifier, DataServiceContextData contextData, DSClient.DataServiceContext context, SaveChangesOptions?options)
        {
            ExceptionUtilities.CheckArgumentNotNull(verifier, "verifier");
            ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");

            DSClient.DataServiceResponse response = null;
            SyncHelpers.ExecuteActionAndWait(c1 => verifier.VerifySaveChanges(c1, contextData, context, options, (c2, r) => { response = r; c2.Continue(); }));
            return(response);
        }
        /// <summary>
        /// Calculates the expected response from DataServiceContext.SaveChanges based on the context data before saving changes.
        /// Assumes there are no errors in the response.
        /// </summary>
        /// <param name="dataBeforeSaveChanges">The data before saving changes.</param>
        /// <param name="options">The options for saving changes.</param>
        /// <param name="context">The DataServiceContext instance which is calling SaveChanges.</param>
        /// <returns><see cref="DataServiceResponseData"/> that expresses expectations for the response.</returns>
        public DataServiceResponseData CalculateSaveChangesResponseData(DataServiceContextData dataBeforeSaveChanges, SaveChangesOptions options, DSClient.DataServiceContext context)
        {
            ExceptionUtilities.CheckArgumentNotNull(dataBeforeSaveChanges, "dataBeforeSaveChanges");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");

            DataServiceResponseData responseData = new DataServiceResponseData();

            responseData.IsBatchResponse = options == SaveChangesOptions.Batch;

            bool hasChanges = false;

            // Note: ordering is important as changes should be processed in the order specified by user.
            foreach (DescriptorData descriptorData in dataBeforeSaveChanges.GetOrderedChanges())
            {
                int statusCode = (int)HttpStatusCode.NoContent;

                var entityDescriptorData = descriptorData as EntityDescriptorData;
                if (entityDescriptorData != null)
                {
                    if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Modified)
                    {
                        responseData.Add(new ChangeOperationResponseData(descriptorData)
                        {
                            StatusCode = statusCode
                        });
                    }

                    if (descriptorData.State == EntityStates.Added)
                    {
                        statusCode = GetStatusCodeForInsert(context);

                        if (entityDescriptorData.IsMediaLinkEntry)
                        {
                            responseData.Add(new ChangeOperationResponseData(descriptorData)
                            {
                                StatusCode = statusCode
                            });
                            statusCode = GetStatusCodeForUpdate(context);
                        }
                    }
                    else if (descriptorData.State == EntityStates.Modified)
                    {
                        statusCode = GetStatusCodeForUpdate(context);
                    }
                    else if (descriptorData.State != EntityStates.Deleted)
                    {
                        continue;
                    }
                }

                var linkDescriptorData = descriptorData as LinkDescriptorData;
                if (linkDescriptorData != null && (linkDescriptorData.State == EntityStates.Added || linkDescriptorData.State == EntityStates.Modified))
                {
                    if (!linkDescriptorData.WillTriggerSeparateRequest())
                    {
                        continue;
                    }
                }

                responseData.Add(new ChangeOperationResponseData(descriptorData)
                {
                    StatusCode = statusCode
                });
                hasChanges = true;
            }

            if (responseData.IsBatchResponse)
            {
                responseData.BatchStatusCode = hasChanges ? (int)HttpStatusCode.Accepted : 0;
            }
            else
            {
                responseData.BatchStatusCode = -1;
            }

            return(responseData);
        }
        public IEnumerable <HttpRequestData> CalculateSaveChangesRequestData(DataServiceContextData dataBeforeSaveChanges, DSClient.DataServiceContext context, SaveChangesOptions options, IEnumerable <DSClient.OperationResponse> cachedOperationsFromResponse)
        {
            ExceptionUtilities.CheckArgumentNotNull(dataBeforeSaveChanges, "dataBeforeSaveChanges");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");
            ExceptionUtilities.CheckArgumentNotNull(cachedOperationsFromResponse, "cachedOperationsFromResponse");

            // make a clone to avoid changing what was passed in
            var contextDataClone = dataBeforeSaveChanges.Clone();

            if (options == SaveChangesOptions.Batch)
            {
                return(new[] { BuildBatchRequest(contextDataClone) });
            }

            var responseQueue = new Queue <DSClient.OperationResponse>(cachedOperationsFromResponse);

            var requests = new List <HttpRequestData>();

            foreach (var descriptorData in contextDataClone.GetOrderedChanges())
            {
                var linkDescriptorData = descriptorData as LinkDescriptorData;
                if (linkDescriptorData != null)
                {
                    if (!linkDescriptorData.WillTriggerSeparateRequest())
                    {
                        continue;
                    }

                    var info = linkDescriptorData.SourceDescriptor.LinkInfos.SingleOrDefault(l => l.Name == linkDescriptorData.SourcePropertyName);
                    if (linkDescriptorData.State == EntityStates.Added)
                    {
                        requests.Add(this.CreateAddLinkRequest(linkDescriptorData, info));
                        SetExpectedIfMatchHeader(requests.Last(), null);
                        SetUnexpectedPreferHeader(requests.Last());
                        SetExpectedXHTTPMethodHeader(requests.Last(), false);
                        SetExpectedDataServiceVersion(requests.Last(), DataServiceProtocolVersion.V4);

                        ExceptionUtilities.Assert(responseQueue.Count > 0, "Link operation did not have a response");
                        responseQueue.Dequeue();
                    }
                    else if (linkDescriptorData.State == EntityStates.Modified)
                    {
                        requests.Add(this.CreateSetLinkRequest(linkDescriptorData, info));
                        SetExpectedIfMatchHeader(requests.Last(), null);
                        SetUnexpectedPreferHeader(requests.Last());
                        SetExpectedXHTTPMethodHeader(requests.Last(), context.UsePostTunneling);
                        SetExpectedDataServiceVersion(requests.Last(), DataServiceProtocolVersion.V4);

                        ExceptionUtilities.Assert(responseQueue.Count > 0, "Link operation did not have a response");
                        responseQueue.Dequeue();
                    }
                    else if (linkDescriptorData.State == EntityStates.Deleted)
                    {
                        requests.Add(this.CreateDeleteLinkRequest(linkDescriptorData, info));
                        SetExpectedIfMatchHeader(requests.Last(), null);
                        SetUnexpectedPreferHeader(requests.Last());
                        SetExpectedXHTTPMethodHeader(requests.Last(), context.UsePostTunneling);
                        SetExpectedDataServiceVersion(requests.Last(), DataServiceProtocolVersion.V4);

                        ExceptionUtilities.Assert(responseQueue.Count > 0, "Link operation did not have a response");
                        responseQueue.Dequeue();
                    }
                }

                var entityDescriptorData = descriptorData as EntityDescriptorData;
                if (entityDescriptorData != null)
                {
                    if (entityDescriptorData.State == EntityStates.Added)
                    {
                        requests.Add(this.CreateInsertRequest(contextDataClone, entityDescriptorData));
                        SetExpectedIfMatchHeader(requests.Last(), null);
                        SetExpectedPreferHeader(requests.Last(), context);
                        SetExpectedXHTTPMethodHeader(requests.Last(), false);

                        if (entityDescriptorData.IsMediaLinkEntry)
                        {
                            SetExpectedDataServiceVersion(requests.Last(), DataServiceProtocolVersion.V4);
                        }
                        else if (dataBeforeSaveChanges.AddAndUpdateResponsePreference != DataServiceResponsePreference.None)
                        {
                            SetExpectedDataServiceVersion(requests.Last(), DataServiceProtocolVersion.V4);
                        }
                        else
                        {
                            SetExpectedDataServiceVersion(requests.Last(), this.EntityDescriptorVersionCalculator.CalculateDataServiceVersion(entityDescriptorData, contextDataClone.MaxProtocolVersion));
                        }

                        SetExpectedMaxDataServiceVersion(requests.Last(), context);

                        this.ApplyNextResponseHeadersAndPayload(contextDataClone, entityDescriptorData, responseQueue);

                        if (entityDescriptorData.IsMediaLinkEntry)
                        {
                            requests.Add(this.CreateUpdateRequest(options, entityDescriptorData));
                            SetExpectedIfMatchHeader(requests.Last(), entityDescriptorData.ETag);
                            SetExpectedPreferHeader(requests.Last(), context);
                            SetExpectedXHTTPMethodHeader(requests.Last(), context.UsePostTunneling);
                            SetExpectedDataServiceVersion(requests.Last(), DataServiceProtocolVersion.V4);
                            SetExpectedMaxDataServiceVersion(requests.Last(), context);

                            this.ApplyNextResponseHeadersAndPayload(contextDataClone, entityDescriptorData, responseQueue);
                        }
                    }
                    else
                    {
                        if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Modified)
                        {
                            requests.Add(new HttpRequestData()
                            {
                                Verb = HttpVerb.Put, Uri = entityDescriptorData.EditStreamUri
                            });
                            SetExpectedIfMatchHeader(requests.Last(), entityDescriptorData.StreamETag);
                            SetUnexpectedPreferHeader(requests.Last());
                            SetExpectedXHTTPMethodHeader(requests.Last(), context.UsePostTunneling);
                            SetExpectedDataServiceVersion(requests.Last(), DataServiceProtocolVersion.V4);

                            ExceptionUtilities.Assert(responseQueue.Count > 0, "Stream operation did not have a response");
                            var response = responseQueue.Dequeue();
                            entityDescriptorData.DefaultStreamDescriptor.UpdateFromHeaders(response.Headers);
                        }

                        if (entityDescriptorData.State == EntityStates.Modified)
                        {
                            requests.Add(this.CreateUpdateRequest(options, entityDescriptorData));
                            SetExpectedIfMatchHeader(requests.Last(), entityDescriptorData.ETag);
                            SetExpectedPreferHeader(requests.Last(), context);
                            SetExpectedXHTTPMethodHeader(requests.Last(), context.UsePostTunneling);
                            SetExpectedDataServiceVersion(requests.Last(), this.EntityDescriptorVersionCalculator.CalculateDataServiceVersion(entityDescriptorData, dataBeforeSaveChanges.MaxProtocolVersion));

                            if (options == SaveChangesOptions.PatchOnUpdate || contextDataClone.AddAndUpdateResponsePreference != DataServiceResponsePreference.None)
                            {
                                SetExpectedDataServiceVersion(requests.Last(), DataServiceProtocolVersion.V4);
                            }

                            this.ApplyNextResponseHeadersAndPayload(contextDataClone, entityDescriptorData, responseQueue);
                        }
                        else if (entityDescriptorData.State == EntityStates.Deleted)
                        {
                            requests.Add(this.CreateDeleteRequest(entityDescriptorData));
                            SetExpectedIfMatchHeader(requests.Last(), entityDescriptorData.ETag);
                            SetUnexpectedPreferHeader(requests.Last());
                            SetExpectedXHTTPMethodHeader(requests.Last(), context.UsePostTunneling);
                            SetExpectedDataServiceVersion(requests.Last(), DataServiceProtocolVersion.V4);

                            this.ApplyNextResponseHeadersAndPayload(contextDataClone, entityDescriptorData, responseQueue);
                        }
                    }
                }

                var streamDescriptorData = descriptorData as StreamDescriptorData;
                if (streamDescriptorData != null)
                {
                    if (streamDescriptorData.State == EntityStates.Modified)
                    {
                        requests.Add(new HttpRequestData()
                        {
                            Verb = HttpVerb.Put, Uri = streamDescriptorData.EditLink
                        });
                        SetExpectedIfMatchHeader(requests.Last(), streamDescriptorData.ETag);
                        SetUnexpectedPreferHeader(requests.Last());
                        SetExpectedXHTTPMethodHeader(requests.Last(), context.UsePostTunneling);
                        SetExpectedDataServiceVersion(requests.Last(), DataServiceProtocolVersion.V4);

                        ExceptionUtilities.Assert(responseQueue.Count > 0, "Stream operation did not have a response");
                        var response = responseQueue.Dequeue();
                        streamDescriptorData.UpdateFromHeaders(response.Headers);
                    }
                }
            }

            requests.ForEach(r => SetExpectedMaxDataServiceVersion(r, context));

            ExceptionUtilities.Assert(responseQueue.Count == 0, "Not all responses were applied");
            ExceptionUtilities.Assert(requests.All(r => headersThatWillBeGenerated.All(h => r.Headers.ContainsKey(h))), "Not all requests had all expected headers");

            return(requests);
        }
 private static void SetExpectedPreferHeader(HttpRequestData request, DSClient.DataServiceContext contextData)
 {
     SetExpectedPreferHeader(request, contextData.AddAndUpdateResponsePreference.ToTestEnum());
 }
        private static void SetExpectedMaxDataServiceVersion(HttpRequestData request, DSClient.DataServiceContext context)
        {
            DataServiceProtocolVersion maxDataServiceVersion = context.MaxProtocolVersion.ToTestEnum();

            SetExpectedMaxDataServiceVersion(request, maxDataServiceVersion);
        }
Beispiel #15
0
        /// <summary>
        /// Executes SaveChanges on the specified context and with specified options and verifies the results.
        /// </summary>
        /// <param name="verifier">The verifier to use for verification.</param>
        /// <param name="contextData">The data for the context.</param>
        /// <param name="context">The context to verify SaveChanges on.</param>
        /// <param name="options">The options for saving changes.</param>
        /// <returns>The response from SaveChanges</returns>
        public static DSClient.DataServiceResponse VerifySaveChanges(this ISaveChangesVerifier verifier, DataServiceContextData contextData, DSClient.DataServiceContext context, SaveChangesOptions? options)
        {
#if SILVERLIGHT
            throw new TaupoNotSupportedException("Not supported in Silverlight");
#else
            ExceptionUtilities.CheckArgumentNotNull(verifier, "verifier");
            ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");

            DSClient.DataServiceResponse response = null;
            SyncHelpers.ExecuteActionAndWait(c1 => verifier.VerifySaveChanges(c1, contextData, context, options, (c2, r) => { response = r; c2.Continue(); }));
            return response;
#endif
        }
Beispiel #16
0
        /// <summary>
        /// Executes SaveChanges on the specified context and with the default options and verifies the results.
        /// </summary>
        /// <param name="verifier">The verifier to use for verification.</param>
        /// <param name="contextData">The data for the context.</param>
        /// <param name="context">The context to verify SaveChanges on.</param>
        /// <returns>The response from SaveChanges</returns>
        public static DSClient.DataServiceResponse VerifySaveChanges(this ISaveChangesVerifier verifier, DataServiceContextData contextData, DSClient.DataServiceContext context)
        {
            ExceptionUtilities.CheckArgumentNotNull(verifier, "verifier");
            ExceptionUtilities.CheckArgumentNotNull(contextData, "contextData");
            ExceptionUtilities.CheckArgumentNotNull(context, "context");

            return(verifier.VerifySaveChanges(contextData, context, null));
        }
        private void TrackDataServiceContext(DataServiceContextData data, DSClient.DataServiceContext context, MethodBase methodInfo, object returnValue, object[] parameterValues)
        {
            MethodInfo methodToTrack = methodInfo as MethodInfo;

            ExceptionUtilities.CheckObjectNotNull(methodToTrack, "Unhandled type for method info '{0}': {1}.", methodInfo.Name, methodInfo);

            if (methodToTrack.Name == "AttachTo")
            {
                string entitySetName = (string)parameterValues[0];
                object entity        = parameterValues[1];
                string etag          = parameterValues.Length == 3 ? (string)parameterValues[2] : null;

                ExceptionUtilities.CheckObjectNotNull(this.EntityDescriptorCalculator, "Entity descriptor value calculator dependency has not been set.");

                var identity = this.EntityDescriptorCalculator.CalculateEntityId(data, entitySetName, entity);
                var editLink = this.EntityDescriptorCalculator.CalculateEditLink(data, entitySetName, entity);

                data.TrackAttachTo(entitySetName, entity, identity, etag, editLink);
                return;
            }
            else if (methodToTrack.Name == "SaveChanges" || methodToTrack.Name == "EndSaveChanges")
            {
                ExceptionUtilities.CheckObjectNotNull(this.DescriptorDataChangeTracker, "Cannot track SaveChanges without descriptor change tracker");
                ExceptionUtilities.Assert(!this.DescriptorDataChangeTracker.ApplyUpdatesImmediately, "ApplyUpdatesImmediately unexpectedly true after SaveChanges call");
                this.DescriptorDataChangeTracker.ApplyPendingUpdates();
                this.DescriptorDataChangeTracker.ApplyUpdatesImmediately = true;

                SaveChangesInfo info;
                ExceptionUtilities.Assert(this.saveChangesInfos.TryGetValue(context, out info), "Could not find save changes info");
                var response           = (DSClient.DataServiceResponse)returnValue;
                var operationResponses = response.ToList();

                data.TrackSaveChanges(info.Options, response, operationResponses, this.DescriptorDataChangeTracker);
                this.DescriptorDataChangeTracker.ApplyPendingUpdates();
                return;
            }
            else if (methodToTrack.Name == "Detach")
            {
                data.TrackDetach(parameterValues[0]);
            }
            else if (methodToTrack.Name == "DetachLink")
            {
                data.TrackDetachLink(parameterValues[0], (string)parameterValues[1], parameterValues[2]);
            }
            else if (methodToTrack.Name == "SetSaveStream")
            {
                this.TrackSetSaveStream(data, methodToTrack, parameterValues);
            }
            else if (methodToTrack.Name == "GetReadStream" || methodToTrack.Name == "EndGetReadStream")
            {
                object entity = null;
                string name   = null;
                if (methodToTrack.Name == "GetReadStream")
                {
                    entity = parameterValues[0];

                    // if the second arg is not present or not a string, then it is an MR, in which case null is correct
                    if (parameterValues.Length > 2)
                    {
                        name = parameterValues[1] as string;
                    }
                }
                else
                {
                    GetReadStreamInfo info;
                    ExceptionUtilities.Assert(this.getReadStreamInfos.TryGetValue(context, out info), "Get read stream info missing");
                    entity = info.Entity;
                    name   = info.StreamName;
                }

                var response = (DSClient.DataServiceStreamResponse)returnValue;
                data.TrackGetReadStream(entity, name, response.ContentType, response.Headers);
            }
            else if (methodToTrack.Name.StartsWith("set_", StringComparison.Ordinal))
            {
                string propertyName = methodToTrack.Name.Substring(4);
                var    testProperty = typeof(DataServiceContextData).GetProperty(propertyName, true, false);
                if (testProperty != null)
                {
                    testProperty.SetValue(data, parameterValues[0], null);
                }
            }
            else
            {
                MethodInfo trackerMethod = this.GetTrackingMethod(methodToTrack);

                if (trackerMethod != null)
                {
                    object[] trakerParameters = new object[trackerMethod.GetParameters().Length];
                    trakerParameters[0] = data;
                    for (int i = 0; i < parameterValues.Length; i++)
                    {
                        trakerParameters[i + 1] = parameterValues[i];
                    }

                    trackerMethod.Invoke(null, trakerParameters);
                }
            }
        }
        /// <summary>
        /// Creates the data service context data from data service context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="maxProtocolVersion">The max protocol version.</param>
        /// <returns>DataServiceContextData based on context</returns>
        public static DataServiceContextData CreateDataServiceContextDataFromDataServiceContext(DSClient.DataServiceContext context, DataServiceProtocolVersion maxProtocolVersion)
        {
            var contextData = new DataServiceContextData(context.GetType(), maxProtocolVersion);

            // set all the properties on the context data to the values from the context
            foreach (var productProperty in typeof(DSClient.DataServiceContext).GetProperties(true, false))
            {
                var testProperty = typeof(DataServiceContextData).GetProperty(productProperty.Name, true, false);
                if (testProperty != null && testProperty.PropertyType.IsAssignableFrom(productProperty.PropertyType))
                {
                    var value = productProperty.GetValue(context, null);
                    testProperty.SetValue(contextData, value, null);
                }
            }

            return contextData;
        }