小伙伴们大家好,相信写过http://asp.net的小伙伴对过滤器(Filter
)一定不会陌生,今天我来跟大家分享一下如何在http://asp.net core Filter
中实现依赖注入,以及相关的技术细节。废话不多说,我们开始吧。
创建自定义过滤器
先创建一个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
和ServiceFilter
。
ServiceFilter
我们先来讲讲ServiceFilter
,使用ServiceFilter
很简单,我们改造一下controller
里filter
的调用,以及在ConfigureServices
中进行注册。
注意:这里AddSingleton
只是出于演示,您可以根据您的需求自定义您的Filter
实例的生命周期。
[ServiceFilter(typeof(MyFilter))]
public IActionResult Index()
{
return View();
}
运行一下,我们可以看到已经起作用了。
ServiceFilter
最值得注意的就是需要对您定义的filter
进行注册才能使用。
为什么它需要事先注册对应的类型呢?我们研究一下源码就可以得知,它创建实例通是通过IServiceProvider
中的GetRequiredService
方法实现的,它的Type
的实例直接从DI
容器中获取。这也许就是它为啥叫ServiceFilter
的原因吧。
下面给大家截了一段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
文章的最后,我们对他们进行一下总结
ServiceFilter
和TypeFilter
都实现了IFilterFactory
ServiceFilter
需要对自定义的Filter
进行注册,TypeFilter
不需要ServiceFilter
的Filter
生命周期源自于您如何注册,而TypeFilter
每次都会创建一个新的实例