2017-04-02 61 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