Hier ist das Setup. Angenommen, ich habe einen Aktionsfilter, der eine Instanz eines Dienstes benötigt:
public interface IMyService
{
void DoSomething();
}
public class MyService : IMyService
{
public void DoSomething(){}
}
Ich habe dann einen ActionFilter, der eine Instanz dieses Dienstes benötigt:
public class MyActionFilter : ActionFilterAttribute
{
private IMyService _myService; // <--- How do we get this injected
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_myService.DoSomething();
base.OnActionExecuting(filterContext);
}
}
In MVC 1/2 war das Injizieren von Abhängigkeiten in Aktionsfilter ein bisschen nervig. Der gebräuchlichste Ansatz war die Verwendung eines benutzerdefinierten Aktionsaufrufers, wie hier zu sehen ist: http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/ The Hauptmotivation für diese Problemumgehung war, dass dieser folgende Ansatz als schlampige und enge Kopplung mit dem Container angesehen wurde:
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);
}
}
Hier verwenden wir die Konstruktorinjektion und überladen den Konstruktor, um den Container zu verwenden und den Service zu injizieren. Ich bin damit einverstanden, dass der Container eng mit dem ActionFilter gekoppelt ist.
Meine Frage lautet jedoch: Sind in ASP.NET MVC 3, wo wir eine Abstraktion des verwendeten Containers haben (über den DependencyResolver), all diese Rahmen noch erforderlich? Gestatten Sie mir zu demonstrieren:
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);
}
}
Jetzt weiß ich, dass einige Puristen sich darüber lustig machen könnten, aber im Ernst, was wäre der Nachteil? Es ist weiterhin testbar, da Sie den Konstruktor verwenden können, der zur Testzeit einen IMyService verwendet und auf diese Weise einen Mock-Service einfügt. Sie sind nicht an eine Implementierung eines DI-Containers gebunden, da Sie den DependencyResolver verwenden. Gibt es also Nachteile bei diesem Ansatz?
Im Übrigen ist hier ein weiterer guter Ansatz, um dies in MVC3 mithilfe der neuen IFilterProvider-Schnittstelle zu tun: http://www.thecodinghumanist.com/blog/archives/2011/1/27/structuremap-action-filters-and-dependency-injection-in -asp-net-mvc-3