Beispiel #1
0
        /// <summary>
        /// Submits the specified <see cref="EntityChangeSet"/> to the DomainService asynchronously.
        /// </summary>
        /// <param name="changeSet">The <see cref="EntityChangeSet"/> to submit to the DomainService.</param>
        /// <param name="cancellationToken"><see cref="CancellationToken"/> which may be used to request cancellation</param>
        /// <returns>The results returned by the submit request.</returns>
        public Task <SubmitCompletedResult> SubmitAsync(EntityChangeSet changeSet, CancellationToken cancellationToken)
        {
            if (changeSet == null)
            {
                throw new ArgumentNullException(nameof(changeSet));
            }

            if (changeSet.IsEmpty)
            {
                throw new InvalidOperationException(OpenRiaServices.DomainServices.Client.Resource.DomainClient_EmptyChangeSet);
            }

            // call the actual implementation
            var submitTask = SubmitAsyncCore(changeSet, cancellationToken);

            return(submitTask.ContinueWith(res =>
            {
                var submitResults = res.GetAwaiter().GetResult();

                // correlate the operation results back to their actual client entity references
                Dictionary <int, Entity> submittedEntities = submitResults.ChangeSet.GetChangeSetEntries().ToDictionary(p => p.Id, p => p.Entity);
                foreach (ChangeSetEntry op in submitResults.Results)
                {
                    op.ClientEntity = submittedEntities[op.Id];
                }

                return submitResults;
            }
                                           , CancellationToken.None
                                           , TaskContinuationOptions.NotOnCanceled
                                           , TaskScheduler.Default));
        }
Beispiel #2
0
        /// <summary>
        /// Submit the specified <see cref="EntityChangeSet"/> to the DomainService, with the results of the operation
        /// being returned on the SubmitCompleted event args.
        /// </summary>
        /// <param name="changeSet">The changeset to submit. If the changeset is empty, an <see cref="InvalidOperationException"/> will
        /// be thrown.</param>
        /// <param name="cancellationToken"><see cref="CancellationToken"/> to be used for requesting cancellation</param>
        /// <returns>The results returned by the submit request.</returns>
        /// <exception cref="InvalidOperationException">The changeset is empty.</exception>
        protected override Task <SubmitCompletedResult> SubmitAsyncCore(EntityChangeSet changeSet, CancellationToken cancellationToken)
        {
            IEnumerable <ChangeSetEntry> submitOperations = changeSet.GetChangeSetEntries();

            TContract channel = this.ChannelFactory.CreateChannel();

            return(CallServiceOperation <SubmitCompletedResult>(channel,
                                                                "SubmitChanges",
                                                                new Dictionary <string, object>()
            {
                { "changeSet", submitOperations }
            },
                                                                (state, asyncResult) =>
            {
                try
                {
                    var returnValue = (IEnumerable <ChangeSetEntry>)EndServiceOperationCall(state, asyncResult);
                    return new SubmitCompletedResult(changeSet, returnValue ?? Enumerable.Empty <ChangeSetEntry>());
                }
                catch (FaultException <DomainServiceFault> fe)
                {
                    throw WebDomainClient <TContract> .GetExceptionFromServiceFault(fe.Detail);
                }
            }, cancellationToken));
        }
        /// <summary>
        /// Gets the results of a submit.
        /// </summary>
        /// <param name="asyncResult">An asynchronous result that identifies a submit.</param>
        /// <returns>The results returned by the submit.</returns>
        protected sealed override SubmitCompletedResult EndSubmitCore(IAsyncResult asyncResult)
        {
            WebDomainClientAsyncResult <TContract> wcfAsyncResult = this.EndAsyncResult(asyncResult, AsyncOperationType.Submit, /* cancel */ false);
            MethodInfo      endSubmitMethod = wcfAsyncResult.EndOperationMethod;
            EntityChangeSet changeSet       = wcfAsyncResult.EntityChangeSet;

            IEnumerable <ChangeSetEntry> returnValue;

            try
            {
                try
                {
                    returnValue = (IEnumerable <ChangeSetEntry>)endSubmitMethod.Invoke(wcfAsyncResult.Channel, new object[] { wcfAsyncResult.InnerAsyncResult });
                }
                catch (TargetInvocationException tie)
                {
                    if (tie.InnerException != null)
                    {
                        throw tie.InnerException;
                    }

                    throw;
                }
                finally
                {
                    ((IChannel)wcfAsyncResult.Channel).Close();
                }
            }
            catch (FaultException <DomainServiceFault> fe)
            {
                throw WebDomainClient <TContract> .GetExceptionFromServiceFault(fe.Detail);
            }

            return(new SubmitCompletedResult(changeSet, returnValue ?? Enumerable.Empty <ChangeSetEntry>()));
        }
