C#基础系列过滤器与特性

摘要:
过滤器和特性结合在一起,在方法上优雅地使用过滤器。3.在过滤器中,。NETFrameWork提供了两种类型:一种是提供给ASP的筛选器。NETMVC在命名空间下使用System.Web。另一个是提供给ASP的过滤器。NETWebApi在命名空间下使用System.Web.Http.Filters。这两种类型不能混合使用,否则无法拦截并生效。

一、前言

   编程中我们会使用特性(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、自定义的特性和过滤器项目

   C#基础系列过滤器与特性第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)中,在程序运行时候依据元数据反射的方式获取相应的特性。

免责声明:文章转载自《C#基础系列过滤器与特性》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Qt使用镜像源快速安装与更新《学习opencv》笔记——矩阵和图像操作——cvAnd、cvAndS、cvAvg and cvAvgSdv下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

随便看看

天气插件(vue)和风天气插件

&lt:“center”:“left”:&lt:v=2.0(函数(d){varc=d.createElement('link')c.rel='stylesheet'.href='http://t.zoukankan.com/https;v=1.4.0'vars=d.createElement;...

阿里云oss对象存储在vue中的使用

阿里云对象存储OSS(ObjectStorageService)是阿里云提供的海量、安全、低成本、高持久的云存储服务。阿里云oss对象存储是阿里云提供的海量、安全、低成本、高持久的云存储服务,包括服务端加密、客户端加密、防盗链、IP黑白名单、细粒度权限管控、日志审计、WORM特性等。满足企业数据安全与合规要求多线BGP骨干网络。...

lstm与bilstm

背景学习和整理lstm和bilstm的理论知识。对于有序数据,bilstm具有数据信息的长、短存储功能。bilstm:它是前lstm和后lstm的组合。为什么需要lstm?它可以更好地捕捉远距离的依赖性。通过培训,你可以了解哪些信息需要记住,哪些信息需要忘记;我不认为他喜欢“否定”,即句子的情感分析是贬义的。“lstm建模有一个问题,它不能从后面到前面对信息...

uniApp之 顶部选项卡

为了在uniapp插件中创建类似于信息应用程序模板的功能,使用了官方的组件刷。起初,它无法滚动。后来,我看了一下官方网站,说有必要添加“滚动视图”标签,以记录第一次使用uniapp的应用程序。首先,在顶部制作一个选项卡,因为我只有两个项目,所以我将它们直接写入视图标记中{item.label}}然后编写以下内容。单击和滑动可以切换选项卡,所选样式:curre...

iOS开发(Swift):创建UINavigationView的三种方法

,表示window值我们会赋值。然后创建一个根视图控制器rootViewController,一个导航控制器navigationController。)-˃Bool{//Overridepointforcustomizationafterapplicationlaunch.window=UIWindowwindow.makeKeyAndVisible()ro...

微信小程序中使用Vant Weapp的ActionSheet上拉菜单出现的样式问题

以下修改的源码均在action-sheet组件中。在index.wxss:2.下方的取消按钮不居中,通过审查元素发现它的宽带已经超出了手机屏幕的宽度,出现的滚动条导致的,具体什么原因导致暂时不知,解决方案是给.van-action-sheet__cancel添加样式box-sizing:border-box可解决。在index.wxss:.van-actio...