ASP.NET Core - 在ActionFilter中使用依赖注入

简介:

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列表中取。
Email:kklldog@gmail.com
作者:Agile.Zhou(kklldog)
出处:http://www.cnblogs.com/kklldog/

相关文章
|
10天前
|
数据可视化 网络协议 C#
C#/.NET/.NET Core优秀项目和框架2024年3月简报
公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享(欢迎关注公众号:追逐时光者,第一时间获取每周精选分享资讯🔔)。
|
3月前
|
开发框架 前端开发 JavaScript
盘点72个ASP.NET Core源码Net爱好者不容错过
盘点72个ASP.NET Core源码Net爱好者不容错过
68 0
|
3月前
|
开发框架 .NET
ASP.NET Core NET7 增加session的方法
ASP.NET Core NET7 增加session的方法
37 0
|
1月前
|
开发框架 人工智能 .NET
C#/.NET/.NET Core拾遗补漏合集(持续更新)
C#/.NET/.NET Core拾遗补漏合集(持续更新)
|
1月前
|
开发框架 中间件 .NET
C# .NET面试系列七:ASP.NET Core
## 第一部分:ASP.NET Core #### 1. 如何在 controller 中注入 service? 在.NET中,在ASP.NET Core应用程序中的Controller中注入服务通常使用<u>依赖注入(Dependency Injection)</u>来实现。以下是一些步骤,说明如何在Controller中注入服务: 1、创建服务 首先,确保你已经在应用程序中注册了服务。这通常在Startup.cs文件的ConfigureServices方法中完成。例如: ```c# services.AddScoped<IMyService, MyService>(); //
60 0
|
2月前
|
开发框架 前端开发 .NET
福利来袭,.NET Core开发5大案例,30w字PDF文档大放送!!!
为了便于大家查找,特将之前开发的.Net Core相关的五大案例整理成文,共计440页,32w字,免费提供给大家,文章底部有PDF下载链接。
32 1
福利来袭,.NET Core开发5大案例,30w字PDF文档大放送!!!
|
2月前
|
算法 BI API
C#/.NET/.NET Core优秀项目和框架2024年1月简报
C#/.NET/.NET Core优秀项目和框架2024年1月简报
|
3月前
|
开发框架 前端开发 .NET
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
ASP.NET CORE 3.1 MVC“指定的网络名不再可用\企图在不存在的网络连接上进行操作”的问题解决过程
38 0
|
30天前
|
开发框架 前端开发 .NET
进入ASP .net mvc的世界
进入ASP .net mvc的世界
28 0
|
1月前
|
开发框架 前端开发 .NET
C# .NET面试系列六:ASP.NET MVC
<h2>ASP.NET MVC #### 1. MVC 中的 TempData\ViewBag\ViewData 区别? 在ASP.NET MVC中,TempData、ViewBag 和 ViewData 都是用于在控制器和视图之间传递数据的机制,但它们有一些区别。 <b>TempData:</b> 1、生命周期 ```c# TempData 的生命周期是短暂的,数据只在当前请求和下一次请求之间有效。一旦数据被读取,它就会被标记为已读,下一次请求时就会被清除。 ``` 2、用途 ```c# 主要用于在两个动作之间传递数据,例如在一个动作中设置 TempData,然后在重定向到另
95 5