Ось установка. Скажімо, у мене є якийсь фільтр дій, який потребує екземпляра служби:
public interface IMyService
{
void DoSomething();
}
public class MyService : IMyService
{
public void DoSomething(){}
}
Потім у мене є ActionFilter, який потребує екземпляра цієї служби:
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 впорскування залежностей у фільтри дій було болем у дупі. Найбільш поширений підхід полягає у використанні Invoker призначених для користувача дій , як можна побачити тут: http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/ Основною мотивацією цього обхідного шляху було те, що такий наступний підхід вважався недбалим і щільним зчепленням з контейнером:
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.
Моє запитання полягає в наступному: тепер у ASP.NET MVC 3, де ми маємо абстракцію використовуваного контейнера (через DependencyResolver), чи всі ці обручі все ще необхідні? Дозвольте мені продемонструвати:
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 під час тестування, і таким чином вводити макетну службу. Ви не прив'язані до жодної реалізації контейнера DI, оскільки використовуєте DependencyResolver, тож чи є у цього підходу мінуси?
До речі, ось ще один приємний підхід для цього в MVC3 за допомогою нового інтерфейсу IFilterProvider: http://www.thecodinghumanist.com/blog/archives/2011/1/27/structuremap-action-filters-and-dependency-injection-in -asp-net-mvc-3