首页 > 技术文章 > .Net 5+MVC+AOP扩展鉴权授权

LZXX 2021-04-14 17:46 原文

1.IActionResult扩展定制
2.登录功能自定义鉴权授权类
3.ResourceFilter扩展定制
4.Filter的多种注册方式
5.自定义全局鉴权类,让某些控制器或方法不使用该鉴权
6.鉴权类带参数
7.自定义三个ActionFitler,分别注册全局/控制器/Action 执行顺序是怎么样的
8.如果想要控制Filter的执行顺序怎么办?
9.net自带鉴权授权(推荐,因为在俄罗斯套娃最外层,提前判断鉴权授权)

1.IActionResult扩展定制

  #region IActionResult扩展
        public JsonResult ToJSON()
        {
            var result = new JsonResult(new
            {
                Id = 123,
                Name = "海贝"
            });

            result.ContentType = "";
            return result;

            //return Json(new
            //{
            //    Id = 123,
            //    Name = "海贝"
            //});
        }
        [CustomAllowAnonymousAttribute]
        public FileResult VerifyCode()
        {
            string code = "";
            Bitmap bitmap = VerifyCodeHelper.CreateVerifyCode(out code);
            base.HttpContext.Session.SetString("CheckCode", code);
            MemoryStream stream = new MemoryStream();
            bitmap.Save(stream, ImageFormat.Gif);
            return File(stream.ToArray(), "image/gif");
        }


        public string TostingConsole()
        {
            return "";
        }


        public IActionResult ToNewtonsoftJsonResult()
        {
            return new NewtonsoftJsonResult(new
            {
                Id = 234,
                Name = "年轻人不讲武德"
            });
        }

        public IActionResult ToXmlResult()
        {
            return new XmlResult("<a href='zhaoxiedu.net'>朝夕官网</a>");
        }

        public void ToStringExtension()
        {
            HttpContext.Response.WriteAsync("<a href='zhaoxiedu.net'>朝夕官网</a>");
        }

        public StringResult ToStringResult()
        {
            return new StringResult("<a href='zhaoxiedu.net'>朝夕官网</a>");
        }


        public class NewtonsoftJsonResult : IActionResult
        {
            private object _Data = null;
            public NewtonsoftJsonResult(object data)
            {
                this._Data = data;
            }

            public async Task ExecuteResultAsync(ActionContext context)
            {
                HttpResponse response = context.HttpContext.Response;
                response.ContentType = "application/json;charset=utf-8";
                await response.WriteAsync(Newtonsoft.Json.JsonConvert.SerializeObject(_Data));
            }
        }

        public class XmlResult : IActionResult
        {
            private string _Data = null;
            public XmlResult(string data)
            {
                this._Data = data;
            }

            public async Task ExecuteResultAsync(ActionContext context)
            {
                HttpResponse response = context.HttpContext.Response;
                response.ContentType = "application/xml;charset=utf-8";
                await response.WriteAsync(_Data);
            }
        }

        public class StringResult : IActionResult
        {
            private string _Data = null;
            public StringResult(string data)
            {
                this._Data = data;
            }

            public async Task ExecuteResultAsync(ActionContext context)
            {
                HttpResponse response = context.HttpContext.Response;
                response.ContentType = "text/plain;charset=utf-8";
                await response.WriteAsync(_Data);
            }
        }

        /// <summary>
        /// 自定义扩展
        /// 专门响应成一个Excel文件下载
        /// 1.赋值对应的Content-type
        /// 2.写入文件流到Response
        /// </summary>
        public class ExcelResult : IActionResult //---NPOI
        {
            private object _Data = null;
            public ExcelResult(object data)
            {
                this._Data = data;
            }

            public async Task ExecuteResultAsync(ActionContext context)
            {
                HttpResponse response = context.HttpContext.Response;
                response.ContentType = "application/vnd.ms-excel";
                //1.设置content-Type
                //2.根据数据生成excel文件
                //3.把excel文件流写入到response
                //await response.WriteAsync(_Data);
            }
        }

        #endregion
