上次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中使用依赖注入主要有两种方式:

  1. ServiceFilterAttribute
  2. 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的构造器:

总结

  1. ActionFilterAttribute的依赖注入可以通过ServiceFilterAttribute,TypeFilterAttribute来实现
  2. ServiceFilterAttribute是通过DI容器来管理ActionFilterAttribute;TypeFilterAttribute则是通过一个工厂直接实例化,所以使用前不需要注册到DI容器中。
  3. IsReusable属性可以实现类似单例的功能,但是运行时并不保证唯一单例。
  4. TypeFilterAttribute的Arguments属性可以作为参数列表。当实例化ActionFilterAttribute的时候如果构造器参数类型没有在DI容器中注册那么会尝试从Arguments列表中取。

ASP.NET Core - 在ActionFilter中使用依赖注入的更多相关文章

  1. ASP.NET Core 新建线程中使用依赖注入的问题

    问题来自博问的一个提问 .net core 多线程数据保存的时候DbContext被释放 . TCPService 通过构造函数注入了 ContentService , ContentService ...

  2. ASP.NET Core 1.0 中的依赖项管理

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  3. 在.NET Core控制台程序中使用依赖注入

    之前都是在ASP.NET Core中使用依赖注入(Dependency Injection),昨天遇到一个场景需要在.NET Core控制台程序中使用依赖注入,由于对.NET Core中的依赖注入机制 ...

  4. Asp.Net Core 第04局:依赖注入

    总目录 前言 本文介绍Asp.Net Core中默认的依赖注入(DI)模式. 环境 1.Visual Studio 2017 2.Asp.Net Core 2.2 开局 第一手:依赖注入说明 1.一个 ...

  5. ASP.NET Core应用的7种依赖注入方式

    ASP.NET Core框架中的很多核心对象都是通过依赖注入方式提供的,如用来对应用进行初始化的Startup对象.中间件对象,以及ASP.NET Core MVC应用中的Controller对象和V ...

  6. dotnet core在Task中使用依赖注入的Service/EFContext

    C#:在Task中使用依赖注入的Service/EFContext dotnet core时代,依赖注入基本已经成为标配了,这就不多说了. 前几天在做某个功能的时候遇到在Task中使用EF DbCon ...

  7. ASP.NET Core MVC 控制器创建与依赖注入

    本文翻译自<Controller activation and dependency injection in ASP.NET Core MVC>,由于水平有限,故无法保证翻译完全准确,欢 ...

  8. ASP.NET Core 1.0基础之依赖注入

      来源https://docs.asp.net/en/latest/fundamentals/dependency-injection.html ASP.NET Core 1.0在设计上原生就支持和 ...

  9. ASP.NET Core 配置文件(无处不在的依赖注入)

    前烟: .NET Core 中取消了以往的 XML 节点配置文件,改用了 *.json 格式. 在 Startup.cs 文件中,构造方法 build appsetting.json 文件, 本文主要 ...

随机推荐

  1. 《自动化平台测试开发-Python测试开发实战》新书出版了

    首先 第一本书,当初在百度阅读初步写了个电子版,刚一上线不久即收到了数百位读者朋友阅读收藏购买,于是顺利成章就出版了纸质书. <软件自动化测试开发>认真看过的读者应该都知道,介绍的主要是自 ...

  2. Android中的AlertDialog和ProgressDialog用法

    手机APP对话框是很多APP都有的下面来看下怎么实现的吧, 打开Android studio 然他自动创建好布局和类; 下面我们修改activity_main.xml中的代码 <?xml ver ...

  3. 前端学习之路CSS基础学习二

    CSS属性相关 样式操作: (1)width:为元素设置宽度 (2)height:为元素设置高度 ps:块儿级标签才能设置长宽行内标签设置长宽没有任何影响 p{ width: 30px; height ...

  4. shell的循环嵌套语法

    测试shell的循环嵌套语法 [root@localhost test]# vi Xunhuanqiantao.sh #!/bin/bash #程序功能描述: # 测试循环嵌套 #作者:孤舟点点 #版 ...

  5. MySql之增删改查 · YbWork's Studio

    前提:在进行"增删改查"的操作之前,先建立一个包含数据表student的数据库(具体操作可以见MySQL之最基本命令): 1."增"--添加数据 1.1 为表中 ...

  6. Android 粘合剂'Binder'

    背景知识 要详细掌握Android 的Binder通信机制需要先提前了解一些通信原理与Linux系统的基础知识. RPC RPC(Remote Procedure Call),即远程过程调用,也被称为 ...

  7. Java程序监控---Metrics

    概念 Metrics是一个给JAVA服务的各项指标提供度量工具的包,在JAVA代码中嵌入Metrics代码,可以方便的对业务代码的各个指标进行监控 目前最为流行的 metrics 库是来自 Coda ...

  8. LeetCode 31:递归、回溯、八皇后、全排列一篇文章全讲清楚

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天我们讲的是LeetCode的31题,这是一道非常经典的问题,经常会在面试当中遇到.在今天的文章当中除了关于题目的分析和解答之外,我们还会 ...

  9. Python——2list和tuple类型

    */ * Copyright (c) 2016,烟台大学计算机与控制工程学院 * All rights reserved. * 文件名:text.cpp * 作者:常轩 * 微信公众号:Worldhe ...

  10. USB小白学习之路(4)HID键盘程序

    HID键盘程序 1. 特别注意 需要特别注意,各个例程中的设备描述符,配置描述符等各种描述符都是已经配置好了的,我们需要做的只是在例程中将代码修改为自己需要的部分即可,一般情况下是不可以串搭配的. 2 ...