筆者沒有學 ASP.NET,直接學 ASP.NET Core ,學完 ASP.NET Core MVC 基礎后,開始學習 ASP.NET Core 的運行原理。發現應用程序有一個非常主要的 “傳導體” HttpContext 。
趕忙寫一下筆記先。
目錄
“傳導體” HttpContext
要理解 HttpContext 是干嘛的,首先,看圖
圖一 內網訪問程序

圖二 反向代理訪問程序

ASP.NET Core 程序中,Kestrel 是一個基於 libuv 的跨平台 ASP.NET Core web 服務器。不清楚 Kerstrel 沒關系,以后慢慢了解。
我們可以理解成,外部訪問我們的程序,通過 Http 或者 Https 訪問,例如 https://localhost:44337/Home/Index,需要通過一個網址,來尋向訪問特定的頁面。
訪問頁面時,會產生 Cookie、Seesion、提交表單、上傳數據、身份認證等,外部與應用程序之間傳導的導體就是 HttpContext。
總之,客戶端跟 Web應用程序交互 是通過 HttpContext 傳導的。
原理
ASP.NET Core 本質是一個控制台程序!ASP.NET Core 程序並不直接監聽請求,而是通過依賴 HTTP Server ,來實現把各自請求轉發到應用程序中。這個被轉發的請求相當於我們日常瀏覽網頁、上傳文件、提交表單等的網絡請求,這些請求會被包裝,然后組合到 HttpContext 中。
就好像顧客到餐廳吃飯
- 需要先點菜、提出服務要求
- 服務員把你的菜單、需求送到廚房
- 廚師在加工好食品
- 服務員再把食品遞給你
HttpContext 相當於這個服務員,她在前、后傳遞信息。
操作 HttpContext 前期准備
一般來說,我們主要寫好Web程序,而無需理會 數據是怎么傳導的。就好像兩台電腦能夠發送資料,我們用不着知道他們是通過無線Wifi、光纖還是銅線電纜傳輸的。
當有需要時,自然需要用~ 廢話少說,先簡單操作 HttpContext 了解下。后面接着解析這個對象。
如果你不需要練習,請直接跳過這一節內容。
- 打開 VS(2017)
- 新建項目
- ASP.NET Core Web 應用程序
- Web應用程序(模型視圖控制器)
- 打開 Startup.cs ,在 ConfigureServices 中,加上
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); //先不用管這個是干嘛的

- 打開 HomeController.cs ,在頂部 using Microsoft.AspNetCore.Http; 把 HomeController 類替換成以下代碼
public class HomeController : Controller { private IHttpContextAccessor _accessor; public HomeController(IHttpContextAccessor accessor) { _accessor = accessor; } [HttpGet] public IActionResult Index(int? id) { var httpcontext = _accessor.HttpContext; return View(httpcontext); } }
-
打開 Views/Home 目錄,刪除除 Index.cshtml 外的其它視圖
- 把 Index.cshtml 的代碼改成
@model Microsoft.AspNetCore.Http.HttpContext @{ Layout = null; }
到這里,准備已經完成。
以上代碼的作用是把 HttpContext 對象 傳遞到 視圖 中,直接在視圖中使用。這樣我們在理解時,只需在視圖測試即可。
HttpContext 類型的屬性和方法
在 ASP.NET Core 中,系統為每一個請求分配一個線程,HttpContext 針對的,就是一個線程。所以它的類、方法、屬性等,都是針對當前請求起作用。
Properties(特性)
| Authentication | 這個已經用不到了,這里只是列一下表。 用於身份認證(ASP.NET中用到),官方不建議在ASP.NT Core中使用。替代方案 Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions |
| Connection | 獲取有關此請求的基礎連接的信息 |
| Features | 獲取此請求上可用的服務器和中間件提供的HTTP特性的集合 |
| Items | 獲取或設置可用於在該請求范圍內共享數據的鍵/值集合 |
| Request | 請求 |
| RequestAborted | 通知此請求基礎的連接何時中止,因此請求操作應取消 |
| RequestServices | 獲取或設置 IServiceProvider 集合,提供訪問的請求的服務容器 |
| Response | 響應 |
| Session | 獲取或設置用於管理此請求的用戶會話數據的對象 |
| TraceIdentifier | 獲取或設置用於在跟蹤日志中表示此請求的唯一標識符 |
| User | 獲取或設置此請求的用戶 |
| WebSockets | 獲取一個對象,該對象管理此請求的WebSu套連接的建立 |
Item、Session、Response 等對象都是需要經常使用到的,下面筆者會詳細實踐。
HttpContext 對象實踐與測試
Request
用於獲取用戶請求的對象,瀏覽器向Web程序提交表單、訪問的URL、URL中包含的查詢字符串、報文請求頭等等。
| Body | 獲取或設置 RequestBody 流 |
| ContentLength | 獲取或設置 Content-Length 頭 |
| ContentType | 獲取或設置Content-Type 頭 |
| Cookies | 獲取或設置 Cookies |
| Form | 獲取或設置 表單內容 |
| HasFormContentType | Checks the Content-Type header for form types. |
| Headers | Gets the request headers. |
| Host | 獲取或設置主機頭。可以包括端口 |
| HttpContext | 獲取或設置請求上下文 |
| IsHttps | 檢測當前是否HTTPS連接 |
| Method | 獲取或設置HTTP方法 |
| Path | 獲取或設置當前請求的路徑,即URL |
| PathBase | 獲取或設置 RequestPathBase,就是URL前面那一段,如https://docs.microsoft.com |
| Protocol | Gets or sets the RequestProtocol. |
| Query | 查詢字符串的集合 |
| QueryString | 獲取或設置用於在Request.Query中創建查詢集合的原始查詢字符串 |
| Scheme | 獲取或設置HTTP請求方案 |
試一試
打開 Index.Cshtml ,把以下代碼加上去
(為了看得清楚一點,我加了表格)
<table>
<tr>
<td>RequestBody流</td>
<td> @Model.Request.Body</td>
</tr>
<tr>
<td>Content-Length頭</td>
<td>@Model.Request.ContentLength</td>
</tr>
<tr>
<td>Content-Type頭</td>
<td> @Model.Request.ContentType</td>
<tr>
<td>Cookies </td>
<td>@Model.Request.Cookies</td>
</tr>
<tr>
<td>IsHttps</td>
<td>@Model.Request.IsHttps</td>
</tr>
<tr>
<td>Host </td>
<td>@Model.Request.Host</td>
</tr>
</table>
運行Web程序,結果如下

在瀏覽器 F12 后,可以看到控制台的內容。請查看 下圖的 1、3部分

Request 的其它使用方法,就不再贅述,你可以在視圖中 @Model.Request. 加上需要測試的屬性即可。
推薦別人關於 Request 的文章 https://www.cnblogs.com/Sea1ee/p/7240943.html
Response
Request 是 客戶端向 Web 發送請求,而 Response 則是 Web 響應 客戶端 的請求。這里筆者就不全部翻譯了
使用Response可以直接影響服務器響應,設置響應內容、響應類型(發送網頁、文件、圖片等)、視圖響應前重定向。
Response 應該在控制器中使用。具體使用方法筆者這里就不贅述。
| Body | 獲取或設置響應體流 |
| ContentLength | Gets or sets the value for the |
| ContentType | 獲取或設置內容類型響應標頭的值 |
| Cookies | 獲取一個對象,該對象可用於管理此響應的Cookie |
| HasStarted | Gets a value indicating whether response headers have been sent to the client. |
| Headers | Gets the response headers. |
| HttpContext | Gets the HttpContext for this response. |
| StatusCode | Gets or sets the HTTP response code. |
Response 的方法
| OnCompleted(Func<Task>) |
在響應已發送到客戶端之后添加要調用的委托 |
| OnCompleted(Func<Object,Task>, Object) | 響應已發送到客戶端之后添加要調用的委托 |
| OnStarting(Func<Task>) | 在響應頭將被發送到客戶端之前添加要調用的委托 |
| OnStarting(Func<Object,Task>, Object) | 在響應頭將被發送到客戶端之前添加要調用的委托 |
| Redirect(String) | 向客戶端返回一個臨時重定向響應(HTTP 302) |
| Redirect(String, Boolean) | 向客戶端返回重定向響應(HTTP 301或HTTP 302) |
| RegisterForDispose(IDisposable) | 處置(不可分)在請求完成處理后,注冊主機處理的對象 |
Response 拓展方法
| GetTypedHeaders(HttpResponse) | |
| WriteAsync(HttpResponse, String, Encoding, CancellationToken) | 取消令牌使用給定的編碼將給定文本寫入響應體 |
| WriteAsync(HttpResponse, String, CancellationToken) | 將給定文本寫入響應體。UTF-8編碼將被使用 |
| Clear(HttpResponse) | |
| SendFileAsync(HttpResponse, IFileInfo, Int64, Nullable<Int64>, CancellationToken) | 使用Sendfile 擴展發送給定的文件 |
| SendFileAsync(HttpResponse, IFileInfo, CancellationToken) | Sends the given file using the SendFile extension. |
| SendFileAsync(HttpResponse, String, Int64, Nullable<Int64>, CancellationToken) | Sends the given file using the SendFile extension. |
| SendFileAsync(HttpResponse, String, CancellationToken) | Sends the given file using the SendFile extension. |
Item
如果你使用過 ViewData,就不難理解 HttpContext.Item
HttpContext.Item 是一個字典集合類型,具體類型為 IDictionary<TModel,TModel>。它的使用方法像 ViewData。(不要跟我說說你不知道 ViewBag、ViewData 是什么~)
打開 Index.Cshtml ,用下面代碼復制替換
@model Microsoft.AspNetCore.Http.HttpContext @{ Layout = null; } @{ List<string> i = new List<string>(); i.Add("a"); i.Add("b"); i.Add("c"); i.Add("d"); i.Add("e"); i.Add("f"); i.Add("g"); i.Add("h"); i.Add("i"); Model.Items["Test"] = i; /* Model.Items 是字典類型 這里設置 鍵 Test 值 i ,它的值是 List<string> 類型 */ foreach(var item in Model.Items["Test"] as List<string>) //字典類型,必須先用 as 轉為對應類型 { <br> @item } }
結果

可以用 HttpContext.Item 來存儲當前請求的意向有用的數據。
HttpContext 的其它方法使用這里不再贅述,需要注意的是,HttpContext 是針對一個請求的而產生的。
