微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

当我们的ActionFilter需要使用某个Service的时候,我们一般会通过构造函数注入。
演示一下,首先自定义一个ActionFilter,通过构造函数注入IMyService:

   public interface IMyService
    {
        string GetServiceName();
    }

    public class MyService : IMyService
    {
        public MyService()
        {
            Console.WriteLine($"Service {GetServiceName()} created.");
        }
        public string GetServiceName()
        {
            return "MyService";
        }
    }
 public class FilterInjectAttribute : ActionFilterattribute
    {
        public FilterInjectAttribute(IMyService myService)
        {
            if (myService == null)
            {
                throw new ArgumentException("myservice");
            }
            Console.WriteLine($"Service {myService.GetServiceName()} was injected.");
        }
    }

但是我们在Controller或Action中使用Attribute的时候VS直接给出红色提示,需要传入构造函数的参数,否则无法编译过去。

当然我们可以直接new一个MyService来当做参数,但是很显然这样就失去了注入的那些好处了。

在ASP.NET Core的ActionFilter中使用依赖注入主要有两种方式:

  1. ServiceFilterattribute

  2. TypeFilterattribute

1.ServiceFilterattribute 

使用ServiceFilterattribute可以使你的ActionFilter完成依赖注入。其实就是把你要用的ActionFilter本身注册一个Service注册到DI容器中。通过ServiceFilter从容器中检索你的ActionFilter,并且注入到需要的地方。所以第一步就是在Starup.cs中要注册你的ActionFilter:

     public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<IMyService, MyService>();
            services.AddScoped(typeof(FilterInjectAttribute));
            services.AddControllers();
        }

然后新建一个Controller,在Action上使用ServiceFilter:

        [ServiceFilter(typeof(FilterInjectAttribute))]
        [Route("/di")]
        public string DI()
        {
            Console.WriteLine("WeatherForecastController method DI running.");
            return "DI";
        }

运行一下,在浏览器里访问下对应的path,可以看到MyService已经注入到FilterInjectAttribute中:

ServiceFilter有一个属性叫IsReusable。从字面意思也很好理解,就是是否可重用的意思。显而易见如果这个属性设置为True,那么多个请求就会复用这个ActionFilter,这就有点像是单例的意思了。

        [ServiceFilter(typeof(FilterInjectAttribute),IsReusable =true)]
        [Route("/di")]
        public string DI()
        {
            Console.WriteLine("WeatherForecastController 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();
        }

改用TypeFilterattribute:

        [TypeFilter(typeof(FilterInjectAttribute))]
        [Route("/di")]
        public string DI()
        {
            Console.WriteLine("WeatherForecastController method DI running.");
            return "DI";
        }

调用结果:

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(IMyService myService,string arg1,string arg2)
        {
            if (myService == null)
            {
                throw new ArgumentException("myservice");
            }

            Console.WriteLine($"Service {myService.GetServiceName()} was injected.");
            Console.WriteLine($"arg1 is {arg1}.");
            Console.WriteLine($"arg2 is {arg2}.");

            Console.WriteLine("FilterInjectAttribute was created.");
        }
    }

在使用的时候传入两个参数:

        [TypeFilter(typeof(FilterInjectAttribute),Arguments = new object[] { "hello","world"})]
        [Route("/di")]
        public string DI()
        {
            Console.WriteLine("WeatherForecastController method DI running.");
            return "DI";
        }

运行一下看到两个参数被传入了FilterInjectAttribute的构造器:

总结

  1. ActionFilterattribute的依赖注入可以通过ServiceFilterattribute,TypeFilterattribute来实现

  2. ServiceFilterattribute是通过DI容器来管理ActionFilterattribute;TypeFilterattribute则是通过一个工厂直接实例化,所以使用前不需要注册到DI容器中。

  3. IsReusable属性可以实现类似单例的功能,但是运行时并不保证唯一单例。

  4. TypeFilterattribute的Arguments属性可以作为参数列表。当实例化ActionFilterattribute的时候如果构造器参数类型没有在DI容器中注册那么会尝试从Arguments列表中取。

参考链接https://mp.weixin.qq.com/s/8iwd7QeYeGMMcdt4KGkDrQ

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