1. 程式人生 > >Asp.Net Core學習筆記:入門篇

Asp.Net Core學習筆記:入門篇

# Asp.Net Core 學習 基於.Net Core 2.2版本的學習筆記。 ## 常識 像Django那樣自動檢查程式碼更新,自動過載伺服器(太方便了) ``` dotnet watch run ``` ## 託管設定 設定專案檔案的`AspNetCoreHostingModel`屬性。 ```xml netcoreapp2.2 InProcess ``` - InProcess:使用IIS伺服器託管 - OutOfProcess:使用自帶Kestrel伺服器託管 ## 中介軟體入門 - 可同時被訪問和請求 - 可以處理請求後,將請求傳遞給下一個中介軟體 - 可以處理請求後,使管道短路 - 可以傳出響應 - 中介軟體是按照新增順序執行的 通過在`Configure`中新增引數`ILogger logger`引入Asp.Net Core自帶的日誌元件。 ```c# public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger logger) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.Use(async (context, next) => { context.Response.ContentType = "text/plain;charset=utf-8"; //await context.Response.WriteAsync("Hello!"); logger.LogDebug("M1: 傳入請求"); await next(); logger.LogDebug("M1: 傳出響應"); }); app.Use(async (context, next) => { context.Response.ContentType = "text/plain;charset=utf-8"; logger.LogDebug("M2: 傳入請求"); await next(); logger.LogDebug("M2: 傳出響應"); }); app.Run(async (context) => { //await context.Response.WriteAsync("你好!"); await context.Response.WriteAsync("M3: 處理請求,生成響應"); logger.LogDebug("M3: 處理請求,生成響應"); }); } ``` 輸出日誌:(可以看到三個中介軟體的執行過程) ``` Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/2.0 GET https://localhost:44383/ StudyManagement.Startup:Debug: M1: 傳入請求 StudyManagement.Startup:Debug: M2: 傳入請求 StudyManagement.Startup:Debug: M3: 處理請求,生成響應 StudyManagement.Startup:Debug: M2: 傳出響應 StudyManagement.Startup:Debug: M1: 傳出響應 Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 52.8954ms 200 text/plain;charset=utf-8 StudyManagement.Startup:Debug: M1: 傳入請求 StudyManagement.Startup:Debug: M2: 傳入請求 StudyManagement.Startup:Debug: M3: 處理請求,生成響應 StudyManagement.Startup:Debug: M2: 傳出響應 StudyManagement.Startup:Debug: M1: 傳出響應 Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 34.3387ms 200 text/plain;charset=utf-8 ``` ## 靜態檔案支援 所有靜態檔案都在目錄`wwwroot`下 ### 首先 ```c# // 設定預設檔案 // 不設定的話,預設就是index.html/default.html這幾個 var defaultFileOpinions = new DefaultFilesOptions(); defaultFileOpinions.DefaultFileNames.Clear(); defaultFileOpinions.DefaultFileNames.Add("test.html"); // 新增預設檔案中介軟體,必須在UseStaticFiles之前註冊 app.UseDefaultFiles(defaultFileOpinions); // 新增靜態檔案中介軟體 app.UseStaticFiles(); ``` ### DirectoryBrowser 中介軟體 可以在瀏覽器瀏覽 `wwwroot` 下的內容。不推薦在生產環境中使用。 ```c# app.UseDirectoryBrowser(); ``` ### FileServer 中介軟體 集成了`UseDefaultFiles`, `UseStaticFiles`, `UseDirectoryBrowser`三個中介軟體的功能。同樣不推薦在生產環境中使用。 ```c# var fileServerOpinions = new FileServerOptions(); fileServerOpinions.DefaultFilesOptions.DefaultFileNames.Clear(); fileServerOpinions.DefaultFilesOptions.DefaultFileNames.Add("test.html"); app.UseFileServer(fileServerOpinions); ``` ## 開發者異常頁面 ```c# if (env.IsDevelopment()) { var developerExceptionPageOptions = new DeveloperExceptionPageOptions(); // 顯示程式碼行數 developerExceptionPageOptions.SourceCodeLineCount = 10; app.UseDeveloperExceptionPage(); } app.Run(async (context) => { throw new Exception("自己丟擲的異常"); }); ``` ## 開發環境變數 - Development:開發環境 - Staging:演示(模擬、臨時)環境 - Production:正式(生產)環境 Ops: - 使用`ASPNETCORE_ENVIRONMENT`環境變數設定開發環境。 - 在開發機上,在`launchSettings.json`檔案中設定環境變數。 - 在Staging和Production環境時,儘量在作業系統設定環境變數。 - 使用`IHostEnvironment`服務訪問執行時環境 - 除了標準環境之外還支援自定義環境(UAT、QA等) ## 引入MVC框架 ### 首先新增MVC服務。 ```c# public void ConfigureServices(IServiceCollection services) { // 單純引入核心MVC服務,只有核心功能 services.AddMvcCore(); // 一般用這個,功能多 services.AddMvc(); } ``` ### 新增中介軟體 ```c# public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger logger) { if (env.IsDevelopment()) { var developerExceptionPageOptions = new DeveloperExceptionPageOptions(); // 顯示程式碼行數 developerExceptionPageOptions.SourceCodeLineCount = 10; app.UseDeveloperExceptionPage(); } app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); } ``` MVC路由規則:`/控制器名稱/方法名稱`,(不區分大小寫) 例如下面例子的路由是:`/home/index` ### HomeController程式碼: ```c# public class HomeController : Controller { public string Index() { return "home controller"; } } ``` ## 初步瞭解模型和依賴注入 ### 定義模型 ```c# public class Student { public int Id { get; set; } public string Name { get; set; } public string ClassName { get; set; } public string Email { get; set; } } ``` ### 定義介面 ```c# public interface IStudentRepository { Student GetById(int id); void Save(Student student); } ``` ### 實現介面 目前還沒接入資料庫,定義一個假資料的類 ```c# public class MockStudentRepository : IStudentRepository { private List _students; public MockStudentRepository() { _students = new List { new Student { Id=1, Name="小米", ClassName="紅米", Email="[email protected]" }, new Student { Id=2, Name="華為", ClassName="榮耀", Email="[email protected]" }, new Student { Id=3, Name="oppo", ClassName="vivo", Email="[email protected]" }, }; } public Student GetById(int id) { return _students.FirstOrDefault(a => a.Id == id); } public void Save(Student student) => throw new NotImplementedException(); } ``` ### 註冊依賴注入 Asp.Net Core依賴注入容器註冊服務有三種 - AddSingleton - AddTransient - AddScoped 依賴注入的優點 - 低耦合 - 高測試性,更加方便進行單元測試 ```c# public void ConfigureServices(IServiceCollection services) { services.AddMvc(); // 註冊依賴注入,將實現類與介面繫結 services.AddSingleton(); } ``` ### 在模型中使用依賴注入 ```c# public class StudentController : Controller { private readonly IStudentRepository _studentRepository; // 通過建構函式注入的方式注入 IStudentRepository public StudentController(IStudentRepository studentRepository) { _studentRepository = studentRepository; } public JsonResult Index(int id) { return Json(_studentRepository.GetById(id)); } } ``` ## 控制器入門 ### 內容格式協商 在控制器方法中使用 `ObjectResult` 返回型別,支援內容協商,根據請求頭引數返回資料, ```c# // 支援內容格式協商 public ObjectResult Details(int id) { return new ObjectResult(_studentRepository.GetById(id)); } ``` 如: ``` Accept: application/xml ``` 將返回xml格式。注:還要新增xml序列化器。 ```c# public void ConfigureServices(IServiceCollection services) { services.AddMvc() // 註冊XML序列化器 .AddXmlSerializerFormatters(); } ``` ## 檢視入門 ### 將資料從控制器傳遞到檢視的方法 前兩種都是弱型別的 - ViewData - ViewBag - 強型別檢視 ### ViewData - 弱型別字典物件 - 使用string型別的鍵值,儲存和chaxun - 執行時動態解析 - 沒有智慧感知,編譯時也沒有型別檢查 使用方法: ```c# ViewData["Title"] = "學生檢視"; ViewData["Model"] = model; ``` cshtml程式碼: ```scss