Beispiel #4
0
        /// <summary>
        /// Returns an <see cref="EntityChangeSet"/> containing the current set of pending changes
        /// </summary>
        /// <returns>The current set of pending changes</returns>
        public EntityChangeSet GetChanges()
        {
            List <Entity> addedEntities    = new List <Entity>();
            List <Entity> modifiedEntities = new List <Entity>();
            List <Entity> removedEntities  = new List <Entity>();

            foreach (KeyValuePair <Type, EntitySet> entitySetItem in this._entitySets)
            {
                EntitySet set = entitySetItem.Value;

                foreach (Entity entity in set.InterestingEntities)
                {
                    if (entity.EntityState == EntityState.New)
                    {
                        addedEntities.Add(entity);
                    }
                    else if (entity.EntityState == EntityState.Modified)
                    {
                        modifiedEntities.Add(entity);
                    }
                    else if (entity.EntityState == EntityState.Deleted)
                    {
                        removedEntities.Add(entity);
                    }
                }
            }

            EntityChangeSet changeSet = new EntityChangeSet(addedEntities.AsReadOnly(), modifiedEntities.AsReadOnly(), removedEntities.AsReadOnly());

            Debug.Assert(this.HasChanges == !changeSet.IsEmpty, "Invariant : these states should be in sync");
            return(changeSet);
        }
        /// <summary>
        /// Submits the specified <see cref="EntityChangeSet"/> to the DomainService asynchronously.
        /// </summary>
        /// <param name="changeSet">The <see cref="EntityChangeSet"/> to submit to the DomainService.</param>
        /// <param name="callback">The callback to invoke when the submit has been executed.</param>
        /// <param name="userState">Optional user state associated with this operation.</param>
        /// <returns>An asynchronous result that identifies this submit request.</returns>
        public IAsyncResult BeginSubmit(EntityChangeSet changeSet, AsyncCallback callback, object userState)
        {
            if (callback == null)
            {
                throw new ArgumentNullException("callback");
            }

            if (changeSet == null)
            {
                throw new ArgumentNullException("changeSet");
            }

            if (changeSet.IsEmpty)
            {
                throw new InvalidOperationException(OpenRiaServices.DomainServices.Client.Resource.DomainClient_EmptyChangeSet);
            }

            DomainClientAsyncResult domainClientResult = DomainClientAsyncResult.CreateSubmitResult(this, changeSet, callback, userState);

            // call the actual implementation asynchronously
            domainClientResult.InnerAsyncResult = this.BeginSubmitCore(
                changeSet,
                delegate(IAsyncResult result)
            {
                DomainClientAsyncResult clientResult = (DomainClientAsyncResult)result.AsyncState;
                clientResult.InnerAsyncResult        = result;
                clientResult.Complete();
            },
                domainClientResult);

            return(domainClientResult);
        }
 /// <summary>
 /// Private constructor used by all public constructors.
 /// </summary>
 /// <param name="changeSet">the changeset being submitted</param>
 /// <param name="message">The localized error message</param>
 /// <param name="innerException">Optional inner exception.</param>
 /// <param name="status">status of the exception</param>
 /// <param name="errorCode">custom error code</param>
 /// <param name="stackTrace">stack trace of the exception</param>
 private SubmitOperationException(EntityChangeSet changeSet, string message, Exception innerException, OperationErrorStatus status, int errorCode, string stackTrace)
     : base(message, innerException, status, errorCode, stackTrace, GetValidationResults(changeSet))
 {
     _changeSet       = changeSet;
     _entitiesInError = new ReadOnlyCollection <Entity>(changeSet
                                                        .Where(p => p.EntityConflict != null || p.HasValidationErrors)
                                                        .ToList());
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="SubmitOperation"/> class.
 /// </summary>
 /// <param name="changeSet">The changeset being submitted.</param>
 /// <param name="completeAction">Optional action to invoke when the operation completes.</param>
 /// <param name="userState">Optional user state to associate with the operation.</param>
 /// <param name="supportCancellation"><c>true</c> to enable <see cref="OperationBase.CancellationToken"/> to be cancelled when <see cref="OperationBase.Cancel"/> is called</param>
 internal SubmitOperation(EntityChangeSet changeSet,
                          Action <SubmitOperation> completeAction, object userState,
                          bool supportCancellation)
     : base(userState, supportCancellation)
 {
     if (changeSet == null)
     {
         throw new ArgumentNullException(nameof(changeSet));
     }
     this._completeAction = completeAction;
     this._changeSet      = changeSet;
 }
Beispiel #8
0
        /// <summary>
        /// Initializes a new <see cref="DomainClientAsyncResult"/> instance used for Submit operations.
        /// </summary>
        /// <param name="domainClient">The associated <see cref="DomainClient"/>.</param>
        /// <param name="entityChangeSet">The Submit operation <see cref="EntityChangeSet"/>.</param>
        /// <param name="callback">Optional <see cref="AsyncCallback"/> to invoke upon completion.</param>
        /// <param name="asyncState">Optional user state information that will be passed to the <paramref name="callback"/>.</param>
        /// <exception cref="ArgumentNullException">if <paramref name="domainClient"/> is null.</exception>
        protected DomainClientAsyncResult(DomainClient domainClient, EntityChangeSet entityChangeSet, AsyncCallback callback, object asyncState)
            : base(callback, asyncState)
        {
            if (domainClient == null)
            {
                throw new ArgumentNullException("domainClient");
            }

            this._asyncOperationType = AsyncOperationType.Submit;
            this._domainClient       = domainClient;
            this._entityChangeSet    = entityChangeSet;
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="SubmitOperation"/> class.
 /// </summary>
 /// <param name="changeSet">The changeset being submitted.</param>
 /// <param name="completeAction">Optional action to invoke when the operation completes.</param>
 /// <param name="userState">Optional user state to associate with the operation.</param>
 /// <param name="cancelAction">Optional action to invoke when the operation is canceled. If null, cancellation will not be supported.</param>
 internal SubmitOperation(EntityChangeSet changeSet,
                          Action <SubmitOperation> completeAction, object userState,
                          Action <SubmitOperation> cancelAction)
     : base(userState)
 {
     if (changeSet == null)
     {
         throw new ArgumentNullException("changeSet");
     }
     this._cancelAction   = cancelAction;
     this._completeAction = completeAction;
     this._changeSet      = changeSet;
 }
Beispiel #10
0
        /// <summary>
        /// Initializes a new instance of the SubmitCompletedResult class
        /// </summary>
        /// <param name="changeSet">The changeset that was submitted.</param>
        /// <param name="operationResults">The <see cref="ChangeSetEntry"/> results sent back from the
        /// DomainService for the submit operation.</param>
        public SubmitCompletedResult(EntityChangeSet changeSet, IEnumerable <ChangeSetEntry> operationResults)
        {
            if (changeSet == null)
            {
                throw new ArgumentNullException("changeSet");
            }
            if (operationResults == null)
            {
                throw new ArgumentNullException("operationResults");
            }

            this._changeSet        = changeSet;
            this._operationResults = new ReadOnlyCollection <ChangeSetEntry>(operationResults.ToList());
        }
        /// <summary>
        /// Builds an operation list for the specified <see cref="EntityChangeSet"/>.
        /// </summary>
        /// <param name="changeSet">The <see cref="EntityChangeSet"/>.</param>
        /// <returns>The list of <see cref="ChangeSetEntry"/> for the specified <see cref="EntityChangeSet"/>.</returns>
        public static List <ChangeSetEntry> Build(EntityChangeSet changeSet)
        {
            CheckForInvalidUpdates(changeSet);

            // translate to an operation list
            List <ChangeSetEntry> operations = BuildOperations(changeSet);

            // recursively visit all composition relationships in the
            // changeset and add operations for unmodified children.
            UnmodifiedOperationAdder.Add(operations);

            // set the association maps for all operations in the changeset
            AssociationMapBuilder.Build(operations);

            return(operations);
        }
        /// <summary>
        /// Submit the specified <see cref="EntityChangeSet"/> to the DomainService, with the results of the operation
        /// being returned on the SubmitCompleted event args.
        /// </summary>
        /// <param name="changeSet">The changeset to submit. If the changeset is empty, an <see cref="InvalidOperationException"/> will
        /// be thrown.</param>
        /// <param name="callback">The callback to invoke when the submit has been executed.</param>
        /// <param name="userState">Optional state that will flow through to the SubmitCompleted event</param>
        /// <returns>An asynchronous result that identifies this submit.</returns>
        /// <exception cref="InvalidOperationException">The changeset is empty.</exception>
        /// <exception cref="InvalidOperationException">The specified query does not exist.</exception>
        protected sealed override IAsyncResult BeginSubmitCore(EntityChangeSet changeSet, AsyncCallback callback, object userState)
        {
            MethodInfo beginSubmitMethod = WebDomainClient <TContract> .ResolveBeginMethod("SubmitChanges");

            MethodInfo endSubmitMethod = WebDomainClient <TContract> .ResolveEndMethod("SubmitChanges");

            IEnumerable <ChangeSetEntry> submitOperations = changeSet.GetChangeSetEntries();

            TContract channel = this.ChannelFactory.CreateChannel();
            WebDomainClientAsyncResult <TContract> wcfAsyncResult = WebDomainClientAsyncResult <TContract> .CreateSubmitResult(this, channel, endSubmitMethod, changeSet, submitOperations.ToList(), callback, userState);

            object[] parameters =
            {
                submitOperations,
                new AsyncCallback(delegate(IAsyncResult asyncResponseResult)
                {
                    wcfAsyncResult.InnerAsyncResult = asyncResponseResult;
                    wcfAsyncResult.Complete();
                }),
                userState
            };

            IAsyncResult asyncResult;

            try
            {
                asyncResult = (IAsyncResult)beginSubmitMethod.Invoke(channel, parameters);
            }
            catch (TargetInvocationException tie)
            {
                if (tie.InnerException != null)
                {
                    throw tie.InnerException;
                }

                throw;
            }

            if (!asyncResult.CompletedSynchronously)
            {
                wcfAsyncResult.InnerAsyncResult = asyncResult;
            }
            return(wcfAsyncResult);
        }
        /// <summary>
        /// Verify that all update operations in the specified <see cref="EntityChangeSet"/> are permitted.
        /// </summary>
        /// <param name="changeSet">The <see cref="EntityChangeSet"/> to check.</param>
        internal static void CheckForInvalidUpdates(EntityChangeSet changeSet)
        {
            AssociationUpdateChecker associationChecker = new AssociationUpdateChecker();

            foreach (Entity entity in changeSet)
            {
                if (entity.EntityState == EntityState.Modified)
                {
                    foreach (MetaMember member in entity.ModifiedProperties)
                    {
                        if (member.IsKeyMember)
                        {
                            throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.Entity_KeyMembersCannotBeChanged, member.Name, entity.GetType().Name));
                        }
                    }
                }

                // search associated entities for any invalid changes
                associationChecker.Visit(entity);
            }
        }
        /// <summary>
        /// Builds the list of submit operations from the current <see cref="EntityChangeSet"/>.
        /// </summary>
        /// <param name="changeSet">The <see cref="EntityChangeSet"/> to process.</param>
        /// <returns>The list of <see cref="ChangeSetEntry"/> for the specified <see cref="EntityChangeSet"/>.</returns>
        private static List <ChangeSetEntry> BuildOperations(EntityChangeSet changeSet)
        {
            List <ChangeSetEntry> operations = new List <ChangeSetEntry>();
            int clientID = 0;
            EntityOperationType operationType = EntityOperationType.None;

            foreach (Entity entity in changeSet)
            {
                switch (entity.EntityState)
                {
                case EntityState.New:
                    operationType = EntityOperationType.Insert;
                    break;

                case EntityState.Modified:
                    operationType = EntityOperationType.Update;
                    break;

                case EntityState.Deleted:
                    operationType = EntityOperationType.Delete;
                    break;

                default:
                    continue;
                }

                // create the operation and apply any original values
                ChangeSetEntry changeSetEntry = new ChangeSetEntry(entity, clientID++, operationType);

                if (entity.OriginalValues != null)
                {
                    if (entity.MetaType.ShouldRoundtripOriginal && entity.OriginalValues != null)
                    {
                        changeSetEntry.OriginalEntity = GetRoundtripEntity(entity);
                    }
                    else
                    {
                        // In cases where the entity is modified but we're not sending
                        // an original we need to flag the entity as having changes.
                        // For example, this happens in Timestamp scenarios.
                        changeSetEntry.HasMemberChanges = true;
                    }
                }

                // add any custom method invocations
                var entityActions = (ICollection <EntityAction>)entity.EntityActions;
                foreach (EntityAction customInvokation in entityActions)
                {
                    if (string.IsNullOrEmpty(customInvokation.Name))
                    {
                        throw new ArgumentException(Resource.DomainClient_InvocationNameCannotBeNullOrEmpty);
                    }

                    if (changeSetEntry.EntityActions == null)
                    {
                        changeSetEntry.EntityActions = new List <Serialization.KeyValue <string, object[]> >();
                    }
                    changeSetEntry.EntityActions.Add(
                        new Serialization.KeyValue <string, object[]>(customInvokation.Name, customInvokation.Parameters.ToArray()));
                }

                operations.Add(changeSetEntry);
            }

            return(operations);
        }
