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"); } AsyncManager asyncManager = GetAsyncManager(controllerContext.Controller); BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState) { // call the XxxAsync() method ParameterInfo[] parameterInfos = AsyncMethodInfo.GetParameters(); var rawParameterValues = from parameterInfo in parameterInfos select ExtractParameterFromDictionary(parameterInfo, parameters, AsyncMethodInfo); object[] parametersArray = rawParameterValues.ToArray(); TriggerListener listener = new TriggerListener(); SimpleAsyncResult asyncResult = new SimpleAsyncResult(asyncState); // hook the Finished event to notify us upon completion Trigger finishTrigger = listener.CreateTrigger(); asyncManager.Finished += delegate { finishTrigger.Fire(); }; asyncManager.OutstandingOperations.Increment(); // to simplify the logic, force the rest of the pipeline to execute in an asynchronous callback listener.SetContinuation(() => ThreadPool.QueueUserWorkItem(_ => asyncResult.MarkCompleted(false /* completedSynchronously */, asyncCallback))); // the inner operation might complete synchronously, so all setup work has to be done before this point ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(AsyncMethodInfo); dispatcher.Execute(controllerContext.Controller, parametersArray); // ignore return value from this method // now that the XxxAsync() method has completed, kick off any pending operations asyncManager.OutstandingOperations.Decrement(); listener.Activate(); return(asyncResult); }; EndInvokeDelegate <object> endDelegate = delegate(IAsyncResult asyncResult) { // call the XxxCompleted() method ParameterInfo[] completionParametersInfos = CompletedMethodInfo.GetParameters(); var rawCompletionParameterValues = from parameterInfo in completionParametersInfos select ExtractParameterOrDefaultFromDictionary(parameterInfo, asyncManager.Parameters); object[] completionParametersArray = rawCompletionParameterValues.ToArray(); ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(CompletedMethodInfo); object actionReturnValue = dispatcher.Execute(controllerContext.Controller, completionParametersArray); return(actionReturnValue); }; return(AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, _executeTag, asyncManager.Timeout)); }
public void MethodInfoProperty() { // Arrange MethodInfo original = typeof(object).GetMethod("ToString"); ActionMethodDispatcher dispatcher = new ActionMethodDispatcher(original); // Act MethodInfo returned = dispatcher.MethodInfo; // Assert Assert.Same(original, returned); }
public void GetDispatcher() { // Arrange MethodInfo methodInfo = typeof(object).GetMethod("ToString"); ActionMethodDispatcherCache cache = new ActionMethodDispatcherCache(); // Act ActionMethodDispatcher dispatcher1 = cache.GetDispatcher(methodInfo); ActionMethodDispatcher dispatcher2 = cache.GetDispatcher(methodInfo); // Assert Assert.Same(methodInfo, dispatcher1.MethodInfo); Assert.Same(dispatcher1, dispatcher2); }
public void ExecuteWithStaticActionMethod() { // Arrange DispatcherController controller = new DispatcherController(); object[] parameters = new object[0]; MethodInfo methodInfo = typeof(DispatcherController).GetMethod("StaticAction"); ActionMethodDispatcher dispatcher = new ActionMethodDispatcher(methodInfo); // Act object returnValue = dispatcher.Execute(controller, parameters); // Assert var intResult = Assert.IsType<int>(returnValue); Assert.Equal(89, intResult); }
public void ExecuteWithStaticActionMethod() { // Arrange DispatcherController controller = new DispatcherController(); object[] parameters = new object[0]; MethodInfo methodInfo = typeof(DispatcherController).GetMethod("StaticAction"); ActionMethodDispatcher dispatcher = new ActionMethodDispatcher(methodInfo); // Act object returnValue = dispatcher.Execute(controller, parameters); // Assert var intResult = Assert.IsType <int>(returnValue); Assert.Equal(89, intResult); }
public void ExecuteWithVoidActionMethod() { // Arrange DispatcherController controller = new DispatcherController(); object[] parameters = new object[] { 5, "some string", new DateTime(2001, 1, 1) }; MethodInfo methodInfo = typeof(DispatcherController).GetMethod("VoidAction"); ActionMethodDispatcher dispatcher = new ActionMethodDispatcher(methodInfo); // Act object returnValue = dispatcher.Execute(controller, parameters); // Assert Assert.Null(returnValue); Assert.Equal(5, controller._i); Assert.Equal("some string", controller._s); Assert.Equal(new DateTime(2001, 1, 1), controller._dt); }
public void ExecuteWithStaticActionMethod() { // Arrange DispatcherController controller = new DispatcherController(); object[] parameters = new object[0]; MethodInfo methodInfo = typeof(DispatcherController).GetMethod("StaticAction"); ActionMethodDispatcher dispatcher = new ActionMethodDispatcher(methodInfo); // Act object returnValue = dispatcher.Execute(controller, parameters); // Assert Assert.IsInstanceOfType(returnValue, typeof(int)); int intResult = (int)returnValue; Assert.AreEqual(89, intResult); }
public void ExecuteWithNormalActionMethod() { // Arrange DispatcherController controller = new DispatcherController(); object[] parameters = new object[] { 5, "some string", new DateTime(2001, 1, 1) }; MethodInfo methodInfo = typeof(DispatcherController).GetMethod("NormalAction"); ActionMethodDispatcher dispatcher = new ActionMethodDispatcher(methodInfo); // Act object returnValue = dispatcher.Execute(controller, parameters); // Assert var stringResult = Assert.IsType<string>(returnValue); Assert.Equal("Hello from NormalAction!", stringResult); Assert.Equal(5, controller._i); Assert.Equal("some string", controller._s); Assert.Equal(new DateTime(2001, 1, 1), controller._dt); }
public void ExecuteWithNormalActionMethod() { // Arrange DispatcherController controller = new DispatcherController(); object[] parameters = new object[] { 5, "some string", new DateTime(2001, 1, 1) }; MethodInfo methodInfo = typeof(DispatcherController).GetMethod("NormalAction"); ActionMethodDispatcher dispatcher = new ActionMethodDispatcher(methodInfo); // Act object returnValue = dispatcher.Execute(controller, parameters); // Assert var stringResult = Assert.IsType <string>(returnValue); Assert.Equal("Hello from NormalAction!", stringResult); Assert.Equal(5, controller._i); Assert.Equal("some string", controller._s); Assert.Equal(new DateTime(2001, 1, 1), controller._dt); }
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); }