Web API - 拦截器 - 拦截异步控制器操作

时间:2017-10-19 08:09:22

标签: c# async-await asp.net-web-api2 interceptor castle-dynamicproxy

在我们的Web API集成测试中,我们遇到了测试异步操作的问题。

在我的简单测试中,我创建了一个简单的控制器动作:

[HttpGet]
[Route("test")]
public async Task<ApiResponse> Test()
{
    return await Task.FromResult(new ApiResponse(true));
}

但是当我运行集成测试时,它会因以下异常而失败:

  

System.InvalidCastException:无法转换类型的对象   'Jacobo.Api.Model.Shared.ApiModels.ApiResponse'键入   'System.Threading.Tasks.Task`1 [Jacobo.Api.Model.Shared.ApiModels.ApiResponse]'。   在Castle.Proxies.IIdentityControllerProxy.Test()at   ServerApi.IntegrationTests.IdentityControllerTests.d__10.MoveNext()   在   E:\开发\雅各布\ ServerApi.IntegrationTests \ IdentityControllerTests.cs:行   218   ---从抛出异常的先前位置开始的堆栈跟踪结束--- at   System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()at   NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(对象   invocationResult)at   NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod(TestExecutionContext   上下文中)

我可以看到它来自何处,因为我们返回的结果不再与动作返回类型相匹配,该结果显然包含在任务中。

我们的Interceptor代码的整个块运行良好:

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.
}

然后测试失败,因为它试图返回等待的结果:

[Test]
public async Task GettingAsyncActionResultWillSucceed()
{
    var ctl = BuildController(new SameMethodStack("GET"));
    var result = await ctl.Test();
    Assert.IsTrue(result.Success);
}

我不确定从哪里开始。

1 个答案:

答案 0 :(得分:1)

终于找到了解决方案。我必须检测方法是否是异步的并且基于将结果包装到任务中:

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 });
            }