ASP.NET Core - in dependency injection using ActionFilter

Last ActionFilter caused by a EF anomaly , in essence, is a version of the Core Knowledge ActionFilter not strong enough grasp of cause, it took time to read Microsoft's official documentation. In addition to problems found IActionFilter, IAsyncActionFilter, there is a place on the dependency injection ActionFilter use also need to pay attention.
When our ActionFilter need to use a Service, we usually injected through the constructor.
Show you, first customize a ActionFilter, IMyService injected through the constructor:

    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());
        }
    }

But we VS given directly when using Attribute red tips, need to pass arguments to the constructor, or can not compile in the past.

Of course, we can directly to MyService as a new parameter, but it is clear that those who lost the benefits of the injection.

In use dependency injection ActionFilter

There are two ways to use dependency injection in ASP.NET Core of ActionFilter in:

  1. ServiceFilterAttribute
  2. TypeFilterAttribute

ServiceFilterAttribute

Use ServiceFilterAttribute can make your ActionFilter complete dependency injection. In fact, you want to use ActionFilter registered itself as a Service registered the DI container. Retrieving your ActionFilter from the container through ServiceFilter, and injected where needed. So the first step is to register your ActionFilter:

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

            services.AddControllers();
            services.AddRazorPages();
        }

Then create a new Controller, use ServiceFilter in Action:

        [ServiceFilter(typeof(FilterInjectAttribute))]
        public string DI()
        {
            Console.WriteLine("HomeController method DI running .");

            return "DI";
        }

Running about, path in the browser under the corresponding access, you can see MyService has been injected into the FilterInjectAttribute in:

ServiceFilterAttribute of IsReusable attributes:

ServiceFilter has a property called IsReusable. It is well understood from the literal meaning, that is, whether reusable meaning. If this obvious property is set to True, the multiple requests will reuse this ActionFilter, It's a bit like a singleton mean.

        [ServiceFilter(typeof(FilterInjectAttribute), IsReusable = true)]
        public string DI()
        {
            Console.WriteLine("HomeController method DI running .");

            return "DI";
        }

Run it several times to access the corresponding action in the browser's path, you can see FilterInjectAttribute constructor only once.

There is an important tips, ASP.NET Core Runtime does not guarantee that the filter is a true singleton . So do not try to use this property to achieve a singleton, and business systems rely on this single case.

TypeFilterAttribute

Use TypeFilterAttribute can also make your ActionFilter complete dependency injection. It ServiceFilterAttribute with similar, but not the use of TypeFilterAttribute injected ActionFilter Find DI container, but directly to instantiate an object by Microsoft.Extensions.DependencyInjection.ObjectFactory. So we do not need to register in advance to FilterInjectAttribute DI container.
First comment out FilterInjectAttribute registration code:

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

            //services.AddScoped(typeof(FilterInjectAttribute));

            services.AddControllers();
            services.AddRazorPages();
        }

Instead TypeFilterAttribute:

        [TypeFilter(typeof(FilterInjectAttribute))]
        public string DI()
        {
            Console.WriteLine("HomeController method DI running .");

            return "DI";
        }

Running about, path in the browser under the corresponding access, you can see MyService has been injected into the FilterInjectAttribute in:

TypeFilterAttribute of IsReusable attributes:

As with the above ServiceFilter, ASP.NET Core Runtime does not guarantee that this filter is really a single case , not more long-winded here.

TypeFilterAttribute's Arguments property:

Arguments parameter is a TypeFilterAttribute with ServiceFilterAttribute important difference, ServiceFilterAttribute not this property. Arguments of type object array. If its constructor parameter type found in the vessel DI, we will continue receiving the Arguments sequentially through the list of instantiated TypeFilterAttribute ActionFilter.
The change FilterInjectAttribute plurality builder added two parameters, and the two parameters can not be guaranteed from the DI fetch:

    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 .");
        }
    }

Incoming when using two parameters:

        [TypeFilter(typeof(FilterInjectAttribute), Arguments  = new object[] { "HAHA", "HOHO" })]
        public string DI()
        {
            Console.WriteLine("HomeController method DI running .");

            return "DI";
        }

Running about seeing two parameters are introduced to FilterInjectAttribute constructor:

to sum up

  1. ActionFilterAttribute dependency injection may be achieved by ServiceFilterAttribute, TypeFilterAttribute
  2. ServiceFilterAttribute is managed by DI container ActionFilterAttribute; TypeFilterAttribute is instantiated by a plant directly, it is not required to register prior to use DI container.
  3. IsReusable properties similar function can be achieved in a single embodiment, but does not guarantee that the only single embodiment runtime.
  4. TypeFilterAttribute Arguments property can be used as the parameter list. If the constructor parameter types are not registered in DI then it will attempt to remove the container from the list when Arguments ActionFilterAttribute the instantiated.

Guess you like

Origin www.cnblogs.com/kklldog/p/di-in-core-actionfilter.html