View Code

2.鉴权授权(两步走1:自定义类,继承Attribute,2:相关方法注册鉴权类3.可选全局注册鉴权,全局实现AOP)

 

 

 

 1.登录方法

  [HttpPost]
        [CustomAllowAnonymousAttribute]
        public IActionResult Login(string name, string password, string verify)
        {
            string verifyCode = base.HttpContext.Session.GetString("CheckCode");
            if (verifyCode != null && verifyCode.Equals(verify, StringComparison.CurrentCultureIgnoreCase))
            { 
                #region 这里在工作中的写法是去数据库中去做验证
                if ("Zhaoxi".Equals(name) && "Zhaoxi".Equals(password))//就认为登录成功了
                {
                    #region Cookie/Session 自己写   一般使用Sessio为主
                    CurrentUser currentUser = new CurrentUser()
                    {
                        Id = 123,
                        Name = "Zhaoxi",
                        Account = "Administrator",
                        Email = "1030499676",
                        Password = "123456",
                        LoginTime = DateTime.Now
                    }; 
                    //写Session/写Cookies 
                    base.HttpContext.SetCookies("CurrentUser", Newtonsoft.Json.JsonConvert.SerializeObject(currentUser), 30);

                    base.HttpContext.Session.SetString("CurrentUser", Newtonsoft.Json.JsonConvert.SerializeObject(currentUser));
                    #endregion

                    return base.Redirect("/Fifth/Index");
                }
                else
                {
                    base.ViewBag.Msg = "账号密码错误";
                }
                #endregion

            }
            else
            {
                base.ViewBag.Msg = "验证码错误";
            }
            return View();
        }
View Code

2.:创建自定义授权类,继承Attribute, IActionFilter 

  public class ActionAuthrizaFilterAttribute : Attribute, IActionFilter
    {
        /// <summary>
        /// 方法执行后
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
            return;
        }

        /// <summary>
        /// 方法执行前
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        { 
            //要先判断,当前请求的Action上是否有标记 [CustomAllowAnonymousAttribute]特性
            //如果有继续往后走,如果没有就不需要匿名
            //应该检测两个地方:控制器和Action 
            //判断action 上是否有CustomAllowAnonymousAttribute
            if (!context.ActionDescriptor.FilterDescriptors.Any(item => item.Filter is CustomAllowAnonymousAttribute))
            {
                return;
            }

            //filterContext.ActionDescriptor.IsDefined(typeof(SkipCheckLoginAttribute)

            //判断控制器 上是否有CustomAllowAnonymousAttribute
            if (!context.Filters.Any(f => f is CustomAllowAnonymousAttribute))
            {
                return;//匿名 不检查  
            }

            ///获取session
            CurrentUser currentUser = context.HttpContext.GetCurrentUserBySession();

            //因为每一次请求来了都要先进入到这儿来,所有,如果有些Action需要避开鉴权;要判断如果标记的是AllowAnonymous,就跳过 
            if (currentUser == null)// 就要拦截
            {
                if (this.IsAjaxRequest(context.HttpContext.Request))
                {
                    context.Result = new JsonResult(new
                    {
                        Success = false,
                        Messge = "没有权限"
                    });
                }
                context.Result = new RedirectResult("~/fifth/Login");//短路器,只要对context.Result赋值,就不再往后执行
            }
            //继续往后 
        }


        private bool IsAjaxRequest(HttpRequest request)
        {
            string header = request.Headers["X-Requested-With"];
            return "XMLHttpRequest".Equals(header);
        }
    }
ActionAuthrizaFilterAttribute

3.:加在需要做授权的方法上

 

4全局注册:鉴权类 对整个系统所有acction都生效 

 

5做了全局生效 如果某些方法不需要生效

1.就自定义空的一个类 继承Attribute

2.然后在鉴权的类,判断有没有这个类,有就不做鉴权认证

  public class CustomAllowAnonymousAttribute:Attribute
    {
    }
CustomAllowAnonymousAttribute

 

