将依赖项注入 ASP.NET MVC 3 操作过滤器.这种方法有什么问题? [英] Injecting dependencies into ASP.NET MVC 3 action filters. What's wrong with this approach?

查看:33
本文介绍了将依赖项注入 ASP.NET MVC 3 操作过滤器.这种方法有什么问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是设置.假设我有一些需要服务实例的操作过滤器:

Here's the setup. Say I have some action filter that needs an instance of a service:

public interface IMyService
{
   void DoSomething();
}

public class MyService : IMyService
{
   public void DoSomething(){}
}

然后我有一个需要该服务实例的 ActionFilter:

I then have an ActionFilter that needs an instance of that service:

public class MyActionFilter : ActionFilterAttribute
{
   private IMyService _myService; // <--- How do we get this injected

   public override void OnActionExecuting(ActionExecutingContext filterContext)
   {
       _myService.DoSomething();
       base.OnActionExecuting(filterContext);
   }
}

在 MVC 1/2 中,将依赖项注入动作过滤器有点麻烦.最常见的方法是使用自定义操作调用程序,如下所示:http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/ 主要动机这种变通方法的背后是因为以下方法被认为是草率且与容器紧密耦合的:

In MVC 1/2 injecting dependencies into action filters was a bit of a pain in the ass. The most common approach was to use a custom action invoker as can be seen here: http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/ The main motivation behind this workaround was because this following approach was considered sloppy and tight coupling with the container:

public class MyActionFilter : ActionFilterAttribute
{
   private IMyService _myService;

   public MyActionFilter()
      :this(MyStaticKernel.Get<IMyService>()) //using Ninject, but would apply to any container
   {

   }

   public MyActionFilter(IMyService myService)
   {
      _myService = myService;
   }

   public override void OnActionExecuting(ActionExecutingContext filterContext)
   {
       _myService.DoSomething();
       base.OnActionExecuting(filterContext);
   }
}

这里我们使用构造函数注入并重载构造函数以使用容器并注入服务.我确实同意将容器与 ActionFilter 紧密耦合.

Here we're using constructor injection and overloading the constructor to use the container and inject the service. I do agree that does tightly couple the container with the ActionFilter.

我的问题是:现在在 ASP.NET MVC 3 中,我们对正在使用的容器进行了抽象(通过 DependencyResolver),所有这些箍仍然是必需的吗?请允许我演示:

My question though is this: Now in ASP.NET MVC 3, where we have an abstraction of the container being used (through the DependencyResolver) are all these hoops still necessary? Allow me to demonstrate:

public class MyActionFilter : ActionFilterAttribute
{
   private IMyService _myService;

   public MyActionFilter()
      :this(DependencyResolver.Current.GetService(typeof(IMyService)) as IMyService)
   {

   }

   public MyActionFilter(IMyService myService)
   {
      _myService = myService;
   }

   public override void OnActionExecuting(ActionExecutingContext filterContext)
   {
       _myService.DoSomething();
       base.OnActionExecuting(filterContext);
   }
}

现在我知道有些纯粹主义者可能会对此嗤之以鼻,但说真的,这有什么坏处?它仍然是可测试的,因为您可以使用在测试时接受 IMyService 的构造函数并以这种方式注入模拟服务.由于您使用了 DependencyResolver,因此您不会被任何 DI 容器的实现所束缚,那么这种方法有什么缺点吗?

Now I know that some purists might scoff at this, but seriously, what would be the downside? It's still testable as you can use the constructor that takes an IMyService at test time and inject a mock service that way. You're not tied down to any implementation of DI container since you're using the DependencyResolver, so are there any downsides to this approach?

顺便说一句,这是使用新的 IFilterProvider 接口在 MVC3 中执行此操作的另一种不错的方法:http://www.thecodinghumanist.com/blog/archives/2011/1/27/structuremap-action-filters-and-dependency-injection-in-asp-net-mvc-3

Incidentally, here's another nice approach for doing this in MVC3 using the new IFilterProvider interface: http://www.thecodinghumanist.com/blog/archives/2011/1/27/structuremap-action-filters-and-dependency-injection-in-asp-net-mvc-3

推荐答案

我不肯定,但我相信你可以只使用一个空的构造函数(对于属性部分)和然后有一个实际注入值的构造函数(对于 filter 部分).*

I'm not positive, but I believe you can just use an empty constructor (for the attribute part) and then have a constructor that actually injects the value (for the filter part).*

编辑:稍微阅读后,似乎可以接受的方法是通过属性注入:

Edit: After a little reading up, it appears that the accepted way to do this is via property injection:

public class MyActionFilter : ActionFilterAttribute
{
    [Injected]
    public IMyService MyService {get;set;}
    
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        MyService.DoSomething();
        base.OnActionExecuting(filterContext);
    }
}

关于为什么不使用服务定位器的问题:它主要只是降低了依赖注入的灵活性.例如,如果您正在注入一个日志服务,并且您想自动为日志服务提供它被注入的类的名称,该怎么办?如果您使用构造函数注入,那会很好用.如果您使用的是依赖关系解析器/服务定位器,那您就不走运了.

Regarding the why not use a Service Locator question: It mostly just reduces the flexibility of your dependency injection. For example, what if you were injecting a logging service, and you wanted to automatically give the logging service the name of the class it's being injected into? If you use constructor injection, that would work great. If you're using a Dependency Resolver/Service Locator, you'd be out of luck.

既然这被接受作为答案,我想公开表示我更喜欢 Mark Seeman 的方法 因为它将动作过滤器的职责与属性分开.此外,Ninject 的 MVC3 扩展有一些非常强大的方法来通过绑定配置动作过滤器.有关详细信息,请参阅以下参考资料:

Since this got accepted as the answer, I'd like to go on the record to say that I prefer Mark Seeman's approach because it separates the Action Filter responsibility away from the Attribute. Furthermore, Ninject's MVC3 extension has some very powerful ways to configure action filters via bindings. See the following references for more details:

正如@usr 在下面的评论中指出的那样,ActionFilterAttributes 在类加载时实例化,并且它们持续整个应用程序生命周期.如果 IMyService 接口不应该是一个单例,那么它最终是一个 俘虏依赖.如果它的实现不是线程安全的,你可能会很痛苦.

As @usr pointed out in the comments below, ActionFilterAttributes are instantiated when the class is loaded, and they last the entire lifetime of the application. If the IMyService interface is not supposed to be a Singleton, then it ends up being a Captive Dependency. If its implementation isn't thread-safe, you could be in for a lot of pain.

每当您的依赖项的生命周期比类的预期生命周期短时,明智的做法是注入工厂以按需生成该依赖项,而不是直接注入.

Whenever you have a dependency with a shorter lifespan than your class's expected lifespan, it's wise to inject a factory to produce that dependency on-demand, rather than injecting it directly.

这篇关于将依赖项注入 ASP.NET MVC 3 操作过滤器.这种方法有什么问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