2017-04-02 60 views
1

我一直在为我的ASP.NET Core API编写一些日志记录服务。
我写了一个中间件,它将记录每个被调用的行为(交叉关注,似乎是合乎逻辑的)。在控制器之外使用HttpContext - 糟糕的做法?

我想记录的一件事是用户的IP(例如)。 我能想到得到这些数据的唯一方法是通过HttpContext.Connection
它按预期工作。

But lately I've been reading有关它的更多信息,我明白访问控制器外部的HttpContext被认为是不好的做法。 它使代码不可测试,因为它很难模拟和模仿。
此外,代码不能移植到其他.NET应用程序,并且必须位于ASP.NET应用程序的上下文中。

所以我的问题是 - 在控制器之外使用HttpContext是否真的是一种很糟糕的做法 - 例如在中间件内部?
如果是这样 - 有什么选择?

或者可能使用HttpContext在ASP.NET内部使用的组件(如顶级控制器或中间件)内部是合法的。

谢谢。

+1

这取决于。如果你在你的域层(=域服务)中引用它,那么它绝对是你能做的最糟糕的事情之一,因为域不能对基础设施有任何依赖(db,webservice,像asp.net,wpf,uwp等主机)。如果它在应用程序层(=应用程序服务)上使用,则没关系。不同之处在于,应用程序级别与应用程序有关,很难或根本不可移植(即访问httpcontext信息,因为没有httpcontext,所以它不能在WPF上工作) – Tseng

+0

@Tseng,是的,这样认为。这就是为什么我问是否可以在顶级控制器和中间件中使用它 - 意味着任何必须在ASP.Net – DotnetProg

回答

3

在控制器以外的ASP.NET核心中使用HttpContext类的实例是完全正确的。特别是编写一个中间件,如果没有代表当前请求的实例HttpContext,将毫无用处。

主要区别在于你不应该使用静态存取器就像HttpContext.Current在ASP.NET System.Web中那种想法。您引用的博客帖子是关于如何在ASP.NET Core中模仿这一点,如果您现有的代码很多依赖于此。在ASP.NET Core术语中,上下文的一个实例被传递给您的中间件的Invoke方法,或者您可以使用依赖注入访问IHttpContextAccessor对象。

查看ASP.NET Core Docs中的示例。 HttpContext被注入为参数名称context,因此不需要依赖像HttpContext.Current这样的静态存取器。尤其是这更容易测试,因为您可以在单元测试中创建自己的HttpContext实例并将其传递给Invoke方法。

public class RequestCultureMiddleware 
{ 
    private readonly RequestDelegate _next; 

    public RequestCultureMiddleware(RequestDelegate next) 
    { 
     _next = next; 
    } 

    public Task Invoke(HttpContext context) 
    { 
     var cultureQuery = context.Request.Query["culture"]; 
     if (!string.IsNullOrWhiteSpace(cultureQuery)) 
     { 
      var culture = new CultureInfo(cultureQuery); 

      CultureInfo.CurrentCulture = culture; 
      CultureInfo.CurrentUICulture = culture; 

     } 

     // Call the next delegate/middleware in the pipeline 
     return this._next(context); 
    } 
} 
+0

范围内生存的代码正如你所说的,我注意到'HttpContext'参数被传递给中间件,这就是我能够获得客户端的远程IP地址的方式。我没有注意到使用'HttpContext'实例和使用静态'HttpContext.Current'之间的细微差别。谢谢你让我放心。 – DotnetProg