6.鉴权类如果需要带参数

 

  public class ActionAuthrizaFilterAttribute : Attribute, IActionFilter
    { 
        #region 需要调用其他服务 
      
        //如果需要使用第三方服务:大家切记,要通过依赖注入来完成; 
        private readonly ILogger<ActionAuthrizaFilterAttribute> _ILogger = null;

        public ActionAuthrizaFilterAttribute(ILogger<ActionAuthrizaFilterAttribute> logger)
        {
            this._ILogger = logger;
        }

        #endregion
         
        //请求来了以后,是要去访问某一个Action;
        //在之前要执行ActionFilter---需要实例化Filter
        //获取当前请求的Controller名称和Action名称,保存起来;
        //权限验证通过以后,就跳转到当前路径下去

        private string currentPath = null;

        /// <summary>
        /// 方法执行后
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
            return;
        }

        /// <summary>
        /// 方法执行前
        /// </summary>
        /// <param name="context"></param>
        public void OnActionExecuting(ActionExecutingContext context)
        {

            Console.WriteLine("开始验证权限。。。。");

            //要先判断,当前请求的Action上是否有标记 [CustomAllowAnonymousAttribute]特性
            //如果有继续往后走,如果没有就不需要匿名
            //应该检测两个地方:控制器和Action 
            //判断action 上是否有CustomAllowAnonymousAttribute

            //在.NET5中这里获取特性判断,不一样了;在EndpointMetadata获取
            //1.无论是标记在Controller上的自定义特性还是标记在Action上的自定义特性能,在这里都是统一通过context.ActionDescriptor.EndpointMetadata来获取
            if (context.ActionDescriptor.EndpointMetadata.Any(item => item is CustomAllowAnonymousAttribute))
            {
                return;
            }

            ////filterContext.ActionDescriptor.IsDefined(typeof(SkipCheckLoginAttribute)

            ////判断控制器 上是否有CustomAllowAnonymousAttribute
            //if (context.Filters.Any(f => f is CustomAllowAnonymousAttribute))
            //{
            //    return;//匿名 不检查  
            //}

            ///获取session
            CurrentUser currentUser = context.HttpContext.GetCurrentUserBySession();

            //因为每一次请求来了都要先进入到这儿来,所有,如果有些Action需要避开鉴权;要判断如果标记的是AllowAnonymous,就跳过 
            if (currentUser == null)// 就要拦截
            { 
                _ILogger.LogInformation($"{currentUser?.Name}权限验证通过了。。。");

                if (this.IsAjaxRequest(context.HttpContext.Request))
                {
                    context.Result = new JsonResult(new
                    {
                        Success = false,
                        Messge = "没有权限"
                    });
                }
                context.Result = new RedirectResult("~/fifth/Login");//短路器,只要对context.Result赋值,就不再往后执行
            }
            //继续往后 
        }


        private bool IsAjaxRequest(HttpRequest request)
        {
            string header = request.Headers["X-Requested-With"];
            return "XMLHttpRequest".Equals(header);
        }
    }
自定义鉴权类

 

 

 


7.定义三个ActionFitler,分别注册全局/控制器/Action

默认执行顺序如何?
如下:
1.全局方法执行前
2.控制器方法执行前
3.ActionFilter方法执行前
4. 执行方法
5.ActionFilter方法执行后
6.控制器方法执行后
7.全局方法执行后


8.如果想要控制Filter的执行顺序怎么办?

 

 

9.net自带鉴权授权(推荐,因为在俄罗斯套娃最外层,提前判断鉴权授权)

第一步:在在startup.cs中间件里面   添加相关代码

 

 第二步:在在startup.cs中间件里面   添加鉴权授权相关支持

 