@ViewData["Title"]

@{ var student = ViewData["model"] as StudyManagement.Models.Student; } 姓名:@student.Name 班級:@student.ClassName ``` ### ViewBag ```c# // 直接給動態屬性賦值 ViewBag.PageTitle = "ViewBag標題"; ViewBag.Student = model; ``` cshtml使用: ```html

@ViewBag.PageTitle

姓名:@ViewBag.Student.Name 班級:@ViewBag.Student.ClassName ``` ### 強型別檢視 在控制器中傳給View()模型 ```c# public IActionResult GetView() { var model = _studentRepository.GetById(1); return View(model); } ``` 在cshtml中指定模型型別 ```scss @model StudyManagement.Models.Student

強型別模型

  • @Model.Id
  • @Model.Name
  • @Model.ClassName
  • @Model.Email
``` ## ViewModel 檢視模型 類似於DTO(資料傳輸物件) ### 定義ViewModel ```c# public class StudentDetailsViewModel { public Student Student { get; set; } public string PageTitle { get; set; } } ``` ### 修改控制器 ```c# public IActionResult Details() { var model = _studentRepository.GetById(1); var viewModel = new StudentDetailsViewModel { Student = model, PageTitle = "viewmodel裡的頁面標題" }; return View(viewModel); } ``` ### 在View中使用 ```scss @model StudyManagement.ViewModels.StudentDetailsViewModel

