ASP.NET Core - 在ActionFilter中使用依赖注入
上次ActionFilter引发的一个EF异常,本质上是对Core版本的ActionFilter的知识掌握不够牢固造成的,所以花了点时间仔细阅读了微软的官方文档。发现除了IActionFilter、IAsyncActionFilter的问题,还有一个就是依赖注入在ActionFilter上的使用也是需要注意的地方。
当我们的ActionFilter需要使用某个Service的时候,我们一般会通过构造函数注入。
演示一下,首先自定义一个ActionFilter,通过构造函数注入IMyService:
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());
}
}
但是我们在使用Attribute的时候VS直接给出红色提示,需要传入构造函数的参数,否则无法编译过去。

当然我们可以直接new一个MyService来当做参数,但是很显然这样就失去了注入的那些好处了。
在ActionFilter中使用依赖注入
在ASP.NET Core的ActionFilter中使用依赖注入主要有两种方式:
- ServiceFilterAttribute
- TypeFilterAttribute
ServiceFilterAttribute
使用ServiceFilterAttribute可以使你的ActionFilter完成依赖注入。其实就是把你要用的ActionFilter本身注册为一个Service注册到DI容器中。通过ServiceFilter从容器中检索你的ActionFilter,并且注入到需要的地方。所以第一步就是要注册你的ActionFilter:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyService,MyService>();
services.AddScoped(typeof(FilterInjectAttribute));
services.AddControllers();
services.AddRazorPages();
}
然后新建一个Controller,在Action上使用ServiceFilter:
[ServiceFilter(typeof(FilterInjectAttribute))]
public string DI()
{
Console.WriteLine("HomeController method DI running .");
return "DI";
}
运行一下,在浏览器里访问下对应的path,可以看到MyService已经注入到FilterInjectAttribute中:

ServiceFilterAttribute的IsReusable属性:
ServiceFilter有一个属性叫IsReusable。从字面意思也很好理解,就是是否可重用的意思。显而易见如果这个属性设置为True,那么多个请求就会复用这个ActionFilter,这就有点像是单例的意思了。
[ServiceFilter(typeof(FilterInjectAttribute), IsReusable = true)]
public string DI()
{
Console.WriteLine("HomeController method DI running .");
return "DI";
}
运行一下,多次在浏览器中访问对应的action的path,可以看到FilterInjectAttribute的构造函数只会执行一次。

这里有一个重要提示, ASP.NET Core runtime 并不保证这个filter是真正的单例。所以不要试图使用这个属性来实现单例,并且业务系统依赖这个单例。
TypeFilterAttribute
使用TypeFilterAttribute也可以使你的ActionFilter完成依赖注入。它跟ServiceFilterAttribute差不多,但是使用TypeFilterAttribute注入的ActionFilter并不从DI容器中查找,而是直接通过Microsoft.Extensions.DependencyInjection.ObjectFactory来实例化对象。所以我们的FilterInjectAttribute不需要提前注册到DI容器中。
首先注释掉FilterInjectAttribute的注册代码:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMyService,MyService>();
//services.AddScoped(typeof(FilterInjectAttribute));
services.AddControllers();
services.AddRazorPages();
}
改用TypeFilterAttribute:
[TypeFilter(typeof(FilterInjectAttribute))]
public string DI()
{
Console.WriteLine("HomeController method DI running .");
return "DI";
}
运行一下,在浏览器里访问下对应的path,可以看到MyService已经注入到FilterInjectAttribute中:

TypeFilterAttribute的IsReusable属性:
跟上面的ServiceFilter一样,ASP.NET Core runtime 并不保证这个filter是真正的单例,这里就不多啰嗦了。
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 .");
}
}
在使用的时候传入两个参数:
[TypeFilter(typeof(FilterInjectAttribute), Arguments = new object[] { "HAHA", "HOHO" })]
public string DI()
{
Console.WriteLine("HomeController method DI running .");
return "DI";
}
运行一下看到两个参数被传入了FilterInjectAttribute的构造器:

