560 lines
20 KiB
C#
560 lines
20 KiB
C#
|
// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
|
|||
|
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.Linq;
|
|||
|
using System.Reflection;
|
|||
|
using System.Threading;
|
|||
|
using System.Threading.Tasks;
|
|||
|
using Moq;
|
|||
|
using Xunit;
|
|||
|
using Assert = Microsoft.TestCommon.AssertEx;
|
|||
|
|
|||
|
namespace System.Web.Mvc.Async.Test
|
|||
|
{
|
|||
|
public class TaskAsyncActionDescriptorTest
|
|||
|
{
|
|||
|
private readonly MethodInfo _taskMethod = typeof(ExecuteController).GetMethod("SimpleTask");
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void Constructor_SetsProperties()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
string actionName = "SomeAction";
|
|||
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|||
|
|
|||
|
// Act
|
|||
|
TaskAsyncActionDescriptor ad = new TaskAsyncActionDescriptor(_taskMethod, actionName, cd);
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Equal(_taskMethod, ad.TaskMethodInfo);
|
|||
|
Assert.Equal(actionName, ad.ActionName);
|
|||
|
Assert.Equal(cd, ad.ControllerDescriptor);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void Constructor_ThrowsIfActionNameIsEmpty()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.ThrowsArgumentNullOrEmpty(
|
|||
|
delegate { new TaskAsyncActionDescriptor(_taskMethod, "", cd); }, "actionName");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void Constructor_ThrowsIfActionNameIsNull()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.ThrowsArgumentNullOrEmpty(
|
|||
|
delegate { new TaskAsyncActionDescriptor(_taskMethod, null, cd); }, "actionName");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void Constructor_ThrowsIfTaskMethodInfoIsInvalid()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|||
|
MethodInfo getHashCodeMethod = typeof(object).GetMethod("GetHashCode");
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.Throws<ArgumentException>(
|
|||
|
delegate { new TaskAsyncActionDescriptor(getHashCodeMethod, "SomeAction", cd); },
|
|||
|
@"Cannot create a descriptor for instance method 'Int32 GetHashCode()' on type 'System.Object' because the type does not derive from ControllerBase.
|
|||
|
Parameter name: taskMethodInfo");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void Constructor_ThrowsIfTaskMethodInfoIsNull()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
ControllerDescriptor cd = new Mock<ControllerDescriptor>().Object;
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.ThrowsArgumentNull(
|
|||
|
delegate { new TaskAsyncActionDescriptor(null, "SomeAction", cd); }, "taskMethodInfo");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void Constructor_ThrowsIfControllerDescriptorIsNull()
|
|||
|
{
|
|||
|
// Act & assert
|
|||
|
Assert.ThrowsArgumentNull(
|
|||
|
delegate { new TaskAsyncActionDescriptor(_taskMethod, "SomeAction", null); }, "controllerDescriptor");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ExecuteTask()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("SimpleTask"));
|
|||
|
|
|||
|
Dictionary<string, object> parameters = new Dictionary<string, object>()
|
|||
|
{
|
|||
|
{ "doWork", true }
|
|||
|
};
|
|||
|
|
|||
|
ControllerContext controllerContext = GetControllerContext();
|
|||
|
|
|||
|
// Act
|
|||
|
object retVal = ExecuteHelper(actionDescriptor, parameters, controllerContext);
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Null(retVal);
|
|||
|
Assert.True((controllerContext.Controller as ExecuteController).WorkDone);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ExecuteTaskGeneric()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("GenericTask"));
|
|||
|
|
|||
|
Dictionary<string, object> parameters = new Dictionary<string, object>()
|
|||
|
{
|
|||
|
{ "taskId", "foo" }
|
|||
|
};
|
|||
|
|
|||
|
// Act
|
|||
|
object retVal = ExecuteHelper(actionDescriptor, parameters);
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Equal("foo", retVal);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ExecuteTaskPreservesStackTraceOnException()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("SimpleTaskException"));
|
|||
|
|
|||
|
Dictionary<string, object> parameters = new Dictionary<string, object>()
|
|||
|
{
|
|||
|
{ "doWork", true }
|
|||
|
};
|
|||
|
|
|||
|
// Act
|
|||
|
IAsyncResult result = actionDescriptor.BeginExecute(GetControllerContext(), parameters, null, null);
|
|||
|
|
|||
|
// Assert
|
|||
|
InvalidOperationException ex = Assert.Throws<InvalidOperationException>(
|
|||
|
() => actionDescriptor.EndExecute(result),
|
|||
|
"Test exception from action"
|
|||
|
);
|
|||
|
|
|||
|
Assert.True(ex.StackTrace.Contains("System.Web.Mvc.Async.Test.TaskAsyncActionDescriptorTest.ExecuteController."));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ExecuteTaskGenericPreservesStackTraceOnException()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("GenericTaskException"));
|
|||
|
|
|||
|
Dictionary<string, object> parameters = new Dictionary<string, object>()
|
|||
|
{
|
|||
|
{ "taskId", "foo" },
|
|||
|
{ "throwException", true }
|
|||
|
};
|
|||
|
|
|||
|
// Act
|
|||
|
IAsyncResult result = actionDescriptor.BeginExecute(GetControllerContext(), parameters, null, null);
|
|||
|
|
|||
|
// Assert
|
|||
|
InvalidOperationException ex = Assert.Throws<InvalidOperationException>(
|
|||
|
() => actionDescriptor.EndExecute(result),
|
|||
|
"Test exception from action"
|
|||
|
);
|
|||
|
|
|||
|
Assert.True(ex.StackTrace.Contains("System.Web.Mvc.Async.Test.TaskAsyncActionDescriptorTest.ExecuteController."));
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ExecuteTaskOfPrivateT()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("TaskOfPrivateT"));
|
|||
|
ControllerContext controllerContext = GetControllerContext();
|
|||
|
|
|||
|
Dictionary<string, object> parameters = new Dictionary<string, object>();
|
|||
|
|
|||
|
// Act
|
|||
|
object retVal = ExecuteHelper(actionDescriptor, parameters, controllerContext);
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Null(retVal);
|
|||
|
Assert.True((controllerContext.Controller as ExecuteController).WorkDone);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ExecuteTaskPreservesState()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("SimpleTask"));
|
|||
|
|
|||
|
Dictionary<string, object> parameters = new Dictionary<string, object>()
|
|||
|
{
|
|||
|
{ "doWork", true }
|
|||
|
};
|
|||
|
|
|||
|
ControllerContext controllerContext = GetControllerContext();
|
|||
|
|
|||
|
// Act
|
|||
|
TaskWrapperAsyncResult result = (TaskWrapperAsyncResult)actionDescriptor.BeginExecute(GetControllerContext(), parameters, callback: null, state: "state");
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Equal("state", result.AsyncState);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ExecuteTaskWithNullParameterAndTimeout()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("TaskTimeoutWithNullParam"));
|
|||
|
|
|||
|
Dictionary<string, object> token = new Dictionary<string, object>()
|
|||
|
{
|
|||
|
{ "nullParam", null },
|
|||
|
{ "cancellationToken", new CancellationToken() }
|
|||
|
};
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.Throws<TimeoutException>(
|
|||
|
() => actionDescriptor.EndExecute(actionDescriptor.BeginExecute(GetControllerContext(0), parameters: token, callback: null, state: null)),
|
|||
|
"The operation has timed out."
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ExecuteWithInfiniteTimeout()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("TaskWithInfiniteTimeout"));
|
|||
|
ControllerContext controllerContext = GetControllerContext(Timeout.Infinite);
|
|||
|
|
|||
|
Dictionary<string, object> parameters = new Dictionary<string, object>()
|
|||
|
{
|
|||
|
{ "cancellationToken", new CancellationToken() }
|
|||
|
};
|
|||
|
|
|||
|
// Act
|
|||
|
object retVal = ExecuteHelper(actionDescriptor, parameters);
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Equal("Task Completed", retVal);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ExecuteTaskWithImmediateTimeout()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("TaskTimeout"));
|
|||
|
|
|||
|
Dictionary<string, object> token = new Dictionary<string, object>()
|
|||
|
{
|
|||
|
{ "cancellationToken", new CancellationToken() }
|
|||
|
};
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.Throws<TimeoutException>(
|
|||
|
() => actionDescriptor.EndExecute(actionDescriptor.BeginExecute(GetControllerContext(0), parameters: token, callback: null, state: null)),
|
|||
|
"The operation has timed out."
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void ExecuteTaskWithTimeout()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("TaskTimeout"));
|
|||
|
|
|||
|
Dictionary<string, object> token = new Dictionary<string, object>()
|
|||
|
{
|
|||
|
{ "cancellationToken", new CancellationToken() }
|
|||
|
};
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.Throws<TimeoutException>(
|
|||
|
() => actionDescriptor.EndExecute(actionDescriptor.BeginExecute(GetControllerContext(2000), parameters: token, callback: null, state: null)),
|
|||
|
"The operation has timed out."
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void SynchronousExecuteThrows()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor actionDescriptor = GetActionDescriptor(GetExecuteControllerMethodInfo("SimpleTask"));
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.Throws<InvalidOperationException>(
|
|||
|
delegate { actionDescriptor.Execute(new ControllerContext(), new Dictionary<string, object>()); }, "The asynchronous action method 'someName' returns a Task, which cannot be executed synchronously.");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void Execute_ThrowsIfControllerContextIsNull()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor ad = GetActionDescriptor(_taskMethod);
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.ThrowsArgumentNull(
|
|||
|
delegate { ad.BeginExecute(null, new Dictionary<string, object>(), null, null); }, "controllerContext");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void Execute_ThrowsIfControllerIsNotAsyncManagerContainer()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor ad = GetActionDescriptor(_taskMethod);
|
|||
|
ControllerContext controllerContext = new ControllerContext()
|
|||
|
{
|
|||
|
Controller = new RegularSyncController()
|
|||
|
};
|
|||
|
|
|||
|
Dictionary<string, object> parameters = new Dictionary<string, object>()
|
|||
|
{
|
|||
|
{ "doWork", true }
|
|||
|
};
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.Throws<InvalidOperationException>(
|
|||
|
delegate { ad.BeginExecute(controllerContext, parameters, null, null); },
|
|||
|
@"The controller of type 'System.Web.Mvc.Async.Test.TaskAsyncActionDescriptorTest+RegularSyncController' must subclass AsyncController or implement the IAsyncManagerContainer interface.");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void Execute_ThrowsIfParametersIsNull()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor ad = GetActionDescriptor(_taskMethod);
|
|||
|
|
|||
|
// Act & assert
|
|||
|
Assert.ThrowsArgumentNull(
|
|||
|
delegate { ad.BeginExecute(new ControllerContext(), null, null, null); }, "parameters");
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void GetCustomAttributesCallsMethodInfoGetCustomAttributes()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
object[] expected = new object[0];
|
|||
|
Mock<MethodInfo> mockMethod = new Mock<MethodInfo>();
|
|||
|
mockMethod.Setup(mi => mi.GetCustomAttributes(true)).Returns(expected);
|
|||
|
TaskAsyncActionDescriptor ad = new TaskAsyncActionDescriptor(mockMethod.Object, "someName", new Mock<ControllerDescriptor>().Object, validateMethod: false)
|
|||
|
{
|
|||
|
DispatcherCache = new ActionMethodDispatcherCache()
|
|||
|
};
|
|||
|
|
|||
|
// Act
|
|||
|
object[] returned = ad.GetCustomAttributes(true);
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Same(expected, returned);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void GetCustomAttributesWithAttributeTypeCallsMethodInfoGetCustomAttributes()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
object[] expected = new object[0];
|
|||
|
Mock<MethodInfo> mockMethod = new Mock<MethodInfo>();
|
|||
|
mockMethod.Setup(mi => mi.GetCustomAttributes(typeof(ObsoleteAttribute), true)).Returns(expected);
|
|||
|
TaskAsyncActionDescriptor ad = new TaskAsyncActionDescriptor(mockMethod.Object, "someName", new Mock<ControllerDescriptor>().Object, validateMethod: false)
|
|||
|
{
|
|||
|
DispatcherCache = new ActionMethodDispatcherCache()
|
|||
|
};
|
|||
|
|
|||
|
// Act
|
|||
|
object[] returned = ad.GetCustomAttributes(typeof(ObsoleteAttribute), true);
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Same(expected, returned);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void GetParameters()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
ParameterInfo pInfo = _taskMethod.GetParameters()[0];
|
|||
|
TaskAsyncActionDescriptor ad = GetActionDescriptor(_taskMethod);
|
|||
|
|
|||
|
// Act
|
|||
|
ParameterDescriptor[] pDescsFirstCall = ad.GetParameters();
|
|||
|
ParameterDescriptor[] pDescsSecondCall = ad.GetParameters();
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.NotSame(pDescsFirstCall, pDescsSecondCall); // Should get a new array every time
|
|||
|
Assert.Equal(pDescsFirstCall, pDescsSecondCall);
|
|||
|
Assert.Single(pDescsFirstCall);
|
|||
|
|
|||
|
ReflectedParameterDescriptor pDesc = pDescsFirstCall[0] as ReflectedParameterDescriptor;
|
|||
|
|
|||
|
Assert.NotNull(pDesc);
|
|||
|
Assert.Same(ad, pDesc.ActionDescriptor);
|
|||
|
Assert.Same(pInfo, pDesc.ParameterInfo);
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void GetSelectors()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
ControllerContext controllerContext = new Mock<ControllerContext>().Object;
|
|||
|
Mock<MethodInfo> mockMethod = new Mock<MethodInfo>();
|
|||
|
|
|||
|
Mock<ActionMethodSelectorAttribute> mockAttr = new Mock<ActionMethodSelectorAttribute>();
|
|||
|
mockAttr.Setup(attr => attr.IsValidForRequest(controllerContext, mockMethod.Object)).Returns(true).Verifiable();
|
|||
|
mockMethod.Setup(m => m.GetCustomAttributes(typeof(ActionMethodSelectorAttribute), true)).Returns(new ActionMethodSelectorAttribute[] { mockAttr.Object });
|
|||
|
|
|||
|
TaskAsyncActionDescriptor ad = new TaskAsyncActionDescriptor(mockMethod.Object, "someName", new Mock<ControllerDescriptor>().Object, validateMethod: false)
|
|||
|
{
|
|||
|
DispatcherCache = new ActionMethodDispatcherCache()
|
|||
|
};
|
|||
|
|
|||
|
// Act
|
|||
|
ICollection<ActionSelector> selectors = ad.GetSelectors();
|
|||
|
bool executedSuccessfully = selectors.All(s => s(controllerContext));
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.Single(selectors);
|
|||
|
Assert.True(executedSuccessfully);
|
|||
|
mockAttr.Verify();
|
|||
|
}
|
|||
|
|
|||
|
[Fact]
|
|||
|
public void IsDefined()
|
|||
|
{
|
|||
|
// Arrange
|
|||
|
TaskAsyncActionDescriptor ad = GetActionDescriptor(_taskMethod);
|
|||
|
|
|||
|
// Act
|
|||
|
bool isDefined = ad.IsDefined(typeof(AuthorizeAttribute), inherit: true);
|
|||
|
|
|||
|
// Assert
|
|||
|
Assert.True(isDefined);
|
|||
|
}
|
|||
|
|
|||
|
public static object ExecuteHelper(TaskAsyncActionDescriptor actionDescriptor, Dictionary<string, object> parameters, ControllerContext controllerContext = null)
|
|||
|
{
|
|||
|
SignalContainer<object> resultContainer = new SignalContainer<object>();
|
|||
|
AsyncCallback callback = ar =>
|
|||
|
{
|
|||
|
object o = actionDescriptor.EndExecute(ar);
|
|||
|
resultContainer.Signal(o);
|
|||
|
};
|
|||
|
|
|||
|
actionDescriptor.BeginExecute(controllerContext ?? GetControllerContext(), parameters, callback, state: null);
|
|||
|
return resultContainer.Wait();
|
|||
|
}
|
|||
|
|
|||
|
private static TaskAsyncActionDescriptor GetActionDescriptor(MethodInfo taskMethod)
|
|||
|
{
|
|||
|
return new TaskAsyncActionDescriptor(taskMethod, "someName", new Mock<ControllerDescriptor>().Object)
|
|||
|
{
|
|||
|
DispatcherCache = new ActionMethodDispatcherCache()
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
private static ControllerContext GetControllerContext(int timeout = 45 * 1000)
|
|||
|
{
|
|||
|
Mock<ControllerContext> mockControllerContext = new Mock<ControllerContext>();
|
|||
|
ExecuteController controller = new ExecuteController();
|
|||
|
controller.AsyncManager.Timeout = timeout;
|
|||
|
mockControllerContext.Setup(c => c.Controller).Returns(controller);
|
|||
|
return mockControllerContext.Object;
|
|||
|
}
|
|||
|
|
|||
|
private static MethodInfo GetExecuteControllerMethodInfo(string methodName)
|
|||
|
{
|
|||
|
return typeof(ExecuteController).GetMethod(methodName);
|
|||
|
}
|
|||
|
|
|||
|
private class ExecuteController : AsyncController
|
|||
|
{
|
|||
|
public bool WorkDone { get; set; }
|
|||
|
|
|||
|
public Task<ActionResult> ReturnedTask { get; set; }
|
|||
|
|
|||
|
public Task<string> GenericTask(string taskId)
|
|||
|
{
|
|||
|
return Task.Factory.StartNew(() => taskId);
|
|||
|
}
|
|||
|
|
|||
|
public Task<string> GenericTaskException(string taskId, bool throwException)
|
|||
|
{
|
|||
|
return Task.Factory.StartNew(() =>
|
|||
|
{
|
|||
|
if (throwException)
|
|||
|
{
|
|||
|
ThrowException();
|
|||
|
}
|
|||
|
;
|
|||
|
return taskId;
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
private void ThrowException()
|
|||
|
{
|
|||
|
throw new InvalidOperationException("Test exception from action");
|
|||
|
}
|
|||
|
|
|||
|
[Authorize]
|
|||
|
public Task SimpleTask(bool doWork)
|
|||
|
{
|
|||
|
return Task.Factory.StartNew(() => { WorkDone = doWork; });
|
|||
|
}
|
|||
|
|
|||
|
public Task SimpleTaskException(bool doWork)
|
|||
|
{
|
|||
|
return Task.Factory.StartNew(() => { ThrowException(); });
|
|||
|
}
|
|||
|
|
|||
|
public Task<ActionResult> TaskTimeoutWithNullParam(Object nullParam, CancellationToken cancellationToken)
|
|||
|
{
|
|||
|
return TaskTimeout(cancellationToken);
|
|||
|
}
|
|||
|
|
|||
|
public Task<string> TaskWithInfiniteTimeout(CancellationToken cancellationToken)
|
|||
|
{
|
|||
|
return Task.Factory.StartNew(() => "Task Completed");
|
|||
|
}
|
|||
|
|
|||
|
public Task<ActionResult> TaskTimeout(CancellationToken cancellationToken)
|
|||
|
{
|
|||
|
TaskCompletionSource<ActionResult> completionSource = new TaskCompletionSource<ActionResult>();
|
|||
|
cancellationToken.Register(() => completionSource.TrySetCanceled());
|
|||
|
ReturnedTask = completionSource.Task;
|
|||
|
return ReturnedTask;
|
|||
|
}
|
|||
|
|
|||
|
public Task TaskOfPrivateT()
|
|||
|
{
|
|||
|
var completionSource = new TaskCompletionSource<PrivateObject>();
|
|||
|
completionSource.SetResult(new PrivateObject());
|
|||
|
WorkDone = true;
|
|||
|
return completionSource.Task;
|
|||
|
}
|
|||
|
|
|||
|
private class PrivateObject
|
|||
|
{
|
|||
|
public override string ToString()
|
|||
|
{
|
|||
|
return "Private Object";
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// Controller is async, so derive from ControllerBase to get sync behavior.
|
|||
|
private class RegularSyncController : ControllerBase
|
|||
|
{
|
|||
|
protected override void ExecuteCore()
|
|||
|
{
|
|||
|
throw new NotImplementedException();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|