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

查看:345
本文介绍了注入依赖于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?

顺便提一句,这是另一个不错的方法在MVC3中使用新的IFilterProvider接口进行此操作: 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

推荐答案

我不积极,但我相信你可以使用一个空构造函数(对于属性部分),然后具有实际注入值(对于过滤器部分)的构造函数。*

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的方法,因为它将Action Filter的职责与属性分离开来。此外,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:

  • https://github.com/ninject/ninject.web.mvc/wiki/Dependency-injection-for-filters
  • https://github.com/ninject/ninject.web.mvc/wiki/Conditional-bindings-for-filters
  • https://github.com/ninject/ninject.web.mvc/wiki/Filter-configurations

由于@usr在下面的评论中指出, ActionFilterAttribute 在类加载时被实例化,并且它们持续整个应用程序的整个生命周期。如果 IMyService 接口不应该是一个Singleton,那么它最终会成为一个俘虏依赖关系。如果它的实现不是线程安全的,你可能会遇到很多痛苦。

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天全站免登陆