如何管理装饰的ApiControllers中的重复?

时间:2017-12-04 06:02:07

标签: c# dependency-injection asp.net-web-api2 decorator dry

我目前正在开展一个项目,每个api控制器都需要记录活动。一个粗略的例子可能是:

[Route(...)]
public IHttpActionResult Foo(...)
{
    using(var logger = ...)
    {
        // use the logger
        return _service.Bar(...);
    }
}

在我看来,这至少有三个问题。

  1. 将日志记录横切关注与违反单一责任原则的请求处理相结合。
  2. logger实现与new违反依赖性倒置原则的控制器耦合。
  3. 重复违反DRY的每个控制器中每个端点的using
  4. 我认为我可以通过装饰控制器来修复(1),(2)使用基本DI,并且(3),我相信,结果会自行解决。但是,我通过装饰具有Route属性端点的控制器来引发另一个重复问题。装饰控制器不应该让我依赖于特定的实现来处理路由,所以我在每个装饰中都需要它们(可能更多)或找到继承或重用它们的方法。

    // I can fluently handle logging with a LoggingController
    // but I still need the route attribute
    [Route(...)]
    public IHttpActionResult Foo(...)
    {
        return LogActivity(...).Foo(...);
    }
    
    private IController LogActivity(...)
    {
        // do logging
        return _controller;
    }
    

    到目前为止,我认为我有两个可行的解决方案:

    1. 将关卡抽象提升为抽象类,我可以继承属性。
    2. 提供代理装饰,只需委托最外面的实际装饰。
    3. (1)将我与一些基本实现联系起来,(2)将我与每个控制器类型的代理/包装器耦合。 (2)看起来似乎是更好的方法,但它是否值得怀疑是否有一些DI或AOP模式可以解决这个问题。

      // (2) with a decorator with no additional
      // behavior or functionality delegates to 
      // the given implementation.
      [Route(...)]
      public IHttpActionResult Foo(...)
      {
          return _controller.Foo(...);
      }
      

1 个答案:

答案 0 :(得分:3)

您可以使用ASP.NET的HTTP消息处理程序(ASP.NET Core的中间件),您可以将其插入请求管道,对其余代码透明。通过这种方式,您可以实现横切关注点处理的正交性,并避免重复自己。

ASP.NET 4.5 +的HTTP消息处理程序示例:

public class RequestLoggingHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        // --> log begin of request
        // for example, you can include time measurement
        Stopwatch requestTime = Stopwatch.StartNew();

        try
        {
            var response = await base.SendAsync(request, cancellationToken);
            // --> log successful completion
            return response;
        }
        catch (Exception e)
        {
            // --> log failure
            throw;
        }
    }
}

这是你插入它的方式:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MessageHandlers.Add(new RequestLoggingHandler());

        //... the rest of the setup...
    }
}

在ASP.NET Core中,还有一种名为Middleware的新方法。有关详细信息,请访问:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware?tabs=aspnetcore2x#writing-middleware