第三步:登录成功之后写入用户信息

  [HttpPost]
        [CustomAllowAnonymousAttribute]
        public IActionResult Login(string name, string password, string verify)
        {
            string verifyCode = base.HttpContext.Session.GetString("CheckCode");
            if (verifyCode != null && verifyCode.Equals(verify, StringComparison.CurrentCultureIgnoreCase))
            {
                #region 这里在工作中的写法是去数据库中去做验证
                if ("Zhaoxi".Equals(name) && "Zhaoxi".Equals(password))//就认为登录成功了
                {
                    #region Cookie/Session 自己写   一般使用Sessio为主
                    //CurrentUser currentUser = new CurrentUser()
                    //{
                    //    Id = 123,
                    //    Name = "Zhaoxi",
                    //    Account = "Administrator",
                    //    Email = "1030499676",
                    //    Password = "123456",
                    //    LoginTime = DateTime.Now
                    //};
                    ////写Session/写Cookies 
                    //base.HttpContext.SetCookies("CurrentUser", Newtonsoft.Json.JsonConvert.SerializeObject(currentUser), 30);

                    //base.HttpContext.Session.SetString("CurrentUser", Newtonsoft.Json.JsonConvert.SerializeObject(currentUser));
                    #endregion

                    #region 鉴权:鉴权,检测有没有登录,登录的是谁,赋值给User
                    //每一个Claim 表示记录当前用户的某一个信息(票证)


                    //这部分角色有可能是从数据库中查询出来的;---对应当前用户登录的时候,动态查询出的角色信息
                    var rolelist = new List<string>() {
                    
                            "Admin",
                            "Teacher",
                            "Student"
                    };
                     
                    var claims = new List<Claim>()//鉴别你是谁,相关信息
                    {
                        new Claim(ClaimTypes.Role,"Admin"),
                        new Claim(ClaimTypes.Name,name),
                        new Claim("password",password),//可以写入任意数据
                        new Claim("Account","Administrator"),
                        new Claim("role","admin"),
                        new Claim("zhaoxi","zhaoxi")
                    };

                    foreach (var role in rolelist)
                    {
                        claims.Add(new Claim(ClaimTypes.Role, role));
                    }
                   
                    //ClaimsPrincipal 用户信息打包,写入到一个身份证中去
                    ClaimsPrincipal userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Customer")); //针对与当前用户的身份证 
                    //登录//把身份证信息保存到Cookies中
                    HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, new AuthenticationProperties
                    {
                        ExpiresUtc = DateTime.UtcNow.AddMinutes(30),//过期时间:30分钟

                    }).Wait();//没用await 

                    #endregion  
                    var user = HttpContext.User; 
                    return base.Redirect("/Fifth/Index");
                }
                else
                {
                    base.ViewBag.Msg = "账号密码错误";
                }
                #endregion

            }
            else
            {
                base.ViewBag.Msg = "验证码错误";
            }
            return View();
        }
登录代码

第四步:标记特性,给需要做鉴权的地方acction支持鉴权

 

 

 10.多角色授权比较死板

//这部分角色有可能是从数据库中查询出来的;---对应当前用户登录的时候,
                    //动态查询出的角色信息
                    var rolelist = new List<string>() {
                    
                            "Admin",
                            "Teacher",
                            "Student"
                    };
                     
                    var claims = new List<Claim>()//鉴别你是谁,相关信息
                    {
                        new Claim(ClaimTypes.Role,"Admin"),//角色授权
                        new Claim(ClaimTypes.Name,name),
                        new Claim("password",password),//可以写入任意数据
                        new Claim("Account","Administrator"),
                        new Claim("role","admin"),
                        new Claim("zhaoxi","zhaoxi")
                    };

                    foreach (var role in rolelist)
                    {
                        claims.Add(new Claim(ClaimTypes.Role, role));
                    }
控制器里面的登录方法
  //角色鉴权
        [Authorize(Roles ="Admin")]
        public ViewResult Index01()
        { 
            _Logge.LogInformation("在这里执行了Action");
            return View();
        }

        [Authorize(Roles = "Admin,Teacher")]
        public ViewResult Index02()
        {
            _Logge.LogInformation("在这里执行了Action");
            return View();
        }

        [Authorize(Roles = "Admin,Teacher,Student")]
        public ViewResult Index03()
        {
            _Logge.LogInformation("在这里执行了Action");
            return View();
        }

        [Authorize(Roles = "Admin,Teacher,Student")] //1.标记Authorze 指定角色以逗号分隔:只要是包含登录的时候写入的某一个角色;就通过验证;或者的关系
        [Authorize(Roles = "ABCCC")]//2.如果标记多个特性,且的关系
        public ViewResult Index04()
        {
            _Logge.LogInformation("在这里执行了Action");
            return View();
        }
         
        [Authorize]
        public ViewResult Index05()
        {
            _Logge.LogInformation("在这里执行了Action");
            return View();
        }
