【问题标题】:Possible to intercept an async method and overwrite ReturnValue?可以拦截异步方法并覆盖 ReturnValue?
【发布时间】:2020-07-30 03:49:11
【问题描述】:

我有一个方法:

public virtual async Task<IActionResult> GetEmployees([HttpTrigger(AuthorizationLevel.Admin, "get", Route = null)] HttpRequest req) {
  return OkObjectResult(null);
}

我知道我可以使用 autofac 同步拦截:

public class CallLogger : IInterceptor
{
  TextWriter _output;

  public CallLogger(TextWriter output)
  {
    _output = output;
  }

 public void Intercept(IInvocation invocation)
  {
    _output.Write("Calling method {0} with parameters {1}... ",
      invocation.Method.Name,
      string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()));

    invocation.Proceed();

    _output.WriteLine("Done: result was {0}.", invocation.ReturnValue);
  }
}

但是如何在可能覆盖我正在拦截的方法返回的结果的同时异步执行此操作?它目前返回一个OkObjectResult,例如,我可能想返回一个 404。

伪代码

public async Task Intercept(IInvocation invocation)
{
    var myAsyncResult = await _myAsyncClass.MyAsyncMethod();

    if (myAsyncResult == expected)
    {
       invocation.Proceed();
    }
    else
    {
       invocation.ReturnValue = // some overwrite of the value - and don't proceed with the invocation.
    }
}

注意

我知道 autofac 中有一些巧妙的异步方法,但这不允许我阻止执行原始方法并覆盖值,而是我需要“继续”调用并使用它的返回:https://stackoverflow.com/a/39784559/12683473

【问题讨论】:

    标签: c# .net autofac interceptor


    【解决方案1】:

    要记住 Castle.Core 的主要内容是,您不能在 await 之后调用 IInvocation.Proceed,因为在拦截器(同步)返回后会重用 IInvocation 实例。

    但是,Castle.Core 的现代版本确实支持IInvocation.CaptureProceedInfo,可以这样使用:

    public class CallLogger : IInterceptor
    {
      public void Intercept(IInvocation invocation)
      {
        invocation.ReturnValue = InterceptAsync<MyResult>(invocation.CaptureProceedInfo());
      }
    
      private async Task<TResult> InterceptAsync<TResult>(IInvocationProceedInfo proceed)
      {
        var myAsyncResult = await _myAsyncClass.MyAsyncMethod();
    
        if (myAsyncResult == expected)
        {
          proceed.Invoke();
        }
        else
        {
          return ...;
        }
      }
    }
    

    这个简单的代码假设你的代码可以指定一个类型MyResult,它是被拦截方法的已知结果。更一般的情况requires reflection and TaskCompletionSource&lt;T&gt;

    【讨论】:

    • 感谢朋友的回复!非常感激。不过,我很困惑 - 并非所有这些代码路径都返回一个值。我假设我的 return ...; 是我的覆盖(即原始调用不会返回的值,这是我即时返回的一些值)。但是,如果需要,我如何从原始调用中返回值?谢谢。
    • @JᴀʏMᴇᴇ: 好抓;我确实做错了。您需要将IInvocation 传递给InterceptAsync,然后在Invoke 之后使用ReturnValue(转换为Task&lt;TResult&gt;)。请参阅source of AsyncInterceptor for details
    猜你喜欢
    • 2020-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-14
    • 1970-01-01
    • 2012-12-26
    • 2017-01-27
    • 1970-01-01
    相关资源
    最近更新 更多