总结
- ActionFilterAttribute的依赖注入可以通过ServiceFilterAttribute,TypeFilterAttribute来实现
- ServiceFilterAttribute是通过DI容器来管理ActionFilterAttribute;TypeFilterAttribute则是通过一个工厂直接实例化,所以使用前不需要注册到DI容器中。
- IsReusable属性可以实现类似单例的功能,但是运行时并不保证唯一单例。
- TypeFilterAttribute的Arguments属性可以作为参数列表。当实例化ActionFilterAttribute的时候如果构造器参数类型没有在DI容器中注册那么会尝试从Arguments列表中取。
ASP.NET Core - 在ActionFilter中使用依赖注入的更多相关文章
- ASP.NET Core 新建线程中使用依赖注入的问题
问题来自博问的一个提问 .net core 多线程数据保存的时候DbContext被释放 . TCPService 通过构造函数注入了 ContentService , ContentService ...
- ASP.NET Core 1.0 中的依赖项管理
var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...
- 在.NET Core控制台程序中使用依赖注入
之前都是在ASP.NET Core中使用依赖注入(Dependency Injection),昨天遇到一个场景需要在.NET Core控制台程序中使用依赖注入,由于对.NET Core中的依赖注入机制 ...
- Asp.Net Core 第04局:依赖注入
总目录 前言 本文介绍Asp.Net Core中默认的依赖注入(DI)模式. 环境 1.Visual Studio 2017 2.Asp.Net Core 2.2 开局 第一手:依赖注入说明 1.一个 ...
- ASP.NET Core应用的7种依赖注入方式
ASP.NET Core框架中的很多核心对象都是通过依赖注入方式提供的,如用来对应用进行初始化的Startup对象.中间件对象,以及ASP.NET Core MVC应用中的Controller对象和V ...
- dotnet core在Task中使用依赖注入的Service/EFContext
C#:在Task中使用依赖注入的Service/EFContext dotnet core时代,依赖注入基本已经成为标配了,这就不多说了. 前几天在做某个功能的时候遇到在Task中使用EF DbCon ...
- ASP.NET Core MVC 控制器创建与依赖注入
本文翻译自<Controller activation and dependency injection in ASP.NET Core MVC>,由于水平有限,故无法保证翻译完全准确,欢 ...
- ASP.NET Core 1.0基础之依赖注入
来源https://docs.asp.net/en/latest/fundamentals/dependency-injection.html ASP.NET Core 1.0在设计上原生就支持和 ...
- ASP.NET Core 配置文件(无处不在的依赖注入)
前烟: .NET Core 中取消了以往的 XML 节点配置文件,改用了 *.json 格式. 在 Startup.cs 文件中,构造方法 build appsetting.json 文件, 本文主要 ...
随机推荐
- 洛谷P4180【Beijing2010组队】次小生成树Tree
题目描述: 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还 ...
- javaweb 中 error-page
我们的请求找不到时,会跳到错误页面,tomcat提供了一个错误页面,但是不太好.分析:tomcat自带错误页面不好的原因:有一下两点: 1.不好看: 2.不能为seo做出贡献.思考:如何解决以上问题? ...
- 吴裕雄--天生自然KITTEN编程:滂沱大雨
- SCSS 与 Sass 异同
SCSS 是 Sass 3 引入新的语法,其语法完全兼容 CSS3,并且继承了 Sass 的强大功能.也就是说,任何标准的 CSS3 样式表都是具有相同语义的有效的 SCSS 文件.另外,SCSS 还 ...
- 解决appium升级后不支持使用name定位的问题
前言 之前一直用的appium1.4版本,最近升级到了1.6突然发现之前的脚本好多都跑失败了,一看报错: selenium.common.exceptions.InvalidSelectorExcep ...
- jsde与gulp使用说明
jade是一款基于haml的html模板引擎,已改为pug 1.全局安装 npm install jade -g 新建一个jade文件夹,再建一个后缀名为.jade的文件编辑.jade文件 jade ...
- CSS中网格布局实战(初级)
大家好,网格布局是我们在网页布局中经常用到的,那这里我就给大家分享一篇简单的网格布局,让大家能简单明了的了解网格布局的基本内容.闲话不多说,直接进入主题! 第一步,基本的框架结构.这里直接一个div来 ...
- 小程序中,设置Sticky定位,距离上面会有一个缝隙
近日,在小程序中使用sticky定位实现吸顶效果,不料入了一个大坑. 定位后,距离有position: relative:的上级元素有个1px大小的缝隙条,透过缝隙,滑动时可看到定位标题下的内容. 此 ...
- sofa-bolt源码阅读(1)-服务端的启动
Bolt服务器的核心类是RpcServer,启动的时候调用父类AbstractRemotingServer的startup方法. com.alipay.remoting.AbstractRemotin ...
- 达拉草201771010105《面向对象程序设计(java)》第十五周学习总结
达拉草201771010105<面向对象程序设计(java)>第十四周学习总结 第一部分:理论知识 JAR文件: 1.Java程序的打包:程序编译完成后,程序员 将.class文件压缩打包 ...