public override object EndExecute(IAsyncResult asyncResult)
        {
            TaskWrapperAsyncResult wrapperResult = (TaskWrapperAsyncResult)asyncResult;

            // Throw an exception with the correct call stack
            try
            {
                wrapperResult.Task.ThrowIfFaulted();
            }
            finally
            {
                if (wrapperResult.CleanupThunk != null)
                {
                    wrapperResult.CleanupThunk();
                }
            }

            // Extract the result of the task if there is a result
            return(_taskValueExtractors.GetOrAdd(TaskMethodInfo.ReturnType, CreateTaskValueExtractor)(wrapperResult.Task));
        }
        public override IAsyncResult BeginExecute(ControllerContext controllerContext, IDictionary <string, object> parameters, AsyncCallback callback, object state)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (parameters == null)
            {
                throw new ArgumentNullException("parameters");
            }

            ParameterInfo[] parameterInfos     = TaskMethodInfo.GetParameters();
            var             rawParameterValues = from parameterInfo in parameterInfos
                                                 select ExtractParameterFromDictionary(parameterInfo, parameters, TaskMethodInfo);

            object[] parametersArray = rawParameterValues.ToArray();

            CancellationTokenSource tokenSource = null;
            bool  disposedTimer              = false;
            Timer taskCancelledTimer         = null;
            bool  taskCancelledTimerRequired = false;

            int timeout = GetAsyncManager(controllerContext.Controller).Timeout;

            for (int i = 0; i < parametersArray.Length; i++)
            {
                if (default(CancellationToken).Equals(parametersArray[i]))
                {
                    tokenSource        = new CancellationTokenSource();
                    parametersArray[i] = tokenSource.Token;

                    // If there is a timeout we will create a timer to cancel the task when the
                    // timeout expires.
                    taskCancelledTimerRequired = timeout > Timeout.Infinite;
                    break;
                }
            }

            ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(TaskMethodInfo);

            if (taskCancelledTimerRequired)
            {
                taskCancelledTimer = new Timer(_ =>
                {
                    lock (tokenSource)
                    {
                        if (!disposedTimer)
                        {
                            tokenSource.Cancel();
                        }
                    }
                }, state: null, dueTime: timeout, period: Timeout.Infinite);
            }

            Task   taskUser            = dispatcher.Execute(controllerContext.Controller, parametersArray) as Task;
            Action cleanupAtEndExecute = () =>
            {
                // Cleanup code that's run in EndExecute, after we've waited on the task value.

                if (taskCancelledTimer != null)
                {
                    // Timer callback may still fire after Dispose is called.
                    taskCancelledTimer.Dispose();
                }

                if (tokenSource != null)
                {
                    lock (tokenSource)
                    {
                        disposedTimer = true;
                        tokenSource.Dispose();
                        if (tokenSource.IsCancellationRequested)
                        {
                            // Give Timeout exceptions higher priority over other exceptions, mainly OperationCancelled exceptions
                            // that were signaled with out timeout token.
                            throw new TimeoutException();
                        }
                    }
                }
            };

            TaskWrapperAsyncResult result = new TaskWrapperAsyncResult(taskUser, state, cleanupAtEndExecute);

            // if user supplied a callback, invoke that when their task has finished running.
            if (callback != null)
            {
                if (taskUser.IsCompleted)
                {
                    // If the underlying task is already finished, from our caller's perspective this is just
                    // a synchronous completion.
                    result.CompletedSynchronously = true;
                    callback(result);
                }
                else
                {
                    // If the underlying task isn't yet finished, from our caller's perspective this will be
                    // an asynchronous completion. We'll use ContinueWith instead of Finally for two reasons:
                    //
                    // - Finally propagates the antecedent Task's exception, which we don't need to do here.
                    //   Out caller will eventually call EndExecute, which correctly observes the
                    //   antecedent Task's exception anyway if it faulted.
                    //
                    // - Finally invokes the callback on the captured SynchronizationContext, which is
                    //   unnecessary when using APM (Begin / End). APM assumes that the callback is invoked
                    //   on an arbitrary ThreadPool thread with no SynchronizationContext set up, so
                    //   ContinueWith gets us closer to the desired semantic.
                    result.CompletedSynchronously = false;
                    taskUser.ContinueWith(_ =>
                    {
                        callback(result);
                    });
                }
            }

            return(result);
        }
        public override IAsyncResult BeginExecute(ControllerContext controllerContext, IDictionary<string, object> parameters, AsyncCallback callback, object state)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (parameters == null)
            {
                throw new ArgumentNullException("parameters");
            }

            ParameterInfo[] parameterInfos = TaskMethodInfo.GetParameters();
            var rawParameterValues = from parameterInfo in parameterInfos
                                     select ExtractParameterFromDictionary(parameterInfo, parameters, TaskMethodInfo);
            object[] parametersArray = rawParameterValues.ToArray();

            CancellationTokenSource tokenSource = null;
            bool disposedTimer = false;
            Timer taskCancelledTimer = null;
            bool taskCancelledTimerRequired = false;

            int timeout = GetAsyncManager(controllerContext.Controller).Timeout;

            for (int i = 0; i < parametersArray.Length; i++)
            {
                if (default(CancellationToken).Equals(parametersArray[i]))
                {
                    tokenSource = new CancellationTokenSource();
                    parametersArray[i] = tokenSource.Token;

                    // If there is a timeout we will create a timer to cancel the task when the
                    // timeout expires.
                    taskCancelledTimerRequired = timeout > Timeout.Infinite;
                    break;
                }
            }

            ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(TaskMethodInfo);

            if (taskCancelledTimerRequired)
            {
                taskCancelledTimer = new Timer(_ =>
                {
                    lock (tokenSource)
                    {
                        if (!disposedTimer)
                        {
                            tokenSource.Cancel();
                        }
                    }
                }, state: null, dueTime: timeout, period: Timeout.Infinite);
            }

            Task taskUser = dispatcher.Execute(controllerContext.Controller, parametersArray) as Task;
            Action cleanupAtEndExecute = () =>
            {
                // Cleanup code that's run in EndExecute, after we've waited on the task value. 

                if (taskCancelledTimer != null)
                {
                    // Timer callback may still fire after Dispose is called. 
                    taskCancelledTimer.Dispose();
                }

                if (tokenSource != null)
                {
                    lock (tokenSource)
                    {
                        disposedTimer = true;
                        tokenSource.Dispose();
                        if (tokenSource.IsCancellationRequested)
                        {
                            // Give Timeout exceptions higher priority over other exceptions, mainly OperationCancelled exceptions 
                            // that were signaled with out timeout token.                             
                            throw new TimeoutException();
                        }
                    }
                }
            };

            TaskWrapperAsyncResult result = new TaskWrapperAsyncResult(taskUser, state, cleanupAtEndExecute);

            // if user supplied a callback, invoke that when their task has finished running. 
            if (callback != null)
            {
                taskUser.Finally(() =>
                {
                    callback(result);
                });
            }

            return result;
        }
