How do I resolve Dependency Injection in MVC Filter attributes

可紊 提交于 2019-12-03 06:28:55
Nicholas Blumhardt

The ExtensibleActionInvoker claims to be able to perform property injection on action filters.

Correct - but don't confuse action filters with the attributes that might not implement them. The cleanest way to approach this in ASP.NET MVC is to split responsibilities, even though the MVC framework allows you to combine them.

E.g., use a pair of classes - an attribute class that holds data only:

// Just a regular old attribute with data values
class SomeAttribute : Attribute { ... }

And a filter that has dependencies injected:

// Gets dependencies injected
class SomeFilter : IActionFilter { ... }

SomeFilter just uses the typical approach of getting the SomeAttribute attribute from the controller or action method via GetCustomAttributes() to do whatever work is needed.

You can then use ExtensibleActionInvoker to wire up the filter:

builder.RegisterControllers(...).InjectActionInvoker();
builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>();
builder.RegisterType<SomeFilter>().As<IActionFilter>();

It might be a little more code than you'd write using the attribute-as-filter approach, but the quality of the code will be better in the long run (e.g. by avoiding the limitations of attributes and the awkwardness of the Service Locator solutions.)

I would seem that the easiest way to achieve this is to bite the bullet and accept a dependency on autofac itself. While a dependency on the IoC is in itself an anti-pattern, it's somewhat more pallatable. You can implement a property as follows:

public class UserAuthorizeAttribute : AuthorizeAttribute
{            
    public IUserRepository CurrentUserService
    {
        get
        {
            var cpa = (IContainerProviderAccessor)HttpContext.Current.ApplicationInstance;
            var cp = cpa.ContainerProvider;
            return cp.RequestLifetime.Resolve<IUserRepository>();
        }
    }
}
     ...

There's no straight-forward way to do this prior to MVC2. There is an interesting technique detailed here: http://www.mattlong.com.au/?p=154. I'd suggest using the Common Service Locator to abstract over this and locate your DI container.

If you're using MVC 3 then you can use MVC Service Location

Constructor injection seems to be impossible w/o changing way of filter registration.

Even in Asp.Net Mvc3:

One place where dependency injection has been difficult in the past is inside the filter attributes themselves. Because the .NET framework runtime is actually responsible for creating these attribute instances, we cannot use a traditional dependency injection strategy.

So - next best thing is property injection (Mvc3 provides some support for that out of the box).

Here's a how to for doing that manually.

I personally use MvcExtensions. I'm fine with registering them in different way. Here's usage.

Another thing You might want to investigate is MvcTurbine project. In contrast to MvcExtensions project which is more general - MvcTurbine is primarily for providing dependency injection support.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!