Вот установка. Скажем, у меня есть какой-то фильтр действий, которому нужен экземпляр службы:
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 внедрение зависимостей в фильтры действий было немного затруднительным. жопа. Наиболее распространенным подходом было использование средства вызова настраиваемого действия, как показано здесь: http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action- filter / Основная мотивация этого обходного пути заключалась в том, что следующий подход считался небрежным и жестким соединением с контейнером:
public class MyActionFilter : ActionFilterAttribute
{
private IMyService _myService;
public MyActionFilter()
:this(MyStaticKernel.Get()) //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