Beispiel #15
0
 /// <summary>
 /// Create a IEnumerable which iterates the changeset and returns all validation errors
 /// </summary>
 /// <param name="changeSet">ChangeSet to read validation errors from</param>
 /// <returns></returns>
 private static IEnumerable <ValidationResult> GetValidationResults(EntityChangeSet changeSet)
 {
     return(changeSet.Where(p => p.EntityConflict != null || p.HasValidationErrors)
            .SelectMany(p => p.ValidationErrors));
 }
Beispiel #16
0
 /// <summary>
 /// Private constructor used by all public constructors.
 /// </summary>
 /// <param name="changeSet">the changeset being submitted</param>
 /// <param name="message">The localized error message</param>
 /// <param name="innerException">Optional inner exception.</param>
 /// <param name="status">status of the exception</param>
 /// <param name="errorCode">custom error code</param>
 /// <param name="stackTrace">stack trace of the exception</param>
 private SubmitOperationException(EntityChangeSet changeSet, string message, Exception innerException, OperationErrorStatus status, int errorCode, string stackTrace)
     : base(message, innerException, status, errorCode, stackTrace, GetValidationResults(changeSet))
 {
     _changeSet = changeSet;
 }
Beispiel #17
0
 /// <summary>
 /// Internal "copy" constructor.
 /// </summary>
 /// <param name="changeSet">the changeset being submitted</param>
 /// <param name="message">The new error message to use</param>
 /// <param name="exception">The exception to copy</param>
 internal SubmitOperationException(EntityChangeSet changeSet, string message, DomainOperationException exception)
     : this(changeSet, message, exception.InnerException, exception.Status, exception.ErrorCode, exception.StackTrace)
 {
     _changeSet = changeSet;
 }
 /// <summary>
 /// Creates a new <see cref="WebDomainClientAsyncResult&lt;TContract&gt;"/> used for Submit operations.
 /// </summary>
 /// <param name="domainClient">The <see cref="WebDomainClient&lt;TContract&gt;"/> associated with this result.</param>
 /// <param name="channel">The channel used to communicate with the server.</param>
 /// <param name="endOperationMethod">The method that completes an asynchronous operation.</param>
 /// <param name="entityChangeSet">The Submit operation <see cref="EntityChangeSet"/>.</param>
 /// <param name="changeSetEntries">The collection of <see cref="ChangeSetEntry"/>s to submit.</param>
 /// <param name="callback">The <see cref="AsyncCallback"/> to invoke upon completion.</param>
 /// <param name="asyncState">Optional user state information that will be passed to the <paramref name="callback"/>.</param>
 /// <returns>A <see cref="WebDomainClientAsyncResult&lt;TContract&gt;"/> used for Submit operations</returns>
 public static WebDomainClientAsyncResult <TContract> CreateSubmitResult(WebDomainClient <TContract> domainClient, TContract channel, MethodInfo endOperationMethod, EntityChangeSet entityChangeSet, IEnumerable <ChangeSetEntry> changeSetEntries, AsyncCallback callback, object asyncState)
 {
     return(new WebDomainClientAsyncResult <TContract>(domainClient, channel, endOperationMethod, entityChangeSet, changeSetEntries, callback, asyncState));
 }
