NetCore过滤器

.netcore过滤器有以下几种类型

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace NetCoreApp.Filters
{
    //优先级1:权限过滤器:它在Filter Pipleline中首先运行,并用于决定当前用户是否有请求权限。如果没有请求权限直接返回。
    public class MyAuthorization : IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {

        }
    }
    //优先级2:资源过滤器: 它在Authorzation后面运行,同时在后面的其它过滤器完成后还会执行。Resource filters 实现缓存或其它性能原因返回。因为它运行在模型绑定前,所以这里的操作都会影响模型绑定。
    public class MyResourceFilterAttribute : IResourceFilter
    {
        //这个ResourceFiltersAttribute是最适合做缓存了,在这里做缓存有什么好处?因为这个OnResourceExecuting是在控制器实例化之前运营,如果能再这里获取ViewReuslt就不必实例化控制器,在走一次视图了,提升性能
        private static readonly Dictionary _Cache = new Dictionary();
        private string _cacheKey;
        /// 
        /// 这个方法会在控制器实例化之前之前
        /// 
        /// 
        public void OnResourceExecuting(ResourceExecutingContext context)
        {
            _cacheKey = context.HttpContext.Request.Path.ToString();//这个是请求地址,它肯定是指向的视图
            if (_Cache.ContainsKey(_cacheKey))
            {
                var cachedValue = _Cache[_cacheKey] as ViewResult;
                if (cachedValue != null)
                {
                    context.Result = cachedValue;
                }
            }
        }
        /// 
        /// 这个方法是是Action的OnResultExecuted过滤器执行完之后在执行的(每次执行完Action之后得到就是一个ViewResult)
        /// 
        /// 
        public void OnResourceExecuted(ResourceExecutedContext context)
        {
            _cacheKey = context.HttpContext.Request.Path.ToString();//这个是请求地址
            if (!string.IsNullOrEmpty(_cacheKey) && !_Cache.ContainsKey(_cacheKey))
            {
                //因为这个方法是是Action的OnResultExecuted过滤器执行完之后在执行的,所以context.Result必然有值了,这个值就是Action方法执行后得到的ViewResult
                var result = context.Result as ViewResult;
                if (result != null)
                {
                    _Cache.Add(_cacheKey, result);
                }
            }
        }
    }
    //优先级3:方法过滤器:它会在执行Action方法前后被调用。这个可以在方法中用来处理传递参数和处理方法返回结果。
    public class MyActionFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            //context.HttpContext.Response.WriteAsync("abc");
        }

    }
    //优先级4:异常过滤器:被应用全局策略处理未处理的异常发生前异常被写入响应体
    public class MyExceptionFilterAttribute:ExceptionFilterAttribute
    {
        private readonly IModelMetadataProvider _moprovider;
        public MyExceptionFilterAttribute(IModelMetadataProvider moprovider)
        {
            this._moprovider = moprovider;
        }
        public override void OnException(ExceptionContext context)
        {
            base.OnException(context);
            if (!context.ExceptionHandled)//如果异常没有被处理过
            {
                string controllerName = (string)context.RouteData.Values["controller"];
                string actionName = (string)context.RouteData.Values["action"];
                //string msgTemplate =string.Format( "在执行controller[{0}的{1}]方法时产生异常",controllerName,actionName);//写入日志

                if (this.IsAjaxRequest(context.HttpContext.Request))
                {

                    context.Result = new JsonResult(new
                    {
                        Result = false,
                        PromptMsg = "系统出现异常,请联系管理员",
                        DebugMessage = context.Exception.Message
                    });
                }
                else
                {
                    var result = new ViewResult { ViewName = "~Views/Shared/Error.cshtml" };
                    result.ViewData = new ViewDataDictionary(_moprovider, context.ModelState);
                    result.ViewData.Add("Execption", context.Exception);
                    context.Result = result;
                }
                    
;            }
        }
        //判断是否为ajax请求
        private bool IsAjaxRequest(HttpRequest request)
        {
            string header = request.Headers["X-Requested-With"];
            return "XMLHttpRequest".Equals(header);
        }
    }
    //优先级5:结果过滤器:它可以在执行Action结果之前执行,且执行Action成功后执行,使用逻辑必须围绕view或格式化执行结果。
    public class MyResultFilterAttribute : ResultFilterAttribute
    {
        public override void OnResultExecuting(ResultExecutingContext context)
        {
            base.OnResultExecuting(context);
        }
        public override void OnResultExecuted(ResultExecutedContext context)
        {
            base.OnResultExecuted(context);
        }
    }
}

过滤器的全局注册

Startup.cs中

namespace NetCoreApp
{
    public class Startup
    {
        public IConfiguration Configuration { get; } //构造函数注入:Configuration用于读取配置文件的
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            
            services.Configure(options =>
            {

                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            Action filters = new Action(r=> {
                r.Filters.Add(typeof(MyAuthorization));
                r.Filters.Add(typeof(MyExceptionFilterAttribute));
                r.Filters.Add(typeof(MyResourceFilterAttribute));
                r.Filters.Add(typeof(MyActionFilterAttribute));
                r.Filters.Add(typeof(MyResultFilterAttribute));
            });
            

            services.AddMvc(filters) //注册全局过滤器
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services.AddAuthentication();
            services.AddSession();       
        }   
    }
}

局部注册

我们创建了过滤器,除了注册这个过滤器为全局过滤器外,还可以在单个控制器,或者单个方法上使用过滤器

以控制器为列,平常我们直接在在控制器上打上我们的创建的过滤器的特性标签就好了

[MyActionFilter] //在这里打上你自己创建的过滤器名称就好了
public class HomeController : Controller
{
    private IUser _user { get; set; }
    public HomeController(IUser user)//构造函数
    {
        this._user = user;
    }
    public IActionResult Index()
    {
        ViewBag.Now = DateTime.Now.ToString();
        return View();
    }
}

但是,如果你的过滤器中使用了,构造函数注入对象的形式,直接在控制器上打特性标签就行不通了。(因为特性需要的参数必须是在这个特性构造前就已经写好了的,不能依赖注入提供的) 

例如:

public class MyActionFilterAttribute : ActionFilterAttribute
{
    private ILogger _logger;
    public MyActionFilterAttribute(ILogger logger)
    {
        this._logger = logger;
    }
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        _logger.LogWarning("在这里执行了Action方法");//记录日志
    }
}

这时候我们就需要用另外一种形式对我们的过滤器进行注册了

方式一:使用TypeFilter这种形式,

[TypeFilter(typeof(MyActionFilterAttribute))] 就表示这个MyActionFilterAttribute这个过滤器对象的创建交给DI来完成。

[TypeFilter(typeof(MyActionFilterAttribute))] //这时候需要这样使用
public class HomeController : Controller
{
    public IActionResult Index()
    {
        ViewBag.Now = DateTime.Now.ToString();
        return View();
    }
}

方式二:使用ServiceFilter这种形式

[ServiceFilter(typeof(MyActionFilterAttribute))]就表示这个MyActionFilterAttribute这个过滤器对象的创建交给DI来完成

但是这种方式需要多一个配置,就是需要在Startup.cs类中的ConfigureServices方法中添加一段配置代码

services.AddScoped(typeof(MyActionFilterAttribute));

这样就可以在可控制器中使用ServiceFilter了

[ServiceFilter(typeof(MyActionFilterAttribute))]
public class HomeController : Controller
{    
    public IActionResult Index()
    {
        ViewBag.Now = DateTime.Now.ToString();
        return View();
    }
}

 

你可能感兴趣的