強型別模型

@Model.PageTitle

  • @Model.Student.Id
  • @Model.Student.Name
  • @Model.Student.ClassName
  • @Model.Student.Email
``` ### View中使用迴圈 ```scss @model IEnumerable @foreach (var student in Model) { }
Id 姓名 班級 郵箱
@student.Id @student.Name @student.ClassName @student.Email
``` ## 佈局檢視 LayoutView ### 建立佈局檢視 ```scss @ViewBag.Title @RenderBody() @RenderSection("Scripts", required: false) ``` ### 渲染檢視 ```scss @model IEnumerable @{ Layout = "~/Views/Shared/_Layout.cshtml"; ViewBag.Title = "首頁 學生列表"; } ``` ### 檢視節點 Section 在佈局視圖裡渲染節點 ```scss @RenderSection("Scripts", required: false) ``` 在普通視圖裡定義節點 ```scss @section Scripts{ } ``` ### 檢視開始 ViewStart 我的理解就是`_ViewStart.cshtml`檔案所在目錄下的每個檢視檔案開始渲染先執行這個檔案的內容。一般直接放在`Views`目錄下,全域性生效,可以放在各個子資料夾下,這樣可以覆蓋全域性的`_ViewStart.cshtml`。 ```scss @{ Layout = "_Layout"; } ``` ### 檢視匯入 ViewImports 用來匯入名稱空間、註冊模型等等n多種操作。 生效機制和ViewStart差不多。 ## 路由 - 常規路由(傳統路由) - 屬性路由 ### 常規路由 在`MapRoute`方法中傳入就好了。 ```c# // 自定義路由 app.UseMvc(route =>route.MapRoute("default", "{controller=Home}/{action=Index}/{id?}")); ``` ### 屬性路由 比傳統路由更加靈活,可以搭配傳統路由使用。 即在控制器方法上新增路由註解,一個方法可以同時對映多個路由。 ```c# [Route("Home/Index")] public IActionResult Index() { return View(_studentRepository.GetAll()); } ``` 路由中也可以指定引數 ```c# [Route("test/{id?}")] public IActionResult Details(int id = 1) { var model = _studentRepository.GetById(id); var viewModel = new StudentDetailsViewModel { Student = model, PageTitle = "viewmodel裡的頁面標題" }; return View(viewModel); } ``` 可以直接在控制器類上加註解,`[controller]/[action]`。 ## 歡迎交流 交流問題請在微信公眾號後臺留言,每一條資訊我都會回覆哈~ - 微信公眾號:畫星星高手 - 打程式碼直播間:[https://live.bilibili.com/11883038](https://live.bilibili.com/11883038) - 知乎:[https://www.zhihu.com/people/dealiaxy](https://www.zhihu.com/people/dealiaxy) - 專欄:[https://zhuanlan.zhihu.com/deali](https://zhuanlan.zhihu.co