/// <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); } }
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); }
/// <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); }
/// <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 }
/// <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; }