Exemplo n.º 4
0
        public override IAsyncResult BeginExecute(ControllerContext controllerContext, IDictionary <string, object> parameters, AsyncCallback callback, object state)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (parameters == null)
            {
                throw new ArgumentNullException("parameters");
            }

            ParameterInfo[] parameterInfos     = TaskMethodInfo.GetParameters();
            var             rawParameterValues = from parameterInfo in parameterInfos
                                                 select ExtractParameterFromDictionary(parameterInfo, parameters, TaskMethodInfo);

            object[] parametersArray = rawParameterValues.ToArray();

            CancellationTokenSource tokenSource = null;
            bool  disposedTimer              = false;
            Timer taskCancelledTimer         = null;
            bool  taskCancelledTimerRequired = false;

            int timeout = GetAsyncManager(controllerContext.Controller).Timeout;

            for (int i = 0; i < parametersArray.Length; i++)
            {
                if (default(CancellationToken).Equals(parametersArray[i]))
                {
                    tokenSource        = new CancellationTokenSource();
                    parametersArray[i] = tokenSource.Token;

                    // If there is a timeout we will create a timer to cancel the task when the
                    // timeout expires.
                    taskCancelledTimerRequired = timeout > Timeout.Infinite;
                    break;
                }
            }

            ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(TaskMethodInfo);

            if (taskCancelledTimerRequired)
            {
                taskCancelledTimer = new Timer(_ =>
                {
                    lock (tokenSource)
                    {
                        if (!disposedTimer)
                        {
                            tokenSource.Cancel();
                        }
                    }
                }, state: null, dueTime: timeout, period: Timeout.Infinite);
            }

            Task   taskUser            = dispatcher.Execute(controllerContext.Controller, parametersArray) as Task;
            Action cleanupAtEndExecute = () =>
            {
                // Cleanup code that's run in EndExecute, after we've waited on the task value.

                if (taskCancelledTimer != null)
                {
                    // Timer callback may still fire after Dispose is called.
                    taskCancelledTimer.Dispose();
                }

                if (tokenSource != null)
                {
                    lock (tokenSource)
                    {
                        disposedTimer = true;
                        tokenSource.Dispose();
                        if (tokenSource.IsCancellationRequested)
                        {
                            // Give Timeout exceptions higher priority over other exceptions, mainly OperationCancelled exceptions
                            // that were signaled with out timeout token.
                            throw new TimeoutException();
                        }
                    }
                }
            };

            TaskWrapperAsyncResult result = new TaskWrapperAsyncResult(taskUser, state, cleanupAtEndExecute);

            // if user supplied a callback, invoke that when their task has finished running.
            if (callback != null)
            {
                taskUser.Finally(() =>
                {
                    callback(result);
                });
            }

            return(result);
        }
        public override IAsyncResult BeginExecute(ControllerContext controllerContext, IDictionary<string, object> parameters, AsyncCallback callback, object state)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (parameters == null)
            {
                throw new ArgumentNullException("parameters");
            }

            ParameterInfo[] parameterInfos = TaskMethodInfo.GetParameters();
            var rawParameterValues = from parameterInfo in parameterInfos
                                     select ExtractParameterFromDictionary(parameterInfo, parameters, TaskMethodInfo);
            object[] parametersArray = rawParameterValues.ToArray();

            CancellationTokenSource tokenSource = null;
            bool disposedTimer = false;
            Timer taskCancelledTimer = null;
            bool taskCancelledTimerRequired = false;

            int timeout = GetAsyncManager(controllerContext.Controller).Timeout;

            for (int i = 0; i < parametersArray.Length; i++)
            {
                if (default(CancellationToken).Equals(parametersArray[i]))
                {
                    tokenSource = new CancellationTokenSource();
                    parametersArray[i] = tokenSource.Token;

                    // If there is a timeout we will create a timer to cancel the task when the
                    // timeout expires.
                    taskCancelledTimerRequired = timeout > Timeout.Infinite;
                    break;
                }
            }

            ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(TaskMethodInfo);

            if (taskCancelledTimerRequired)
            {
                taskCancelledTimer = new Timer(_ =>
                {
                    lock (tokenSource)
                    {
                        if (!disposedTimer)
                        {
                            tokenSource.Cancel();
                        }
                    }
                }, state: null, dueTime: timeout, period: Timeout.Infinite);
            }

            Task taskUser = dispatcher.Execute(controllerContext.Controller, parametersArray) as Task;
            Action cleanupAtEndExecute = () =>
            {
                // Cleanup code that's run in EndExecute, after we've waited on the task value. 

                if (taskCancelledTimer != null)
                {
                    // Timer callback may still fire after Dispose is called. 
                    taskCancelledTimer.Dispose();
                }

                if (tokenSource != null)
                {
                    lock (tokenSource)
                    {
                        disposedTimer = true;
                        tokenSource.Dispose();
                        if (tokenSource.IsCancellationRequested)
                        {
                            // Give Timeout exceptions higher priority over other exceptions, mainly OperationCancelled exceptions 
                            // that were signaled with out timeout token.                             
                            throw new TimeoutException();
                        }
                    }
                }
            };

            TaskWrapperAsyncResult result = new TaskWrapperAsyncResult(taskUser, state, cleanupAtEndExecute);

            // if user supplied a callback, invoke that when their task has finished running. 
            if (callback != null)
            {
                if (taskUser.IsCompleted)
                {
                    // If the underlying task is already finished, from our caller's perspective this is just
                    // a synchronous completion.
                    result.CompletedSynchronously = true;
                    callback(result);
                }
                else
                {
                    // If the underlying task isn't yet finished, from our caller's perspective this will be
                    // an asynchronous completion. We'll use ContinueWith instead of Finally for two reasons:
                    //
                    // - Finally propagates the antecedent Task's exception, which we don't need to do here.
                    //   Out caller will eventually call EndExecute, which correctly observes the
                    //   antecedent Task's exception anyway if it faulted.
                    //
                    // - Finally invokes the callback on the captured SynchronizationContext, which is
                    //   unnecessary when using APM (Begin / End). APM assumes that the callback is invoked
                    //   on an arbitrary ThreadPool thread with no SynchronizationContext set up, so
                    //   ContinueWith gets us closer to the desired semantic.
                    result.CompletedSynchronously = false;
                    taskUser.ContinueWith(_ =>
                    {
                        callback(result);
                    });
                }
            }

            return result;
        }