NET Core中怎么使用HttpContext.Current


NET Core中怎么使用HttpContext.Current

一、前言

  我們都知道,ASP.NET Core作為最新的框架,在MVC5和ASP.NET WebForm的基礎上做了大量的重構。如果我們想使用以前版本中的HttpContext.Current的話,目前是不可用的,因為ASP.NET Core中是並沒有這個API的。

  當然我們也可以通過在Controller中訪問HttpContext,但是某些情況下,這樣使用起來還是不如HttpContext.Current方便。

二、IHttpContextAccessor

  利用ASP.NET Core的依賴注入容器系統,通過請求獲取IHttpContextAccessor接口,我們擁有模擬使用HttpContext.Current這樣API的可能性。但是因為IHttpContextAccessor接口默認不是由依賴注入進行實例管理的。我們先要將它注冊到ServiceCollection中:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
  4. // Other code...
  5. }

  來模擬一個HttpContext.Current吧:

  1. public static class HttpContext
  2. {
  3. public static IServiceProvider ServiceProvider;
  4. public static Microsoft.AspNetCore.Http.HttpContext Current
  5. {
  6. get
  7. {
  8. object factory = ServiceProvider.GetService(typeof(Microsoft.AspNetCore.Http.IHttpContextAccessor));
  9. Microsoft.AspNetCore.Http.HttpContext context = ((Microsoft.AspNetCore.Http.HttpContextAccessor)factory).HttpContext;
  10. return context;
  11. }
  12. }
  13. }

  其實說到HttpContext.Current就不得不提到多線程問題,在以前的ASP.NET版本中,如果遇到多線程環境很有可能HttpContext.Current為空的情況。說到這個問題以前就是有解決方案的,那就是CallContext;

  CallContext 是類似於方法調用的線程本地存儲區的專用集合對象,並提供對每個邏輯執行線程都唯一的數據槽。數據槽不在其他邏輯線程上的調用上下文之間共享。當 CallContext 沿執行代碼路徑往返傳播並且由該路徑中的各個對象檢查時,可將對象添加到其中。

  當使用ASP.NET的時候,雖然線城池里的線程是復用的,但是CallContext並不在一個線程的多次使用中共享。因為CallContext是針對邏輯線程的TLS,線程池中被復用的線程是操作系統中的內核對象而不是托管對象。就像數據庫連接池中保存的是非托管資源而不是托管資源。因此,先后執行的兩個托管線程可能在底層復用了一個物理線程(內核對象),但並不能共享同一組CallContext數據槽。就像先后new的兩個SqlConnection對象可能在底層使用了同一個物理連接,但是托管對象的屬性已經被重置。

  與此對照的是ThreadStaticAttribute,標記上這個特性的靜態字段是往物理線程的TLS中保存數據(根據MSDN的描述猜的。具體沒試過),因此如果兩個托管線程對象內部使用的是同一個物理線程,則這個字段會復用(在兩個線程通過這一字段訪問同一個數據槽)。

  在.NET Core中,也有新的API選擇,AsyncLocal<T>。

三、HttpContextAccessor

  我們來看看ASP.NET Core中的IHttpContextAccessor接口實現吧:

 

  1. public class HttpContextAccessor : IHttpContextAccessor
  2. {
  3. #if NET451
  4. private static readonly string LogicalDataKey = "__HttpContext_Current__" + AppDomain.CurrentDomain.Id;
  5. public HttpContext HttpContext
  6. {
  7. get
  8. {
  9. var handle = CallContext.LogicalGetData(LogicalDataKey) as ObjectHandle;
  10. return handle?.Unwrap() as HttpContext;
  11. }
  12. set
  13. {
  14. CallContext.LogicalSetData(LogicalDataKey, new ObjectHandle(value));
  15. }
  16. }
  17. #elif NETSTANDARD1_3
  18. private AsyncLocal<HttpContext> _httpContextCurrent = new AsyncLocal<HttpContext>();
  19. public HttpContext HttpContext
  20. {
  21. get
  22. {
  23. return _httpContextCurrent.Value;
  24. }
  25. set
  26. {
  27. _httpContextCurrent.Value = value;
  28. }
  29. }
  30. #endif
  31. }

 

  最后我只能說在ASP.NET Core中是萬物皆DI啊,其實Core中的實現早就為我們想好了這些功能,只是改變了使用方式。

 

GitHub:https://github.com/maxzhang1985/YOYOFx  如果覺還可以請Star下, 歡迎一起交流。

 

.NET Core 開源學習群: 214741894  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM