隨著技術的發展,ASP.NET Core MVC也推出了好長時間,經過不斷的版本更新迭代,已經越來越完善,本系列文章主要講解ASP.NET Core MVC開發B/S系統過程中所涉及到的相關內容,適用於初學者,在校畢業生,或其他想從事ASP.NET Core MVC 系統開發的人員。 經過前幾篇文章... ...
隨著技術的發展,ASP.NET Core MVC也推出了好長時間,經過不斷的版本更新迭代,已經越來越完善,本系列文章主要講解ASP.NET Core MVC開發B/S系統過程中所涉及到的相關內容,適用於初學者,在校畢業生,或其他想從事ASP.NET Core MVC 系統開發的人員。 經過前幾篇文章的講解,初步瞭解ASP.NET Core MVC項目創建,啟動運行,以及命名約定,創建控制器,視圖,模型,接收參數,傳遞數據,路由,頁面佈局,wwwroot和客戶端庫,Razor語法,EnityFrameworkCore與資料庫等內容,今天繼續講解ASP.NET Core MVC 中HttpContext等相關內容,僅供學習分享使用。
什麼是HttpContext?
在B/S模式開發的程式中,客戶端是瀏覽器,伺服器端Web服務程式,HttpContext是連接客戶端和伺服器端程式的橋梁,交代了當前請求的環境信息,它封裝了請求[Request]和響應[Response]及其他所有信息,示意圖如下所示:
圖一 內網訪問程式
圖二 反向代理訪問程式
在示意圖中,Kestrel 是一個基於 libuv 的跨平臺ASP.NET Core web伺服器。不清楚 Kerstrel 沒關係,以後慢慢瞭解。
註意:HttpContext從客戶端發起一個請求開始,到伺服器端響應完成結束,每一個新的請求,都會創建一個新的HttpContext對象。
HttpContext屬性
在HttpContext中,最常用的屬性有3個【Request,Response,Session】具體屬性如下表所示:
控制器中應用HttpContext
在控制器中,HttpContext作為控制器父類ControllerBase的屬性存在,且Request和Response作為使用頻率非常高的常用對像,控制器也聲明成了屬性,都可以直接使用。如下所示:
控制器外使用HttpContext
在應用程式中,控制器繼承了Controller類,所以才能不用聲明就可以直接使用HttpContext,但是除了控制器,還在其他的程式,那在其他程式中,如何使用HttpContext呢?
首先有一個服務介面IStudentService和服務實現類StudentService,其他中在StudentService中訪問HttpContext,如下所示:
1 namespace DemoCoreMVC.Services 2 { 3 public interface IStudentService 4 { 5 /// <summary> 6 /// 保存類 7 /// </summary> 8 void Save(); 9 } 10 } 11 12 namespace DemoCoreMVC.Services 13 { 14 public class StudentService : IStudentService 15 { 16 private readonly IHttpContextAccessor contextAccessor; 17 18 public StudentService(IHttpContextAccessor contextAccessor) 19 { 20 this.contextAccessor = contextAccessor; 21 } 22 23 public void Save() 24 { 25 var name = this.contextAccessor.HttpContext?.Request.Query["Name"]; 26 Console.WriteLine(name); 27 } 28 } 29 }
在控制器中,通過構造函數的方式將IStudentService註入進去,如下所示:
1 using DemoCoreMVC.Services; 2 using Microsoft.AspNetCore.Mvc; 3 4 namespace DemoCoreMVC.Controllers 5 { 6 public class StudentController : Controller 7 { 8 private readonly IStudentService studentService; 9 10 public StudentController(IStudentService studentService) 11 { 12 this.studentService = studentService; 13 } 14 15 public IActionResult Save() 16 { 17 studentService.Save(); 18 return Json("成功"); 19 } 20 21 public IActionResult Index() 22 { 23 return View(); 24 } 25 } 26 }
在Program.cs中,將服務添加到容器中,如下所示:
1 //增加一個預設的HttpContextAccessor 2 builder.Services.AddHttpContextAccessor(); 3 //增加服務 4 builder.Services.AddScoped<IStudentService, StudentService>();
經過以上3步,就可以實現在控制器之外的類中,訪問HttpContext,測試示例,如下所示:
註意:在ASP.NET Core MVC項目中,對象的創建,優先從容器中獲取,這樣可以不需要考慮它的創建過程和構造參數。如:創建服務Service,控制器對象Controller,視圖對象View,數據訪問層Repository等內容。對於模型對象,如視圖模型,數據模型等不依賴其他對象的類型,則可以通過New進行創建。
HttpRequest
HttpRequest表示單個請求的傳入端,常用的Query用於獲取Get請求傳遞的參數,Form用於獲取Post請求傳遞的參數,如下所示:
HttpRequest示例
在本示例中,以Request.Form為例,獲取Post方式傳遞的參數,客戶端將所有需要傳遞的內容包括在Form表單內容,在伺服器端Action中通過Request.Form["Key"]進行獲取。如下所示:
Add.cshtml視圖中Form表單內容,如下所示:
1 <form action="~/Hello/Save" method="post"> 2 <div style="margin:10px;"> 3 <span>學號:</span> 4 <input type="text" name="Id" /> 5 </div> 6 <div style="margin:10px;"> 7 <span>姓名:</span> 8 <input type="text" name="Name" /> 9 </div style="margin:10px;"> 10 <div style="margin:10px;"> 11 <span>年齡:</span> 12 <input type="text" name="Age" /> 13 </div> 14 <div style="margin:10px;"> 15 <span>性別:</span> 16 <input type="text" name="Sex" /> 17 </div> 18 <div style="margin:10px;"> 19 <input type="submit" name="submit" value="保存" /> 20 </div> 21 </form>
HelloController中Save方法,如下所示:
1 [HttpPost] 2 public IActionResult Save() 3 { 4 5 var id = Request.Form["Id"]; 6 var name = Request.Form["Name"]; 7 var age = Request.Form["Age"]; 8 var sex = Request.Form["Sex"]; 9 var student = new Student() 10 { 11 Id = string.IsNullOrEmpty(id) ? 0 : int.Parse(id), 12 Name = name, 13 Age = string.IsNullOrEmpty(age) ? 0 : int.Parse(age), 14 Sex = sex 15 }; 16 return Json(student); 17 }
運行測試,在瀏覽器中輸入網址【https://localhost:7116/Hello/add】進行測試,如下所示:
HttpRequest其它示例
HttpRequest中的其它示例,如下所示:
1 public IActionResult Index() 2 { 3 Console.WriteLine($"Request.Host:{Request.Host}" ); 4 Console.WriteLine($"Request.Path:{Request.Path}"); 5 Console.WriteLine($"Request.Protocol:{Request.Protocol}"); 6 Console.WriteLine($"Request.ContentType:{Request.ContentType}"); 7 Console.WriteLine($"Request.Headers:"); 8 foreach(var header in Request.Headers) 9 { 10 Console.WriteLine($"{header.Key}:{header.Value}"); 11 } 12 Console.WriteLine($"Request.Cookies:"); 13 foreach (var cookie in Request.Cookies) 14 { 15 Console.WriteLine($"{cookie.Key}:{cookie.Value}"); 16 } 17 return View(); 18 }
其它屬性示例截圖,如下所示:
註意:在Request的Get請求中,預設ContentType為空,Cookies如果沒有設置,也為空。
Cookie存放於客戶端瀏覽器中,可以通過瀏覽器開發者模式F12下進行查看,以www.bilibili.com為例,如下所示:
HttpResponse
HttpResponse表示單個請求的傳出內容,
狀態碼StatusCode
StatusCode是一個int類型,表示當前響應Http請求的狀態,可以通過System.Net.HttpStatusCode(枚舉)進行轉換,常用的有以下幾種:
- OK = 200,成功,這是最常用的一個響應狀態碼
- NotFound = 404, 未發現,即請求的信息不存在
- InternalServerError = 500,伺服器內部錯誤
- Redirect = 302, 請求已被重定向
在Controller中,常見的狀態碼返回值,以被定義為方法,如:Ok(),NotFound()等,可以直接調用。
HttpResponse示例
在響應的Headers中,添加Author信息,如下所示:
1 public IActionResult Test2() 2 { 3 Response.Headers.Add("Author", "公子小六"); 4 return Json("ABC"); 5 }
在添加Headers時,如果是漢字,則會報下麵一個錯誤,如下所示:
以上錯誤表示編碼錯誤,漢字無效,需要進行編碼轉換,如下所示:
1 public IActionResult Test2() 2 { 3 var author = HttpUtility.UrlEncode("公子小六", Encoding.UTF8); 4 Response.Headers.Add("Author", author); 5 return Json("ABC"); 6 }
請求示例如下所示:
會話Session
由於Http請求是無狀態的,單次請求完成後,就會進行釋放,那麼如何在無狀態的請求中,保留一些相關的數據呢?這就用到了Session,Session在用戶打開瀏覽器登錄系統開始,到關閉瀏覽器退出系統結束,將用戶請求的一些數據,以鍵值對的形式保存在伺服器端的緩存中,可以解決無狀態協議模式下數據的頻繁傳遞傳遞,減少請求數據量,提高性能。Session一般應用在小型的單體應用程式中,對於大型的分散式程式,則不適用。
每一個用戶的瀏覽器請求都有自己的Session記憶體塊,不會和其他用戶的請求相混淆。
要啟用Session,首先需要在Program.cs中添加Session服務,和啟用Session中間件,如下所示:
1 using DemoCoreMVC.Services; 2 using Microsoft.AspNetCore.Server.Kestrel.Core; 3 using System.Text.Encodings.Web; 4 using System.Text.Unicode; 5 6 var builder = WebApplication.CreateBuilder(args); 7 8 // Add services to the container. 9 builder.Services.AddControllersWithViews().AddJsonOptions(options => 10 { 11 options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); 12 }); 13 14 builder.Services.Configure<KestrelServerOptions>(options => 15 { 16 options.AllowSynchronousIO = true; 17 }); 18 19 //1. 往容器中添加Session服務,啟用Session服務 20 builder.Services.AddSession(); 21 22 var app = builder.Build(); 23 24 // Configure the HTTP request pipeline. 25 if (!app.Environment.IsDevelopment()) 26 { 27 app.UseExceptionHandler("/Home/Error"); 28 // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 29 app.UseHsts(); 30 } 31 32 //2.使用Session中間件,主要用於攔截Http請求 33 app.UseSession(); 34 app.UseHttpsRedirection(); 35 app.UseStaticFiles(); 36 37 //1. 添加路由中間件EndpointRoutingMiddleware 38 app.UseRouting(); 39 app.MapControllers(); 40 app.UseAuthorization(); 41 42 app.MapControllerRoute( 43 name: "default", 44 pattern: "{controller=Home}/{action=Index}/{id?}"); 45 46 47 app.Run();
Session屬性和方法
在實際應用中,一般使用擴展方法SetString(key,value),GetString(key)進行Session值的設置和獲取,如下所示:
註意,關於Session使用,有以下兩點需要註意:
- 在控制器中,可以直接使用Session屬性
- 在非控制器中,可以使用請求上下文HttpContext進行獲取。
Session示例
以常用的登錄為例,實現如下功能:
- 用戶打開登錄頁面,輸入賬號密碼,點擊登錄按鈕
- 驗證用戶名密碼,驗證成功後,保存Session,跳轉到首頁
- 首頁獲取Session中保存的內容,並通過ViewBag傳遞到客戶端,顯示在頁面上。
首先創建控制器LoginController,如下所示:
1 namespace DemoCoreMVC.Controllers 2 { 3 public class LoginController : Controller 4 { 5 public IActionResult Index() 6 { 7 return View(); 8 } 9 10 public IActionResult Login() 11 { 12 var username = Request.Form["username"]; 13 var password = Request.Form["password"]; 14 if(username=="admin" && password == "abc123") 15 { 16 HttpContext.Session.SetString("username", username); 17 } 18 return Redirect("/Home"); 19 } 20 } 21 }
然後創建Login/Index.cshtml視圖,如下所示:
1 <form action="~/Login/Login" method="post"> 2 <div style="margin:10px;"> 3 <span style="display:inline-block; width:80px;">用戶名:</span> 4 <input type="text" name="username" /> 5 </div> 6 <div style="margin:10px;"> 7 <span style="display:inline-block;width:80px;">密 碼:</span> 8 <input type="password" name="password" /> 9 </div style="margin:10px;"> 10 <div style="margin:10px;"> 11 <input type="submit" name="submit" value="登錄" /> 12 </div> 13 </form>
修改HomeController中代碼,如下所示:
1 public class HomeController : Controller 2 { 3 4 public HomeController() 5 { 6 } 7 8 public IActionResult Index() 9 { 10 var username = HttpContext.Session.GetString("username"); 11 ViewBag.Username = username; 12 return View(); 13 } 14 }
Home/Index.cshtml中修改代碼,獲取ViewBag傳遞的值,如下所示:
1 <div class="text-center"> 2 <h1 class="display-4">Welcome @ViewBag.Username</h1> 3 <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p> 4 </div>
以上就是Session示例的創建和獲取的相關代碼,頁面測試如下所示:
Session唯一標識
每一個瀏覽器打開的Session都有一個唯一標識,在控制器中,可以通過HttpContext.Session.Id進行區分。可以在Program.cs中添加服務到容器時配置相關參數,如下所示:
1 //1. 往容器中添加Session服務,啟用Session服務 2 builder.Services.AddSession(option => 3 { 4 option.IdleTimeout = TimeSpan.FromMinutes(10); 5 option.Cookie.Name = "DemoMvcCore"; 6 });
設置Session選項中的Cookie的名稱後,會在瀏覽器客戶端創建對應的值,如下所示:
參考文章
本篇文章主要參考內容如下:
1. https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.http.httpcontext?view=aspnetcore-7.0
2. https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.http.httprequest?view=aspnetcore-7.0
3. https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.http.httpresponse?view=aspnetcore-7.0
4. https://learn.microsoft.com/zh-cn/dotnet/api/microsoft.aspnetcore.http.isession?view=aspnetcore-7.0
以上就是ASP.NET Core MVC從入門到精通之HttpContext的全部內容。
作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文版權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段聲明,且在文章頁面明顯位置給出原文連接,謝謝。
關註個人公眾號,定時同步更新技術及職場文章