Web API - 拦截器 - 拦截异步控制器操作
Web API - Interceptor - intercepting async controller actions
在我们的 Web API 集成测试中,我们在测试异步操作时遇到了问题。
在我的简单测试中,我创建了一个简单的控制器操作:
[HttpGet]
[Route("test")]
public async Task<ApiResponse> Test()
{
return await Task.FromResult(new ApiResponse(true));
}
然而,当我 运行 时,集成测试失败,出现以下异常:
System.InvalidCastException : Unable to cast object of type
'Jacobo.Api.Model.Shared.ApiModels.ApiResponse' to type
'System.Threading.Tasks.Task`1[Jacobo.Api.Model.Shared.ApiModels.ApiResponse]'.
at Castle.Proxies.IIdentityControllerProxy.Test() at
ServerApi.IntegrationTests.IdentityControllerTests.d__10.MoveNext()
in
E:\Dev\Jacobo\ServerApi.IntegrationTests\IdentityControllerTests.cs:line
218
--- End of stack trace from previous location where exception was thrown --- at
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at
NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(Object
invocationResult) at
NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod(TestExecutionContext
context)
我可以看到这是从哪里来的,因为我们正在 return 一个结果不再匹配显然包含在任务中的操作 return 类型。
我们的整个拦截器代码块运行良好:
public void Intercept(IInvocation invocation)
{
// our interceptor implementation ...
// some irrelevant code before this
invocation.ReturnValue = webInvocation.Invoke(_client, invocation.Arguments); // the return value is populated correctly. not wrapped in a task.
}
然后测试失败,因为它试图 return 等待的结果:
[Test]
public async Task GettingAsyncActionResultWillSucceed()
{
var ctl = BuildController(new SameMethodStack("GET"));
var result = await ctl.Test();
Assert.IsTrue(result.Success);
}
我很不确定从这里到哪里去。
终于找到解决办法了。我必须检测该方法是否是异步的,并基于此将结果包装到任务中:
if (isAsync)
{
var result = webInvocation.Invoke(_client, invocation.Arguments);
var type = result.GetType();
var methodInfo = typeof(Task).GetMethod("FromResult");
var genericMethod = methodInfo.MakeGenericMethod(type);
invocation.ReturnValue = genericMethod.Invoke(result, new []{ result });
}
在我们的 Web API 集成测试中,我们在测试异步操作时遇到了问题。
在我的简单测试中,我创建了一个简单的控制器操作:
[HttpGet]
[Route("test")]
public async Task<ApiResponse> Test()
{
return await Task.FromResult(new ApiResponse(true));
}
然而,当我 运行 时,集成测试失败,出现以下异常:
System.InvalidCastException : Unable to cast object of type 'Jacobo.Api.Model.Shared.ApiModels.ApiResponse' to type 'System.Threading.Tasks.Task`1[Jacobo.Api.Model.Shared.ApiModels.ApiResponse]'. at Castle.Proxies.IIdentityControllerProxy.Test() at ServerApi.IntegrationTests.IdentityControllerTests.d__10.MoveNext() in E:\Dev\Jacobo\ServerApi.IntegrationTests\IdentityControllerTests.cs:line 218 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(Object invocationResult) at NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod(TestExecutionContext context)
我可以看到这是从哪里来的,因为我们正在 return 一个结果不再匹配显然包含在任务中的操作 return 类型。
我们的整个拦截器代码块运行良好:
public void Intercept(IInvocation invocation)
{
// our interceptor implementation ...
// some irrelevant code before this
invocation.ReturnValue = webInvocation.Invoke(_client, invocation.Arguments); // the return value is populated correctly. not wrapped in a task.
}
然后测试失败,因为它试图 return 等待的结果:
[Test]
public async Task GettingAsyncActionResultWillSucceed()
{
var ctl = BuildController(new SameMethodStack("GET"));
var result = await ctl.Test();
Assert.IsTrue(result.Success);
}
我很不确定从这里到哪里去。
终于找到解决办法了。我必须检测该方法是否是异步的,并基于此将结果包装到任务中:
if (isAsync)
{
var result = webInvocation.Invoke(_client, invocation.Arguments);
var type = result.GetType();
var methodInfo = typeof(Task).GetMethod("FromResult");
var genericMethod = methodInfo.MakeGenericMethod(type);
invocation.ReturnValue = genericMethod.Invoke(result, new []{ result });
}