• ASP.NET Core Filter如何支持依赖注入?


    简述

    1、可以通过全局注册,支持依赖注入

    2、通过TypeFilter(typeof(Filter)) 标记在方法,标记在控制器

    3、通过ServiceFilter(typeof(Filter))标记在方法,标记在控制器,必须要注册Filter这类;

    TypeFilter和ServiceFilter的本质是实现了一个IFilterFactory接口;

    实践

    先创建一个MVC项目,然后我们创建一个自定义的过滤器

        public class MyFilter: ActionFilterAttribute    {        public override void OnActionExecuting(ActionExecutingContext context)        {            base.OnActionExecuting(context);        }    }

    这里我们没有做任何事,现在需求来了,我们需要过滤器中记录日志,这时候我们就需要注入Logger,代码大致如下。

       public class MyFilter: ActionFilterAttribute    {        private readonly ILogger<MyFilter> _logger;        public MyFilter(ILogger<MyFilter> logger)        {            _logger = logger;        }        public override void OnActionExecuting(ActionExecutingContext context)        {            _logger.LogInformation("do something.....");            base.OnActionExecuting(context);        }    }

        这样注入是不行的,会有问题,可以试一试,下面用TypeFilter和ServiceType

    ServiceFilter

    我们先来讲讲ServiceFilter,使用ServiceFilter很简单,我们改造一下controller里filter的调用,以及在ConfigureServices中进行注册。

    注意:这里AddSingleton只是出于演示,您可以根据您的需求自定义您的Filter实例的生命周期。

     [ServiceFilter(typeof(MyFilter))] public IActionResult Index()  {            return View(); }

    图片

    运行一下,我们可以看到已经起作用了。

    图片

    ServiceFilter最值得注意的就是需要对您定义的filter进行注册才能使用。

    为什么它需要事先注册对应的类型呢?我们研究一下源码就可以得知,它创建实例通是通过IServiceProvider中的GetRequiredService方法实现的,它的Type的实例直接从DI容器中获取。这也许就是它为啥叫ServiceFilter的原因吧。

    TypeFilter

    TypeFilter和ServiceFilter比较类似,我们改造一下

    图片

    是不是很像,它和ServiceFilter的区别是它不从DI容器中创建实例,所以不需要在ConfigureServices中进行注册就能使用。我们来看一下源码

    图片

    实际上,TypeFilter是通过ObjectFactory来创建实例的,ObjectFactory是ActivatorUtilities.CreateFactory创建出来的委托,对于没有注册的服务想创建实例,.net core提供的ActivatorUtilities就派上用场了。这么说可能有点抽象,我下面写一个小例子。

     public class Employee    {        private readonly ILogger<Employee> _logger;        private readonly string _name;        public Employee(ILogger<Employee>logger,string name)        {            _logger = logger;            _name = name;        }        public void Say()        {            _logger.LogInformation($"My name is {_name}");        }    }

    我创建了一个Employee类,构造器里有logger也有name,这种情况下,甚至构造器中有更多参数,我们想创造一个Employee的实例是不太容易的,这个时候就该ActivatorUtilities登场了。代码大致如下

    var factory = ActivatorUtilities.CreateFactory(typeof(Employee), new Type[] {typeof(string)});var employee = factory(_provider, new object[] {"Laosiji"}) as Employee;employee?.Say();

    这里我将IServiceProvider传递进去,同时还有额外的name参数,让它帮我们创造出实例,结果如下

    图片

    当然这只是一个简单的例子,帮助您理解ObjectFactory,ActivatorUtilities之间的关系,如果您感兴趣可以自己深入的研究一下。

    说回正题,TypeFilter是每次请求都会创建自定义Filter的实例的,也许有的小伙伴发现它还有别的参数,比如可以这样

      [TypeFilter(typeof(MyFilter),IsReusable = true)]

    IsReusable代表是否可以复用,默认值是false,设置为true的时候,可以起到类似单例的效果,但是框架并不能保证它每次都会是单例的,所以您有特殊要求,还是使用ServiceFilter比较妥当,IsReusable就不要动他了。

    ServiceFilter vs TypeFilter

    文章的最后,我们对他们进行一下总结

    1. ServiceFilter和TypeFilter都实现了IFilterFactory

    2. ServiceFilter需要对自定义的Filter进行注册,TypeFilter不需要

    3. ServiceFilter的Filter生命周期源自于您如何注册,而TypeFilter每次都会创建一个新的实例

  • 相关阅读:
    POJ 2187 Beauty Contest(凸包+旋转卡壳)
    POJ 3845 Fractal(计算几何の旋转缩放)
    POJ 1755 Triathlon(线性规划の半平面交)
    POJ 2540 Hotter Colder(半平面交)
    POJ 3525/UVA 1396 Most Distant Point from the Sea(二分+半平面交)
    POJ 3348 Cows(凸包+多边形面积)
    POJ 1228 Grandpa's Estate(凸包唯一性判断)
    POJ 2826 An Easy Problem?!(线段交点+简单计算)
    如何在ARC代码中混编非ARC代码
    给view 添加事件
  • 原文地址:https://www.cnblogs.com/qingfenglin/p/15251487.html
Copyright © 2020-2023  润新知