Beispiel #19
0
 /// <summary>
 /// Constructor that accepts a localized exception message and status
 /// </summary>
 /// <param name="changeSet">the changeset being submitted</param>
 /// <param name="message">The localized exception message</param>
 /// <param name="status">The status of the exception</param>
 public SubmitOperationException(EntityChangeSet changeSet, string message, OperationErrorStatus status)
     : this(changeSet, message, /*innerException*/ null, status, /*errorCode*/ 0, /*stackTrace*/ null)
 {
     _changeSet = changeSet;
 }
Beispiel #20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SubmitResult"/> class.
 /// </summary>
 /// <param name="changeSet">The changeset which was submitted.</param>
 public SubmitResult(EntityChangeSet changeSet)
 {
     _changeSet = changeSet;
 }
Beispiel #21
0
 /// <summary>
 /// Method called by the framework to asynchronously process the specified <see cref="EntityChangeSet"/>.
 /// Overrides should not call the base method.
 /// </summary>
 /// <param name="changeSet">The <see cref="EntityChangeSet"/> to submit to the DomainService.</param>
 /// <param name="callback">The callback to invoke when the submit has been executed.</param>
 /// <param name="userState">Optional user state associated with this operation.</param>
 /// <returns>An asynchronous result that identifies this submit request.</returns>
 protected virtual IAsyncResult BeginSubmitCore(EntityChangeSet changeSet, AsyncCallback callback, object userState)
 {
     throw new NotSupportedException();
 }
