zoukankan      html  css  js  c++  java
  • C#基础系列过滤器与特性

    一、前言

       编程中我们会使用特性(Attribute)标注到程序集、类、方法、属性上进行描述,在Asp.net MVC或者Asp.net WebApi中使用过滤器(Filter)对Action、Result、Exception、Authorize进行AOP(切面编程)。并且过滤器和特性结合,将过滤器优雅的使用在方法上。本文针对特性与过滤器做一个总结。

    二、定义

       1、特性(Attribute),在微软官方文档的定义是使用特性,可以有效地将元数据或声明性信息与代码(程序集、类型、方法、属性等)相关联。按个人理解,就是对元数据的描述,类和方法,属性作为元数据,使用特性在元数据上使用特性,其作用就是对元数据补充说明,使用反射的方式获取特性内容,使用特性信息。

      主要用途,比如描述类、方法和接口的 COM 属性、从标题、版本、说明或商标方面描述程序集、描述的方法的安全要求等详情参考msdn给的官方文档说明,总结就是基于元数据的描述信息,然后使用描述信息。

      2、过滤器(Filter),提供了在asp.net MVC与asp.net webApi的请求处理管道过程中注入额外的逻辑,提供了一个简单而优雅的方式来实现横切关注点。主要分四类过滤器IAuthorizationFilter(授权过滤器)、IActionFilter(Action方法过滤器)、IResultFilter(ActionResult方法返回结果)、IExceptionFilter(异常过滤器),类库中通过继承接口提供了AuthorizeAttribute、ActionFilterAttribute、HandleErrorAttribute给开发者进行继承重写实现业务逻辑。

      主要用途,比如基于AuthorizeAttribute(提供角色、用户名)方式的授权、日志信息、安全验证、图片防盗链、基于ActionFilterAttribute注入业务逻辑,请求和返回结果的处理等。

      3、在过滤器中.NET FrameWork中提供两类,一类是在命名空间为using System.Web.Mvc下的提供给ASP.NET MVC的过滤器、一类是在命名空间using System.Web.Http.Filters下提供给ASP.NET WebApi的过滤器,两者不能混用,否则无法拦截生效。

    三、使用

    1、自定义的特性和过滤器项目

       

     2、使用自定义特性在程序集、方法、属性等上,对其进行描述。通过反射的方式获取相应信息。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    namespace TQF.CustomFilterAttribute.App_Start.Filter
    {
        // _Attribute 接口运行时中
        public class TestAttribute: Attribute
        {
            public string ActionName { get; set; }
    
            public TestAttribute()
            {
    
            }
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    using System.Web;
    using System.Web.Mvc;
    using TQF.CustomFilterAttribute.App_Start.Filter;
    
    namespace TQF.CustomFilterAttribute.Controllers
    {
        /// <summary>
        /// MVC请求
        /// </summary>
        public class HomeController : Controller
        {
            public string Field { get; set; }
    
            public HomeController()
            {
    
            }
    
            //[TestMvcFilter(ActionName =nameof(Index))]
            [Test(ActionName =nameof(Index))]
            public ActionResult Index()
            {
                ViewBag.Title = "Home Page";
    
                //获取类的属性描述
                var classIfno = typeof(HomeController).GetCustomAttribute<TestAttribute>();
                //获取指定属性的属性描述
                var fieldIfno = typeof(HomeController).GetProperty("Field").GetCustomAttribute<TestAttribute>();
                //获取指定方法的属性描述
                var methodIfno = typeof(HomeController).GetMethod("Index").GetCustomAttribute<TestAttribute>();
    
                return View();
            }
    
            [HttpPost]
            public JsonResult Save()
            {
                //throw (new Exception("error", new InvalidCastException()));
                return new JsonResult();
            }
    
            public ActionResult Error()
            {
                return View();
            }
        }
    }

    3、自定义AuthorizeAttribute过滤

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using TQF.CustomFilterAttribute.Models;
    
    namespace TQF.CustomFilterAttribute.App_Start.Filter
    {
        /// <summary>
        /// Mvc请求权限授权过滤器
        /// </summary>
        public class TestMvcAuthorizeAttribute: AuthorizeAttribute
        {
            public override void OnAuthorization(AuthorizationContext filterContext)
            {
                var result = new ResultModel() { Message = "授权中" };
                //actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, result);
                // 获取特殊设置的角色和用户,进行权限判断
                if (Users == "admin")
                {
                    // 返回,不进行权限验证或者验证成功
                    return;
                }
                else
                {
    
                }
    
                //base.OnAuthorization(filterContext);
            }
    
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web;
    using System.Web.Http;
    using System.Web.Http.Controllers;
    using TQF.CustomFilterAttribute.Models;
    
    namespace TQF.CustomFilterAttribute.App_Start.Filter
    {
        /// <summary>
        /// webApi请求权限授权过滤器
        /// </summary>
        public class TestHttpAuthorizeAttribute: AuthorizeAttribute
        {
            public override void OnAuthorization(HttpActionContext actionContext)
            {
                var result = new ResultModel() { Message = "授权中" };
                //actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.OK, result);
                // 获取特殊设置的角色和用户,进行权限判断
                if (Users == "admin"){
                    // 返回,不进行权限验证或者验证成功
                    return;
                }else{
    
                }
                
                base.OnAuthorization(actionContext);
            }
        }
    }

    4、自定义ActionFilterAttribute过滤器(其包括实现了IActionFilterIResultFilter接口)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    
    namespace TQF.CustomFilterAttribute.App_Start.Filter
    {
        /// <summary>
        /// Mvc
        /// </summary>
        public class TestMvcActionFilterAttribute: ActionFilterAttribute
        {
            /// <summary>
            /// action 执行中
            /// </summary>
            /// <param name="filterContext"></param>
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                filterContext.HttpContext.Response.Write("OnActionExecuting");
                base.OnActionExecuting(filterContext);
            }
    
            /// <summary>
            /// action 执行结束
            /// </summary>
            /// <param name="filterContext"></param>
            public override void OnActionExecuted(ActionExecutedContext filterContext)
            {
                filterContext.HttpContext.Response.Write("OnActionExecuted");
                base.OnActionExecuted(filterContext);
            }
    
            /// <summary>
            /// 生成结果中
            /// </summary>
            /// <param name="filterContext"></param>
            public override void OnResultExecuting(ResultExecutingContext filterContext)
            {
                filterContext.HttpContext.Response.Write("OnResultExecuting");
                base.OnResultExecuting(filterContext);
            }
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="filterContext"></param>
            public override void OnResultExecuted(ResultExecutedContext filterContext)
            {
                filterContext.HttpContext.Response.Write("OnResultExecuting");
                base.OnResultExecuted(filterContext);
            }
    
            
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Web;
    using System.Web.Http.Controllers;
    using System.Web.Http.Filters;
    using TQF.CustomFilterAttribute.Models;
    
    namespace TQF.CustomFilterAttribute.App_Start.Filter
    {
        /// <summary>
        /// WebApi 请求的Action方法过滤器
        /// </summary>
        public class TestHttpActionFilterAttribute: ActionFilterAttribute
        {
            /// <summary>
            /// 执行前
            /// </summary>
            /// <param name="actionContext"></param>
            public override void OnActionExecuting(HttpActionContext actionContext)
            {
                var result = new ResultModel() { Message = "执行中"};
                // 返回请求结果,不执行后续
                actionContext.Response=actionContext.Request.CreateResponse(HttpStatusCode.OK, result); 
                base.OnActionExecuting(actionContext);
            }
    
            /// <summary>
            /// 执行后
            /// </summary>
            /// <param name="actionExecutedContext"></param>
            public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
            {
                var result = new ResultModel() { Message = "执行后" };
                // 更改请求结果
                actionExecutedContext.Response = actionExecutedContext.Request.CreateResponse(HttpStatusCode.OK, result);
                base.OnActionExecuted(actionExecutedContext);
            }
        }
    }

    5、自定义HandleErrorAttribute过滤器

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using TQF.CustomFilterAttribute.Models;
    
    namespace TQF.CustomFilterAttribute.App_Start.Filter
    {
        /// <summary>
        /// 处理中产生的异常,异常过滤器
        /// </summary>
        public class TestHandleErrorAttribute: HandleErrorAttribute
        {
            public override void OnException(ExceptionContext filterContext)
            {
                // 异常的具体信息
                var exceptionType = filterContext.Exception.InnerException.GetType().FullName;
                var exceptionMessage = filterContext.Exception.InnerException.Message;
                var exceptionMethod = filterContext.Exception.TargetSite;
                var exceptionStackTrace = filterContext.Exception.StackTrace;
    
                // 写入日志文件
                filterContext.ExceptionHandled = true;
                if (filterContext.HttpContext.Request.IsAjaxRequest())
                {
                    // 返回统一的错误信息
                    var result = new ResultModel();
                    filterContext.HttpContext.Response.ContentType = "application/json";
                    filterContext.HttpContext.Response.Write(Newtonsoft.Json.JsonConvert.SerializeObject(result));
                    filterContext.HttpContext.Response.End();
                }
                else
                {
                    // 返回统一的错误页面
                    filterContext.HttpContext.Response.Redirect("/Home/Error");
                    base.OnException(filterContext);
                    filterContext.HttpContext.Response.End();
                }
            }
        }
    }

    5、过滤器的注册,通过特性的方式将过滤器标注在Action上,或者在全局中进行注册,让所有的Action都使用。比如在Asp.NET MVC中提供的App_Start文件的FilterConfig类中注册。

    using System.Web;
    using System.Web.Mvc;
    using TQF.CustomFilterAttribute.App_Start.Filter;
    
    namespace TQF.CustomFilterAttribute
    {
        public class FilterConfig
        {
            public static void RegisterGlobalFilters(GlobalFilterCollection filters)
            {
                // filters.Add(new HandleErrorAttribute());
                // filters.Add(new TestHandleErrorAttribute());
                // filters.Add(new TestMvcActionFilterAttribute());
                // filters.Add(new TestMvcAuthorizeAttribute());
                // filters.Add(new TestFilter());
            }
        }
    }
     

    或者在Global.asaxApplication_Start方法中GlobalFilters注册。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Http;
    using System.Web.Mvc;
    using System.Web.Optimization;
    using System.Web.Routing;
    using TQF.CustomFilterAttribute.App_Start.Filter;
    
    namespace TQF.CustomFilterAttribute
    {
        public class WebApiApplication : System.Web.HttpApplication
        {
            protected void Application_Start()
            {
                //AreaRegistration.RegisterAllAreas();
                GlobalConfiguration.Configure(WebApiConfig.Register);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);
                GlobalFilters.Filters.Add(new TestHttpActionFilterAttribute());
            }
        }
    }

    注意ASP.NET WebApi的fliter不能在FilterConfig类中注册,必须在WebApiConfig类中注册。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Http;
    using TQF.CustomFilterAttribute.App_Start.Filter;
    
    namespace TQF.CustomFilterAttribute
    {
        public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API 配置和服务
    
                // Web API 路由
                config.MapHttpAttributeRoutes();
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                config.Filters.Add(new TestHttpActionFilterAttribute());
            }
        }
    }

    四、总结

      1、过滤器提供AOP的面向切面的关注点,动态注入业务逻辑,将相关的非主业务逻辑进行优雅解耦,并且可以使用特性的方式便利添加在各个Action上。

      2、通过自定义过滤器,重写过滤器的虚方法,使用方法中提供的参数上下文信息(包含请求数据的请求体、请求头、返回数据的请求结果、异常信息)来处理业务。

      3、各过滤器的执行顺序依次是IAuthorizationFilter->IActionFilter->IResultFilter->IExceptionFilter,首先是授权的验证,其次是Action方法的处理过程和返回结果、最后是产生的异常信息。

      4、对于特性与注释的区别,注释是在代码编译器编译阶段会丢弃的部分,而特性是代码的一部分会编译到程序集(Assembly)的元数据(Metadata)中,在程序运行时候依据元数据反射的方式获取相应的特性。

  • 相关阅读:
    今天是周日,一如既往的在加班
    懒出来的框架
    把Visio文档中形状信息导出到XML文件的VBA代码
    DataGridView多线程更新数据的问题的解决办法
    为VS定制一个自己的代码生成器
    安装VS2012之后自己开发的自定义工具没法使用问题的解决办法
    通过RSA进行私钥加密公钥解密算法的进一步改进
    程序员在职场 该反思了吗?
    图片与字节数组相互转换的方法
    jQuery Ajax 方法调用 Asp.Net WebService 的详细例子
  • 原文地址:https://www.cnblogs.com/tuqunfu/p/15630134.html
Copyright © 2011-2022 走看看