需要鉴权的地方
//支持角色验证
            services.AddAuthorization(options =>
            {
                //增加当前角色
                options.AddPolicy("CustomAuthorizePolicy", policy =>
                {
                    //这里表示生效的时候,一些验证逻辑
                    policy.RequireRole("Admin,Teacher,Student");
                });
            });
startup.cs-ConfigureServices方法

 

 11.自定义策略认证(推荐)

  public class CustomAuthorizationHandler : AuthorizationHandler<CustomAuthorizationRequirement>
    {
        public CustomAuthorizationHandler()
        {

        }
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomAuthorizationRequirement requirement)
        { 
            if (requirement.Name == "Policy01")
            {
                ///策略1的逻辑
            }

            if (requirement.Name == "Policy02")
            {
                ///策略1的逻辑
            }

            if (true)
            {

            }

            //在这里可以自己定义自己的规则
            {
                //去数据库里面查出所有角色想信息
                //其实这里可以去数据库里面去做一些查询,然后根据用户的信息,做计算;如果符合就context.Succeed(requirement); 
                //否则就Task.CompletedTask; 
            }
            //context.User 鉴权成功(登录成功以后),用户的信息; 
            var role = context.User.FindFirst(c => c.Value.Contains("admin"));
            if (role != null)
            {
                context.Succeed(requirement); //验证通过了

            }
            return Task.CompletedTask; //验证不同过
        }
    }
}
CustomAuthorizationHandler.cs
  public class CustomAuthorizationRequirement: IAuthorizationRequirement
    {

        /// <summary>
        /// 
        /// </summary>
        public CustomAuthorizationRequirement(string policyname)
        {
            this.Name = policyname;
        }

        public string Name { get; set; }
    }
CustomAuthorizationRequirement
 [Authorize(policy: "customPolicy")]
        public ViewResult Index06()
        {
            _Logge.LogInformation("在这里执行了Action");
            return View();
        }

        [Authorize(policy: "customPolicy02")]

        [Authorize(policy: "customPolicy01")]
        public ViewResult Index07()
        {
            _Logge.LogInformation("在这里执行了Action");
            return View();
        }
需要验证的地方
  ////支持策略认证
            //services.AddAuthorization(options =>
            //{
            //    options.AddPolicy("customPolicy", polic =>
            //    {
            //        polic.AddRequirements(new CustomAuthorizationRequirement("Policy01"));//指定策略
            //    });
            //});

            //services.AddAuthorization(options =>
            //{
            //    options.AddPolicy("customPolicy01", polic =>
            //    {
            //        polic.AddRequirements(new CustomAuthorizationRequirement("Policy02"));
            //    });
            //});


            //services.AddAuthorization(options =>
            //{
            //    options.AddPolicy("customPolicy02", polic =>
            //    {
            //        polic.AddRequirements(new CustomAuthorizationRequirement("Policy03"));
            //    });
            //});

            //在这里标记自定义的授权Hanlder生效
            services.AddSingleton<IAuthorizationHandler, CustomAuthorizationHandler>();
Startup.cs-Cnfigureservice()

 

角色认证+策步骤:
1.登录时写入角色claimtypes.role
2.在startup中支持角色认证
/3.在标记action/控制器的时候增加authorize 参数role,
4.标记一个,多个role分隔,是或者关系,如果标记多个authorize,roles是且的关系