Beispiel #22
0
 /// <summary>
 /// Method called by the framework to asynchronously process the specified <see cref="EntityChangeSet"/>.
 /// Overrides should not call the base method.
 /// </summary>
 /// <param name="changeSet">The <see cref="EntityChangeSet"/> to submit to the DomainService.</param>
 /// <param name="cancellationToken"><see cref="CancellationToken"/> which may be used to request cancellation</param>
 /// <returns>The results returned by the submit request.</returns>
 protected virtual Task <SubmitCompletedResult> SubmitAsyncCore(EntityChangeSet changeSet, CancellationToken cancellationToken)
 {
     throw new NotSupportedException();
 }
Beispiel #23
0
 /// <summary>
 /// Creates a new <see cref="DomainClientAsyncResult"/> used for Submit operations.
 /// </summary>
 /// <param name="domainClient">The associated <see cref="DomainClient"/>.</param>
 /// <param name="entityChangeSet">The Submit operation <see cref="EntityChangeSet"/>.</param>
 /// <param name="callback">The <see cref="AsyncCallback"/> to invoke upon completion.</param>
 /// <param name="asyncState">Optional user state information that will be passed to the <paramref name="callback"/>.</param>
 /// <returns>A <see cref="DomainClientAsyncResult"/> used for Submit operations</returns>
 public static DomainClientAsyncResult CreateSubmitResult(DomainClient domainClient, EntityChangeSet entityChangeSet, AsyncCallback callback, object asyncState)
 {
     return(new DomainClientAsyncResult(domainClient, entityChangeSet, callback, asyncState));
 }
