主頁 > .NET開發 > ASP.NET Core MVC基礎知識

ASP.NET Core MVC基礎知識

2021-08-31 15:17:01 .NET開發

本章將和大家分享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

上一篇:物件池在 .NET (Core)中的應用[1]: 編程篇

下一篇:物件池在 .NET (Core)中的應用[2]: 設計篇

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more