自定义步骤
策略验证;验证的时候自定义策略,再action 控制器使用策略;策略自己定义
1.定义权限验证的执行类,实现authorizationhandler抽象
2.在starup注册ioc服务------在action/控制器/全局标记authorize以后,在请求action时,就会先进入到定义的权限验证类中去执行handlerequirementasync
3.验证方式有很多种; 每一种可以定义一种策略 实现iauthorizationrequirement接口
4.定义的策略要在验证逻辑中使用;可以当authorizationhandler 的泛型参数;

 

 12.ResourceFilter做缓存AOP+或者可以把缓存缓存redis

第一步自定义 缓存类 继承 Attribute

  public class CustomResourceFilterAttribute : Attribute, IResourceFilter
    {
        /// <summary>
        /// 可以把Redis的操作类库给注入进来,保存缓存就保存到Redis中去。。。。
        /// </summary>

        public CustomResourceFilterAttribute()
        { 
        
        }

        private static Dictionary<string, object> CacheDictionary = new Dictionary<string, object>(); 
       /// <summary>
       /// 在XX资源之前
       /// </summary>
       /// <param name="context"></param>
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            ///1.先判断缓存中是否有数据
            ///2.如果有数据,就直接拿着数据走了
            ///3.没有就继续往后,就去实例化控制器,去执行Action做计算 
            //缓存:需要一个key;  只要是key不变,拿到的数据就不变;
            //如果做缓存,一般请求路径不变,数据一般不变; 
            string key = context.HttpContext.Request.Path;
            if (CacheDictionary.Any(item=>item.Key==key))
            {
                context.Result = CacheDictionary[key] as IActionResult;
            }
            //如果没有缓存---就继续往后; 
            Console.WriteLine("CustomResourceFilterAttribute.OnResourceExecuting");
        }

        /// <summary>
        /// 在xx资源之后
        /// </summary>
        /// <param name="context"></param>
        public void OnResourceExecuted(ResourceExecutedContext context)
        {

            //代码执行到这里,就表示一定完成了逻辑计算;就有结果;
            string key = context.HttpContext.Request.Path;
            CacheDictionary[key] = context.Result;
            Console.WriteLine("CustomResourceFilterAttribute.OnResourceExecuted");
        }

    }
CustomResourceFilterAttribute

 

第二步控制器添加特性

   [CustomResourceFilterAttribute]
        public IActionResult Index()
        {

            TestServiceException testServiceException = new TestServiceException();
            testServiceException.Show();


            ViewBag.date = DateTime.Now;

            return View();
        }
controller

缓存:在第一次请求数据以后,把计算结果保存在内存----

下一次再来请求的时候,只要是还是要获取之前的数据;就直接取内存数据;不用做计算了;提高性能;
1.定义一个ResourceFilter 实现IResourceFilter接口
2.实现方法,标记在action上

执行顺序:
1.ResourceFilter---OnResourceExecuting
2.执行控制器构造函数
3.执行Action
4.ResourceFilter---OnResourceExecuted

 

 

13.异常AOP ExceptionFilter  

第一步:自定义异常类 继承Attribute

public class CustomExceptionFilterAttribute : Attribute, IExceptionFilter
    {

        private readonly IModelMetadataProvider _modelMetadataProvider;

        public CustomExceptionFilterAttribute(IModelMetadataProvider modelMetadataProvider)
        {
            _modelMetadataProvider = modelMetadataProvider;
        }

        /// <summary>
        /// 当异常发生的时候就触发
        /// </summary>
        /// <param name="context"></param>
        public void OnException(ExceptionContext context)
        {
            //判断异常是否被处理了
            if (!context.ExceptionHandled)
            {
                if (this.IsAjaxRequest(context.HttpContext.Request))//header看看是不是XMLHttpRequest
                {
                    context.Result = new JsonResult(new
                    {
                        Result = false,
                        Msg = context.Exception.Message
                    });//中断式---请求到这里结束了,不再继续Action
                }
                else
                {
                    var result = new ViewResult { ViewName = "~/Views/Shared/Error.cshtml" };
                    result.ViewData = new ViewDataDictionary(_modelMetadataProvider, context.ModelState);
                    result.ViewData.Add("Exception", context.Exception);



                    context.Result = result; //断路器---只要对Result赋值--就不继续往后了;
                }
                context.ExceptionHandled = true;
            }
        }
        private bool IsAjaxRequest(HttpRequest request)
        {
            string header = request.Headers["X-Requested-With"];
            return "XMLHttpRequest".Equals(header);
        }
    } 
