本章將和大家分享ASP.NET Core MVC的一些基礎知識,包括Action接收引數、Action向視圖傳值、常用過濾器的使用、布局頁、分部視圖、視圖組件ViewComponent的使用以及在視圖中如何匯入公共命名空間等,希望通過本文的分享能夠對初學者有所幫助,下面我們直接進入主題,
首先來看一下我們的解決方案:

本Demo的Web專案為ASP.NET Core Web 應用程式(目標框架為.NET Core 3.1) MVC專案,
1、Action接收引數及Action向視圖傳值
下面直接通過代碼加注釋的方式來講解:
Home控制器:
using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Http; using MvcDemo.Models; using MvcDemo.Attributes; namespace MvcDemo.Controllers { public class HomeController : BaseController { private readonly ILogger<HomeController> _logger; public HomeController(ILogger<HomeController> logger) { _logger = logger; } //Action接收引數方式1 //id 指的是路由中的占位符{id},如果有值則id就是那個值 //myId是URL中的值或者表單中name=myId的那個值 public async Task<IActionResult> Index(int? id, int? myId) { Console.WriteLine($"執行緒{Thread.CurrentThread.ManagedThreadId}開始執行 => This is Home/Index Action"); await Task.Delay(1000); Console.WriteLine($"執行緒{Thread.CurrentThread.ManagedThreadId}執行結束 => This is Home/Index Action"); //Action接收引數方式2 //var value1 = Request.Query["myId"]; //var value2 = Request.Form["myId"]; //var value3 = Request.Form["name"].ToArray(); //接收多個值 //var value4 = RouteData.Values["id"]; //獲取路由占位符的值 var listStu = new List<Student>(){ new Student(){ Name = "張三", Sex = "男", Age = 16 }, new Student(){ Name = "李四", Sex = "男", Age = 17 }, new Student(){ Name = "小美", Sex = "女", Age = 18 } }; //Action向View傳值的4種方式 //ViewData["鍵"] = 值; 此方式View在接收Action傳過去的值時 //1、如果是字串或者是數值型則可以直接使用,否則需要轉換成對應的型別再進行處理 ViewData["Stu"] = listStu[0]; //2、ViewBag 動態型別,ViewBag底層用的是ViewData,所以這2個是相通的,設定其中一個值后另外一個也就有值了 ViewBag.Title = "Home Index Page"; ViewBag.ListStu = listStu; //3、TempData["鍵"] = 值; TempData["Love"] = 520; //4、View(obj); View接收的就是Model,可以指定Model的資料型別,這樣子就可以直接使用 return View(listStu[2]); } //Action接收引數方式3 //使用物體接收post提交的引數 public IActionResult MyLayoutDemo(Student stu) { return View(); } /// <summary> /// 分部視圖Demo /// 分部視圖微軟官方檔案:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/partial?view=aspnetcore-5.0 /// </summary> /// <returns></returns> public IActionResult MyPartialDemo() { ViewBag.Stu = new Student() { Name = "王五", Sex = "男", Age = 22 }; ViewBag.FatherViewVal = "我是來自父視圖ViewData里面的值"; return View(); } #region Ajax互動 //Action接收引數方式4 //引數串列IFormCollection物件,這種方式只能接收到表單提交的引數,該方式不常用 public async Task<JsonResult> GetListDataAsync(IFormCollection form) { var myId = form["myId"].ToString(); await Task.Delay(500); var result = new { code = 1, total = 10, data = new Student() { Id = myId, Name = "錢七", Sex = "男", Age = 22 }, msg = "獲取成功" }; return Json(result); } #endregion Ajax互動 } }
對應的Home/Index視圖:
@{ Layout = null; var value = https://www.cnblogs.com/xyh9039/p/"15345678910"; if (value.IsMobile()) { Console.WriteLine("This is Home/Index View"); } } @* 給Model指定資料型別 *@ @model Student @{ Student stu = ViewData["Stu"] as Student; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewData["Title"]</title> </head> <body> <div> @foreach (var item in ViewBag.ListStu) { @:我是foreach <br /> @Html.Raw("我是Html.Raw<br />") <text> 我是foreach內部的text </text> <p> 姓名:@(item.Name),性別:@(item.Sex),年齡:@(item.Age) </p> <p> 我是foreach內部p標簽內的字串 </p> <hr /> } <p> 我是TempData["Love"]:@TempData["Love"] </p> <p> 我是ViewData["Stu"]:@((ViewData["Stu"] as Student).Name) </p> <p> 我是Model.Name:@Model.Name </p> <p> 我是ViewBag.ListStu[0].Name:@ViewBag.ListStu[0].Name </p> <p> 我是stu.Name:@(stu.Name) </p> </div> </body> </html>
訪問 /Home/Index 運行結果如下:

此外Action向視圖傳值還有一種特殊的情況就是匿名型別,具體的傳值方式可參考博文:https://www.cnblogs.com/xyh9039/p/11348684.html
2、 在視圖中如何匯入公共命名空間
MVC框架給我們提供了一個特殊的視圖,叫 _ViewImports.cshtml,可以在該視圖當中匯入公共命名空間,

它的作用域是_ViewImports.cshtml視圖所在的Views檔案夾下的所有視圖,
另外我們還可以看到一個特殊的視圖,叫_ViewStart.cshtml,如下圖:
其作用就是在所有的View在呈現之前都會先執行_ViewStart.cshtml里面的代碼,但是有一種特殊情況就是如果一個View是按照分部視圖方式輸出的,則不會觸發_ViewStart.cshtml里面的代碼,
3、 分部視圖
首先來看下目錄結構:

其中Action如下所示:
/// <summary> /// 分部視圖Demo /// 分部視圖微軟官方檔案:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/partial?view=aspnetcore-5.0 /// </summary> /// <returns></returns> public IActionResult MyPartialDemo() { ViewBag.Stu = new Student() { Name = "王五", Sex = "男", Age = 22 }; ViewBag.FatherViewVal = "我是來自父視圖ViewData里面的值"; return View(); }
對應的視圖如下:
其中_MyPartial.cshtml視圖:
@model Student <h2>我是_MyPartial.cshtml</h2> <p style="color:red;"> @(Model.Name),@(Model.Sex),@(Model.Age) <br /> @ViewBag.Name <br /> @ViewData["Name"] <br /> @ViewBag.FatherViewVal </p>
其中MyPartialDemo.cshtml視圖:
@{ Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>MyPartialDemo</title> </head> <body> <div> <p> @* 分部視圖 *@ 我是Html.PartialAsync: @await Html.PartialAsync("_MyPartial", ViewBag.Stu as Student, new ViewDataDictionary(this.ViewData) { { "Name", "老李" } }) </p> <hr /> <p> @* 分部視圖 *@ @* 呼叫無回傳值的方法時必須放在花括號內部 *@ 我是Html.RenderPartialAsync: @{await Html.RenderPartialAsync("_MyPartial", ViewBag.Stu as Student, new ViewDataDictionary(this.ViewData) { { "Name", "老王" } });} </p> <hr /> <p> @* 視圖組件 *@ 我是Component.InvokeAsync: @await Component.InvokeAsync("StuInfo", new { id = "10086" }) </p> </div> </body> </html>
訪問 /Home/MyPartialDemo 運行結果如下:

分部視圖微軟官方檔案:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/partial?view=aspnetcore-5.0

分部視圖的視圖搜索路徑:
//按名稱(無檔案擴展名)參考分部視圖,則按所述順序搜索以下位置 //1、/Areas/<Area-Name>/Views/<Controller-Name> //2、/Areas/<Area-Name>/Views/Shared //3、/Views/Shared //4、/Pages/Shared @await Html.PartialAsync("_PartialName") //存在檔案擴展名時 //該視圖必須與呼叫分部視圖的檔案位于同一檔案夾中 @await Html.PartialAsync("_PartialName.cshtml") //從應用程式根目錄參考分部視圖 //以波形符斜杠 (~/) 或斜杠 (/) 開頭的路徑指代應用程式根目錄 @await Html.PartialAsync("~/Views/Folder/_PartialName.cshtml") @await Html.PartialAsync("/Views/Folder/_PartialName.cshtml") //參考使用相對路徑的分部視圖 @await Html.PartialAsync("../Account/_LoginPartial.cshtml")
4、視圖組件
可以看到上一步在講解分部視圖的時候里面就有呼叫了一個視圖組件
//呼叫視圖組件 @await Component.InvokeAsync("StuInfo", new { id = "10086" })
接下來我們就來看下如何實作,同樣我們先來看下目錄結構:

下面我們直接來看代碼:
視圖組件類StuInfoViewComponent.cs,名稱以ViewComponent后綴結尾:
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using MvcDemo.Models; namespace MvcDemo.ViewComponents { /// <summary> /// 學生資訊視圖組件 /// 視圖組件微軟官方檔案:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/view-components?view=aspnetcore-5.0 /// </summary> [ViewComponent(Name = "StuInfo")] //[ViewComponent] 屬性可以更改用于參考視圖組件的名稱, public class StuInfoViewComponent : ViewComponent { private readonly ILogger<StuInfoViewComponent> _logger; public StuInfoViewComponent(ILogger<StuInfoViewComponent> logger) { _logger = logger; } public async Task<IViewComponentResult> InvokeAsync(string id) { var stu = new Student { Id = id, Name = "隔壁老王", Sex = "男", Age = 32 }; #region 摘自官網 /* 視圖搜索路徑 運行時在以下路徑中搜索視圖: /Views/{Controller Name}/Components/{View Component Name}/{View Name} /Views/Shared/Components/{View Component Name}/{View Name} /Pages/Shared/Components/{View Component Name}/{View Name} */ #endregion 摘自官網 return View(stu); } } }
Default.cshtml視圖:
@* 視圖組件 *@ @model Student <h2>我是StuInfoViewComponent</h2> <div> StuId=@(Model.Id),StuName=@(Model.Name),StuAge=@(Model.Age),StuSex=@(Model.Sex) </div>
呼叫視圖組件:
//呼叫視圖組件 @await Component.InvokeAsync("StuInfo", new { id = "10086" })
視圖組件微軟官方檔案:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/view-components?view=aspnetcore-5.0
其中值得注意的是:
1、[ViewComponent] 屬性可以更改用于參考視圖組件的名稱,
2、視圖組件的默認視圖名稱為“Default”,這意味著視圖檔案通常命名為“Default.cshtml”, 可以在創建視圖組件結果或呼叫 View 方法時指定不同的視圖名稱,
3、官方建議將視圖檔案命名為 Default.cshtml 并使用 Views/Shared/Components/{View Component Name}/{View Name} 路徑,
4、視圖搜索路徑
/* 視圖搜索路徑 運行時在以下路徑中搜索視圖: /Views/{Controller Name}/Components/{View Component Name}/{View Name} /Views/Shared/Components/{View Component Name}/{View Name} /Pages/Shared/Components/{View Component Name}/{View Name} */
5、布局頁Layout
先來看下目錄結構:

下面我們直接上代碼:
_Header.cshtml視圖:
<script src=https://www.cnblogs.com/xyh9039/p/"~/js/jquery-3.6.0.min.js"></script>
_MyLayout.cshtml自定義布局頁:
@{ //指定布局頁 //默認使用 /Views/Shared/ 目錄下的_Layout布局頁 Layout = null; } <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@(ViewBag.Title)</title> @* 加載分部視圖 *@ @await Html.PartialAsync("_Header") @* 占位符寫法1 *@ @RenderSection("header", required: false) @* 占位符寫法2 *@ @await RenderSectionAsync("header2", required: false) </head> <body> <h1>我是_MyLayout.cshtml</h1> <div> @* 將來內容將填充到這里 *@ @RenderBody() </div> @RenderSection("footer", required: false) @await RenderSectionAsync("footer2", required: false) </body> </html>
為視圖MyLayoutDemo.cshtml指定布局頁:
@{ ViewBag.Title = "MyLayoutDemo"; //指定布局頁 //此發現程序與用于發現分部視圖的程序相同 //Layout = "~/Views/Shared/_MyLayout.cshtml"; //指定布局頁 Layout = "_MyLayout"; //指定布局頁 } @* 填充布局頁里面對應的占位符 *@ @section header{ <script type="text/javascript"> </script> } <h2>MyLayoutDemo</h2> @* 填充布局頁里面對應的占位符 *@ @section footer2{ <script type="text/javascript"> </script> }
訪問 /Home/MyLayoutDemo 運行結果如下:

布局頁微軟官方檔案:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/views/layout?view=aspnetcore-5.0
其中值得注意的是:
指定的布局可以使用完整路徑(例如 /Pages/Shared/_Layout.cshtml 或 /Views/Shared/_Layout.cshtml)或部分名稱(示例:_Layout),
如果提供了部分名稱, Razor 視圖引擎將使用其標準發現行程搜索布局檔案, 首先搜索處理程式方法(或控制器)所在的檔案夾,然后搜索 Shared 檔案夾,
此發現程序與用于發現分部視圖的程序相同,
6、常用過濾器的使用
老樣子,我們首先先來看下相應的目錄機構:

下面我們重點來看下基類和過濾器:
基類BaseController如下所示:
using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Diagnostics; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using MvcDemo.Attributes; namespace MvcDemo.Controllers { /// <summary> /// 自定義控制器的基類 /// </summary> public class BaseController : Controller { /// <summary> /// 是否需要登入驗證 /// </summary> protected bool IsNeedLogin = true; /// <summary> /// 在Action執行前觸發(用于讓子類重寫) /// </summary> /// <param name="context">Action執行前背景關系物件</param> protected virtual void OnSubActionExecuting(ActionExecutingContext context) { } /// <summary> /// 在Action執行前觸發(如果繼承該類的子類也重寫了該方法,則先執行子類的方法,再執行父類的方法) /// </summary> /// <param name="context">Action執行前背景關系物件</param> public override void OnActionExecuting(ActionExecutingContext context) { base.OnActionExecuting(context); OnSubActionExecuting(context); //先執行子類的 //獲取請求進來的控制器與Action var controllerActionDescriptor = context.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor; #region 【權限驗證】【登入驗證】 //獲取區域名稱 var areaName = context.ActionDescriptor.RouteValues["area"] ?? ""; areaName = (string)context.RouteData.Values["area"]; //獲取控制器名稱 var controllerName = context.ActionDescriptor.RouteValues["controller"]; controllerName = controllerActionDescriptor.ControllerName; controllerName = context.RouteData.Values["controller"].ToString(); //獲取action名稱 var actionName = context.ActionDescriptor.RouteValues["action"]; actionName = controllerActionDescriptor.ActionName; actionName = context.RouteData.Values["action"].ToString(); //獲取當前的請求方式:Get或者Post string requestMethod = context.HttpContext.Request.Method.ToLower(); //獲取路由占位符對應的值 object currId = context.RouteData.Values["id"]; //獲取當前請求URL引數 var value =https://www.cnblogs.com/xyh9039/p/ context.HttpContext.Request.Query.ContainsKey("key") ? context.HttpContext.Request.Query["key"].ToString() : ""; //獲取Action引數值 IDictionary<string, object> actionArguments = context.ActionArguments; if (actionArguments != null) { foreach (KeyValuePair<string, object> item in actionArguments) { var key = item.Key; //引數名 var val = item.Value; //引數值 } } ParamsFilter(context); //引數過濾 //判斷當前所請求的控制器上是否有打上指定的特性標簽 if (controllerActionDescriptor.ControllerTypeInfo.IsDefined(typeof(SkipLoginValidateAttribute), false)) { //有的話就不進行相關操作【例如:不進行登入驗證】 //return; } //獲取當前所請求的Action上指定的特性標簽 object[] arrObj1 = controllerActionDescriptor.MethodInfo.GetCustomAttributes(typeof(SkipLoginValidateAttribute), false); //獲取當前所請求的Action上所有的特性標簽 object[] arrObj2 = controllerActionDescriptor.MethodInfo.GetCustomAttributes(false); //判斷當前所請求的Action上是否有打上指定的特性標簽 if (controllerActionDescriptor.MethodInfo.IsDefined(typeof(SkipLoginValidateAttribute), false) || !IsNeedLogin) { //有的話就不進行相關操作【例如:不進行登入驗證】 return; } #endregion 【權限驗證】【登入驗證】 //【權限驗證】【登入驗證】邏輯 //To Do Something } #region 引數過濾 /// <summary> /// 引數過濾 /// </summary> void ParamsFilter(ActionExecutingContext context) { //獲取引數集合 var parameters = context.ActionDescriptor.Parameters; //遍歷引數集合 foreach (var param in parameters) { if (!context.ActionArguments.ContainsKey(param.Name)) { continue; } if (context.ActionArguments[param.Name] == null) { continue; } //當引數是字串 if (param.ParameterType.Equals(typeof(string))) { //業務處理 var value =https://www.cnblogs.com/xyh9039/p/ context.ActionArguments[param.Name].ToString(); context.ActionArguments[param.Name] = value.Replace(" ", ""); } else if (param.ParameterType.Equals(typeof(string[]))) //如果是字串陣列則遍歷每一個成員 { var arrStrs = context.ActionArguments[param.Name] as string[]; if (arrStrs != null && arrStrs.Length > 0) { for (int i = 0; i < arrStrs.Length; i++) { arrStrs[i] = arrStrs[i].Replace(" ", ""); //業務處理 } context.ActionArguments[param.Name] = arrStrs; } } else if (param.ParameterType.IsClass) //當引數是一個物體 { ModelParamsFilter(param.ParameterType, context.ActionArguments[param.Name]); } } } /// <summary> /// 物體引數過濾 /// </summary> object ModelParamsFilter(Type type, object obj) { if (obj == null) { return obj; } var properties = type.GetProperties(); foreach (var item in properties) { if (item.GetValue(obj) == null) { continue; } var attribute = typeof(SkipLoginValidateAttribute); if (item.IsDefined(attribute, false)) //特殊引數處理 { continue; } //當引數是字串 if (item.PropertyType.Equals(typeof(string))) { //業務處理 string value =https://www.cnblogs.com/xyh9039/p/ item.GetValue(obj).ToString(); item.SetValue(obj, value.Replace(" ", "")); } else if (item.PropertyType.Equals(typeof(string[]))) //如果是字串陣列則遍歷每一個成員 { var arrStrs = item.GetValue(obj) as string[]; if (arrStrs != null && arrStrs.Length > 0) { for (int i = 0; i < arrStrs.Length; i++) { arrStrs[i] = arrStrs[i].Replace(" ", ""); //業務處理 } item.SetValue(obj, arrStrs); } } else if (item.PropertyType.IsClass) //當引數是一個物體 { item.SetValue(obj, ModelParamsFilter(item.PropertyType, item.GetValue(obj))); } } return obj; } #endregion 引數過濾 /// <summary> /// 在Action執行后觸發(如果繼承該類的子類也重寫了該方法,則先執行子類的方法,再執行父類的方法) /// </summary> /// <param name="context">Action執行后背景關系物件</param> public override void OnActionExecuted(ActionExecutedContext context) { base.OnActionExecuted(context); } /// <summary> /// 在Action執行前觸發 /// 注意:OnActionExecuting和OnActionExecuted是同步方法,而OnActionExecutionAsync是異步方法,同步和異步是不能同時都執行的,如果都寫上了那只會執行異步的方法, /// 官網相關資料:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters?view=aspnetcore-5.0 /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { //await base.OnActionExecutionAsync(context, next); #region 摘自官網 /* // Do something before the action executes. // next() calls the action method. var resultContext = await next(); // Do something after the action executes. */ #endregion 摘自官網 //Action執行之前的業務處理 Console.WriteLine("======================================================================================"); Console.WriteLine($"執行緒{Thread.CurrentThread.ManagedThreadId}開始執行 => This is BaseController/OnActionExecutionAsync"); Stopwatch sw = new Stopwatch(); sw.Start(); ActionExecutedContext resultContext = await next(); //執行Action sw.Stop(); //Action執行之后的業務處理 Console.WriteLine($"執行緒{Thread.CurrentThread.ManagedThreadId}執行結束 => This is BaseController/OnActionExecutionAsync 處理花費時間:{sw.ElapsedMilliseconds}ms"); } } }
自定義Action過濾器如下所示:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.Filters; using MvcDemo.Attributes; namespace MvcDemo.Filters { /// <summary> /// 自定義Action過濾器(也可通過BaseController實作過濾器功能) /// </summary> public class MyActionFilterAttribute : ActionFilterAttribute { /// <summary> /// 在Action執行前觸發(如果在控制器中也重寫了該方法,則先執行控制器中的方法,再執行過濾器中的方法) /// </summary> /// <param name="filterContext">Action執行前背景關系物件</param> public override void OnActionExecuting(ActionExecutingContext filterContext) { base.OnActionExecuting(filterContext); //獲取請求進來的控制器與Action var controllerActionDescriptor = filterContext.ActionDescriptor as Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor; #region 【權限驗證】【登入驗證】 //獲取區域名稱 var areaName = filterContext.ActionDescriptor.RouteValues["area"] ?? ""; areaName = (string)filterContext.RouteData.Values["area"]; //獲取控制器名稱 var controllerName = filterContext.ActionDescriptor.RouteValues["controller"]; controllerName = controllerActionDescriptor.ControllerName; controllerName = filterContext.RouteData.Values["controller"].ToString(); //獲取action名稱 var actionName = filterContext.ActionDescriptor.RouteValues["action"]; actionName = controllerActionDescriptor.ActionName; actionName = filterContext.RouteData.Values["action"].ToString(); //獲取當前的請求方式:Get或者Post string requestMethod = filterContext.HttpContext.Request.Method.ToLower(); //獲取路由占位符對應的值 object currId = filterContext.RouteData.Values["id"]; //獲取當前請求URL引數 var value =https://www.cnblogs.com/xyh9039/p/ filterContext.HttpContext.Request.Query.ContainsKey("key") ? filterContext.HttpContext.Request.Query["key"].ToString() : ""; //獲取Action引數值 IDictionary<string, object> actionArguments = filterContext.ActionArguments; if (actionArguments != null) { foreach (KeyValuePair<string, object> item in actionArguments) { var key = item.Key; //引數名 var val = item.Value; //引數值 } } ParamsFilter(filterContext); //引數過濾 //判斷當前所請求的控制器上是否有打上指定的特性標簽 if (controllerActionDescriptor.ControllerTypeInfo.IsDefined(typeof(SkipLoginValidateAttribute), false)) { //有的話就不進行相關操作【例如:不進行登入驗證】 //return; } //獲取當前所請求的Action上指定的特性標簽 object[] arrObj1 = controllerActionDescriptor.MethodInfo.GetCustomAttributes(typeof(SkipLoginValidateAttribute), false); //獲取當前所請求的Action上所有的特性標簽 object[] arrObj2 = controllerActionDescriptor.MethodInfo.GetCustomAttributes(false); //判斷當前所請求的Action上是否有打上指定的特性標簽 if (controllerActionDescriptor.MethodInfo.IsDefined(typeof(SkipLoginValidateAttribute), false)) { //有的話就不進行相關操作【例如:不進行登入驗證】 return; } #endregion 【權限驗證】【登入驗證】 //【權限驗證】【登入驗證】邏輯 //To Do Something } #region 引數過濾 /// <summary> /// 引數過濾 /// </summary> void ParamsFilter(ActionExecutingContext filterContext) { //獲取引數集合 var parameters = filterContext.ActionDescriptor.Parameters; //遍歷引數集合 foreach (var param in parameters) { if (!filterContext.ActionArguments.ContainsKey(param.Name)) { continue; } if (filterContext.ActionArguments[param.Name] == null) { continue; } //當引數是字串 if (param.ParameterType.Equals(typeof(string))) { //業務處理 var value =https://www.cnblogs.com/xyh9039/p/ filterContext.ActionArguments[param.Name].ToString(); filterContext.ActionArguments[param.Name] = value.Replace(" ", ""); } else if (param.ParameterType.Equals(typeof(string[]))) //如果是字串陣列則遍歷每一個成員 { var arrStrs = filterContext.ActionArguments[param.Name] as string[]; if (arrStrs != null && arrStrs.Length > 0) { for (int i = 0; i < arrStrs.Length; i++) { arrStrs[i] = arrStrs[i].Replace(" ", ""); //業務處理 } filterContext.ActionArguments[param.Name] = arrStrs; } } else if (param.ParameterType.IsClass) //當引數是一個物體 { ModelParamsFilter(param.ParameterType, filterContext.ActionArguments[param.Name]); } } } /// <summary> /// 物體引數過濾 /// </summary> object ModelParamsFilter(Type type, object obj) { if (obj == null) { return obj; } var properties = type.GetProperties(); foreach (var item in properties) { if (item.GetValue(obj) == null) { continue; } var attribute = typeof(SkipLoginValidateAttribute); if (item.IsDefined(attribute, false)) //特殊引數處理 { continue; } //當引數是字串 if (item.PropertyType.Equals(typeof(string))) { //業務處理 string value =https://www.cnblogs.com/xyh9039/p/ item.GetValue(obj).ToString(); item.SetValue(obj, value.Replace(" ", "")); } else if (item.PropertyType.Equals(typeof(string[]))) //如果是字串陣列則遍歷每一個成員 { var arrStrs = item.GetValue(obj) as string[]; if (arrStrs != null && arrStrs.Length > 0) { for (int i = 0; i < arrStrs.Length; i++) { arrStrs[i] = arrStrs[i].Replace(" ", ""); //業務處理 } item.SetValue(obj, arrStrs); } } else if (item.PropertyType.IsClass) //當引數是一個物體 { item.SetValue(obj, ModelParamsFilter(item.PropertyType, item.GetValue(obj))); } } return obj; } #endregion 引數過濾 /// <summary> /// 在Action執行后觸發(如果在控制器中也重寫了該方法,則先執行過濾器中的方法,再執行控制器中的方法) /// </summary> /// <param name="filterContext">Action執行后背景關系物件</param> public override void OnActionExecuted(ActionExecutedContext filterContext) { base.OnActionExecuted(filterContext); } /// <summary> /// 在Action回傳前觸發,執行View前 /// </summary> /// <param name="filterContext">Action回傳前背景關系物件</param> public override void OnResultExecuting(ResultExecutingContext filterContext) { base.OnResultExecuting(filterContext); } /// <summary> /// 在Action回傳后,View顯示后觸發 /// </summary> /// <param name="filterContext">Action回傳后背景關系物件</param> public override void OnResultExecuted(ResultExecutedContext filterContext) { base.OnResultExecuted(filterContext); } /// <summary> /// 在Action執行前觸發 /// 注意:OnActionExecuting和OnActionExecuted是同步方法,而OnActionExecutionAsync是異步方法,同步和異步是不能同時都執行的,如果都寫上了那只會執行異步的方法, /// 官網相關資料:https://docs.microsoft.com/zh-cn/aspnet/core/mvc/controllers/filters?view=aspnetcore-5.0 /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { //await base.OnActionExecutionAsync(context, next); #region 摘自官網 /* // Do something before the action executes. // next() calls the action method. var resultContext = await next(); // Do something after the action executes. */ #endregion 摘自官網 //Action執行之前的業務處理 Console.WriteLine($"執行緒{Thread.CurrentThread.ManagedThreadId}開始執行 => This is MyActionFilterAttribute/OnActionExecutionAsync"); Stopwatch sw = new Stopwatch(); sw.Start(); ActionExecutedContext resultContext = await next(); //執行Action sw.Stop(); //Action執行之后的業務處理 Console.WriteLine($"執行緒{Thread.CurrentThread.ManagedThreadId}執行結束 => This is MyActionFilterAttribute/OnActionExecutionAsync 處理花費時間:{sw.ElapsedMilliseconds}ms"); } /// <summary> /// 在Result執行前觸發 /// 注意:OnResultExecuting和OnResultExecuted是同步方法,而OnResultExecutionAsync是異步方法,同步和異步是不能同時都執行的,如果都寫上了那只會執行異步的方法, /// </summary> /// <param name="context"></param> /// <param name="next"></param> /// <returns></returns> public override async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { //await base.OnResultExecutionAsync(context, next); //Result執行之前的業務處理(View執行前) Console.WriteLine($"執行緒{Thread.CurrentThread.ManagedThreadId}開始執行 => This is MyActionFilterAttribute/OnResultExecutionAsync"); Stopwatch sw = new Stopwatch(); sw.Start(); ResultExecutedContext resultContext = await next(); //執行Result(執行View) sw.Stop(); //Result執行之后的業務處理(View執行后) Console.WriteLine($"執行緒{Thread.CurrentThread.ManagedThreadId}執行結束 => This is MyActionFilterAttribute/OnResultExecutionAsync 處理花費時間:{sw.ElapsedMilliseconds}ms"); } } }
在Startup.cs里面注冊全域過濾器:
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using MvcDemo.Filters; namespace MvcDemo { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(options => { options.Filters.Add<MyActionFilterAttribute>(); //注冊全域過濾器 任意控制器-Action }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "areas", pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"); endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } }
最后我們使用cmd命令列方式啟動我們的Demo,并且訪問 /Home/Index,看下最終控制臺的輸出結果:

關于過濾器的更多內容,有興趣的可參考我之前寫的另外一篇博文:https://www.cnblogs.com/xyh9039/p/14359665.html
至此本文就全部介紹完了,如果覺得對您有所啟發請記得點個贊哦!!!
Demo原始碼:
鏈接:https://pan.baidu.com/s/1EuNkf23sdDHhtFxERZxAvA 提取碼:2cyo
此文由博主精心撰寫轉載請保留此原文鏈接:https://www.cnblogs.com/xyh9039/p/15174104.html
著作權宣告:如有雷同純屬巧合,如有侵權請及時聯系本人修改,謝謝!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/295782.html
標籤:.NET Core
