- 一、在ActionFilter中使用依赖注入">一、在ActionFilter中使用依赖注入
- 1. ServiceFilterAttribute">1. ServiceFilterAttribute
- 2. ServiceFilterAttribute的IsReusable属性:">2. ServiceFilterAttribute的IsReusable属性:
- 3. TypeFilterAttribute">3. TypeFilterAttribute
- 4. TypeFilterAttribute的IsReusable属性:">4. TypeFilterAttribute的IsReusable属性:
- 5. TypeFilterAttribute的Arguments属性:">5. TypeFilterAttribute的Arguments属性:
- 二、总结">二、总结
但是我们在使用Attribute的时候VS直接给出红色提示,需要传入构造函数的参数,否则无法编译过去。
public interface IMyService
{
string GetServiceName();
}
public class MyService:IMyService
{
public MyService()
{
Console.WriteLine("Service {0} created .",GetServiceName());
}
public string GetServiceName()
{
return"MyService";
}
}
public class FilterInjectAttribute:ActionFilterAttribute
{
public FilterInjectAttribute(IMyService myService)
{
if(myService ==null)
{
throw new ArgumentNullException("myService");
}
Console.WriteLine("Service {0} was injected .", myService.GetServiceName());
}
}
当然我们可以直接new一个MyService来当做参数,但是很显然这样就失去了注入的那些好处了。
一、在ActionFilter中使用依赖注入
在ASP.NET Core的ActionFilter中使用依赖注入主要有两种方式:- ServiceFilterAttribute
- TypeFilterAttribute
1. ServiceFilterAttribute
使用ServiceFilterAttribute可以使你的ActionFilter完成依赖注入。其实就是把你要用的ActionFilter本身注册为一个Service注册到DI容器中。通过ServiceFilter从容器中检索你的ActionFilter,并且注入到需要的地方。所以第一步就是要注册你的ActionFilter:然后新建一个Controller,在Action上使用ServiceFilter:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyService,MyService>();
services.AddScoped(typeof(FilterInjectAttribute));
services.AddControllers();
services.AddRazorPages();
}
运行一下,在浏览器里访问下对应的path,可以看到MyService已经注入到FilterInjectAttribute中:
[ServiceFilter(typeof(FilterInjectAttribute))]
publicstring DI()
{
Console.WriteLine("HomeController method DI running .");
return "DI";
}
2. ServiceFilterAttribute的IsReusable属性:
ServiceFilter有一个属性叫IsReusable。从字面意思也很好理解,就是是否可重用的意思。显而易见如果这个属性设置为True,那么多个请求就会复用这个ActionFilter,这就有点像是单例的意思了。运行一下,多次在浏览器中访问对应的action的path,可以看到FilterInjectAttribute的构造函数只会执行一次。
[ServiceFilter(typeof(FilterInjectAttribute),IsReusable=true)]
public string DI()
{
Console.WriteLine("HomeController method DI running .");
return"DI";
}
这里有一个重要提示, ASP.NET Core runtime 并不保证这个filter是真正的单例。所以不要试图使用这个属性来实现单例,并且业务系统依赖这个单例。
3. TypeFilterAttribute
使用TypeFilterAttribute也可以使你的ActionFilter完成依赖注入。它跟ServiceFilterAttribute差不多,但是使用TypeFilterAttribute注入的ActionFilter并不从DI容器中查找,而是直接通过Microsoft.Extensions.DependencyInjection.ObjectFactory来实例化对象。所以我们的FilterInjectAttribute不需要提前注册到DI容器中。 首先注释掉FilterInjectAttribute的注册代码:- publicvoidConfigureServices(IServiceCollection services)
- {
- services.AddScoped
(); - //services.AddScoped(typeof(FilterInjectAttribute));
- services.AddControllers();
- services.AddRazorPages();
- }
改用TypeFilterAttribute:
- [TypeFilter(typeof(FilterInjectAttribute))]
- publicstring DI()
- {
- Console.WriteLine(“HomeController method DI running .”);
- return“DI”;
- }
运行一下,在浏览器里访问下对应的path,可以看到MyService已经注入到FilterInjectAttribute中:
4. TypeFilterAttribute的IsReusable属性:
跟上面的ServiceFilter一样,ASP.NET Core runtime 并不保证这个filter是真正的单例,这里就不多啰嗦了。5. TypeFilterAttribute的Arguments属性:
Arguments参数是TypeFilterAttribute跟ServiceFilterAttribute的一个重要区别,ServiceFilterAttribute并没有这属性。Arguments类型为object数组。通过TypeFilterAttribute实例化的ActionFilter,如果它的构造器中的参数类型在DI容器中找不到,会继续在Arguments参数列表里按顺序获取。改一下FilterInjectAttribute构造器多加入2个参数,并且保证这2个参数无法从DI中取到:
在使用的时候传入两个参数:
public class FilterInjectAttribute:ActionFilterAttribute
{
public FilterInjectAttribute(string arg1,IMyService myService,string arg2)
{
if(myService ==null)
{
throw new ArgumentNullException("myService");
}
Console.WriteLine("Service {0} was injected .", myService.GetServiceName());
Console.WriteLine("arg1 is {0} .", arg1);
Console.WriteLine("arg2 is {0} .", arg2);
Console.WriteLine("FilterInjectAttribute was created .");
}
}
运行一下看到两个参数被传入了FilterInjectAttribute的构造器:
[TypeFilter(typeof(FilterInjectAttribute),Arguments=newobject[]{"HAHA","HOHO"})]
public string DI()
{
Console.WriteLine("HomeController method DI running .");
return"DI";
}
二、总结
- ActionFilterAttribute的依赖注入可以通过ServiceFilterAttribute,TypeFilterAttribute来实现
- ServiceFilterAttribute是通过DI容器来管理ActionFilterAttribute;TypeFilterAttribute则是通过一个工厂直接实例化,所以使用前不需要注册到DI容器中。
- IsReusable属性可以实现类似单例的功能,但是运行时并不保证唯一单例。
- TypeFilterAttribute的Arguments属性可以作为参数列表。当实例化ActionFilterAttribute的时候如果构造器参数类型没有在DI容器中注册那么会尝试从Arguments列表中取。