CustomExceptionFilterAttribute

第二步:全局注册

   services.AddMvc(option =>
            {
                //3.全局注册  对当前项目所有Action都生效
                //option.Filters.Add(new ActionAuthrizaFilterAttribute()); 
                //option.Filters.Add<ActionAuthrizaFilterAttribute>();//也可以支持以来注入 
                option.Filters.Add<GlobalActionFilterAttribute>();//全局注册
                option.Filters.Add<CustomExceptionFilterAttribute>(); //全局异常都可以捕捉

                //option.Filters.Add<Authorize>();
            });
startup.cs-ConfigureServices()

第三步:增加异常友好页面

@*@model ErrorViewModel*@
@{
    ViewData["Title"] = "Error";
}
@{
    ViewData["Title"] = "Error";
    Exception exception = base.ViewData["Exception"] as Exception;
}

<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<h1>@exception.Message</h1>

<h3>Development Mode</h3>
<p>
    Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
    <strong>The Development environment shouldn't be enabled for deployed applications.</strong>
    It can result in displaying sensitive information from exceptions to end users.
    For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
    and restarting the app.
</p>
Error.cshtml

 

第四步:有点错误补充不到 增加补充错误措施

     #region 捕捉异常的补充 
            app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");//只要不是200 都能进来
            app.UseExceptionHandler(errorApp =>
            {
                errorApp.Run(async context =>
                {
                    context.Response.StatusCode = 200;
                    context.Response.ContentType = "text/html";
                    await context.Response.WriteAsync("<html lang=\"en\"><body>\r\n");
                    await context.Response.WriteAsync("ERROR!<br><br>\r\n");
                    var exceptionHandlerPathFeature =
                        context.Features.Get<IExceptionHandlerPathFeature>();

                    Console.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");
                    Console.WriteLine($"{exceptionHandlerPathFeature?.Error.Message}");
                    Console.WriteLine("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");

                    if (exceptionHandlerPathFeature?.Error is FileNotFoundException)
                    {
                        await context.Response.WriteAsync("File error thrown!<br><br>\r\n");
                    }
                    await context.Response.WriteAsync("<a href=\"/\">Home</a><br>\r\n");
                    await context.Response.WriteAsync("</body></html>\r\n");
                    await context.Response.WriteAsync(new string(' ', 512)); // IE padding
                });
            });
            #endregion
startup.cs-configure

 

 

 

 

 

 

T:能正常捕获,F:捕获不了

 

 

14.ResultFilter  结果AOP,呈现结果之前的AOP

第一步:

  public class CustomoResultFilterAttribute : Attribute, IResultFilter
    {

        public void OnResultExecuting(ResultExecutingContext context)
        {
            Console.WriteLine("CustomoResultFilterAttribute.OnResultExecuting");
        }

        public void OnResultExecuted(ResultExecutedContext context)
        {
            Console.WriteLine("CustomoResultFilterAttribute.OnResultExecuted");
        }
    }

    public class CustomoAsyncResultFilterAttribute : Attribute, IAsyncResultFilter
    {
        public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            {
                Console.WriteLine("结果执行前");
            }
            await next.Invoke(); //执行结果
            {
                Console.WriteLine("结果执行后");
            }
        }
    }

    public class CustomoResultFromParentFilterAttribute : ResultFilterAttribute
    {

        public override void OnResultExecuted(ResultExecutedContext context)
        {
            base.OnResultExecuted(context);
        }

        public override void OnResultExecuting(ResultExecutingContext context)
        {
            base.OnResultExecuting(context);
        }

        public override Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
        {
            return base.OnResultExecutionAsync(context, next);
        }
    }
CustomoResultFilterAttribute

 

推荐阅读