我目前正在开展一个项目,每个api控制器都需要记录活动。一个粗略的例子可能是:
[Route(...)]
public IHttpActionResult Foo(...)
{
using(var logger = ...)
{
// use the logger
return _service.Bar(...);
}
}
在我看来,这至少有三个问题。
logger
实现与new
违反依赖性倒置原则的控制器耦合。using
。我认为我可以通过装饰控制器来修复(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)将我与每个控制器类型的代理/包装器耦合。 (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(...);
}
答案 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