Beispiel #24
0
 /// <summary>
 /// Constructor that accepts a localized exception message and status
 /// </summary>
 /// <param name="changeSet">the changeset being submitted</param>
 /// <param name="message">The localized exception message</param>
 /// <param name="innerException">inner exception.</param>
 public SubmitOperationException(EntityChangeSet changeSet, string message, Exception innerException)
     : this(changeSet, message, innerException, /*status*/ OperationErrorStatus.ServerError, /*errorCode*/ 0, /*stackTrace*/ null)
 {
     _changeSet = changeSet;
 }
        /// <summary>
        /// Initializes a new <see cref="WebDomainClientAsyncResult&lt;TContract&gt;"/> instance used for Submit operations.
        /// </summary>
        /// <param name="domainClient">The <see cref="WebDomainClient&lt;TContract&gt;"/> associated with this result.</param>
        /// <param name="channel">The channel used to communicate with the server.</param>
        /// <param name="endOperationMethod">The method that completes an asynchronous operation.</param>
        /// <param name="entityChangeSet">The Submit operation <see cref="EntityChangeSet"/>.</param>
        /// <param name="changeSetEntries">The collection of <see cref="ChangeSetEntry"/>s to submit.</param>
        /// <param name="callback">Optional <see cref="AsyncCallback"/> to invoke upon completion.</param>
        /// <param name="asyncState">Optional user state information that will be passed to the <paramref name="callback"/>.</param>
        /// <exception cref="ArgumentNullException">if <paramref name="domainClient"/> is null.</exception>
        /// <exception cref="ArgumentNullException">if <paramref name="endOperationMethod"/> is null.</exception>
        private WebDomainClientAsyncResult(WebDomainClient <TContract> domainClient, TContract channel, MethodInfo endOperationMethod, EntityChangeSet entityChangeSet, IEnumerable <ChangeSetEntry> changeSetEntries, AsyncCallback callback, object asyncState)
            : base(domainClient, entityChangeSet, callback, asyncState)
        {
            if (channel == null)
            {
                throw new ArgumentNullException("channel");
            }

            if (endOperationMethod == null)
            {
                throw new ArgumentNullException("endOperationMethod");
            }

            this._endOperationMethod = endOperationMethod;
            this._channel            = channel;
            this._changeSetEntries   = changeSetEntries;
        }