#asp.net-mvc #ninject
#asp.net-mvc #ninject
Вопрос:
У меня есть ASP.NET Приложение MVC 3, которое использует расширение Ninject.MVC3 для настройки DI в моем приложении MVC. А именно NinjectMVC3.cs
, в App_Start
папке, где определены мои привязки, есть файл. Это хорошо работает для DI в контроллерах моего приложения.
В дополнение к ASP.NET Веб-приложение MVC, мое решение, также содержит библиотеку классов projects, назовем ее MyProject.Core
projects , в которой есть моя модель домена, сервисы и так далее. Там у меня есть вызываемый класс UserServices
, который использует вызываемую службу EmailServices
, например:
public class UserServices : IUserServices
{
private readonly IEmailServices _emailServices = new EmailServices();
public void CreateUser(...)
{
// Create user...
_emailServices.SendWelcomeEmail(newUser);
}
}
Как вы можете видеть, UserServices
класс имеет жестко запрограммированную зависимость от EmailServices
, но я бы хотел, чтобы он также был настроен на использование DI. А именно, в моем ASP.NET Приложение MVC (или проект модульного тестирования, или где угодно еще) Я хочу иметь возможность сказать «Привязать IEmailServices
к использованию TestEmailServices
» и UserServices
использовать класс TestEmailServices
вместо EmailServices
.
Как мне это сделать? Я хотел бы иметь возможность делать что-то вроде:
public class UserServices : IUserServices
{
private readonly IEmailServices _emailServices = kernel.Get<EmailServices>();
...
}
Но я не уверен kernel
, откуда это произойдет в данном случае. Имеет ли смысл то, что я спрашиваю, или я лаю здесь не то дерево?
Спасибо
Ответ №1:
Вы должны быть в состоянии сделать это с помощью внедрения конструктора, например:
private readonly IEmailServices _emailServices;
public UserServices(IEmailServices emailServices)
{
_emailServices = emailServices;
}
Внедрение службы в ваши контроллеры должно обрабатываться автоматически фабрикой пользовательских контроллеров Ninject, которая будет использовать настроенный контейнер IoC для разрешения IUserServices
объекта при создании контроллера, которому, в свою очередь, будет предоставлен IEmailServices
объект контейнером:
public class MyController : Controller
{
private readonly IUserServices _userServices;
public MyController(IUserServices userServices)
{
_userServices = userServices;
}
}
При модульном тестировании вы можете вручную внедрить поддельную или фиктивную службу электронной почты в пользовательскую службу.
Комментарии:
1. Да, это ответ. Не используйте ядро Ninject в качестве локатора служб. Не связывайте свои реализации библиотеки с Ninject. Просто позвольте ему построить все дерево объектов в основном приложении.
2. Ах, я должен был просто попробовать это! <хлопает по лбу /> 🙂 Спасибо
Ответ №2:
Если вы все равно используете MVC 3, как насчет регистрации Ninject с помощью встроенного DependencyResolver?
System.Web.Mvc.DependencyResolver.SetResolver(yourKernel);
Затем вы можете просто использовать
var svc = System.Web.Mvc.DependencyResolver.Current.GetService<bla>();
там, где вам это нужно. Я не знаю, принимает ли SetResolver ядро Ninject напрямую или вам нужен класс-оболочка, но я бы счел это самым чистым решением.
Комментарии:
1. Это будет работать, но оно по-прежнему зависит от антишаблона Service Locator и совершенно не нужно в MVC, где вы можете просто зарегистрировать Ninject как фабрику контроллеров и использовать обычную инъекцию конструктора везде. Не говоря уже о том, что он связывает библиотеку классов с
System.Web.Mvc
, что кажется неправильным…2. @Aaronaught Да и нет. DependencyResolver в MVC 3 обрабатывает все (поэтому больше нет необходимости в фабрике контроллеров, он использует DI автоматически, если DependencyResolver может его разрешить). Однако могут быть ситуации, когда просто невозможно внедрить все зависимости (например, у меня есть HtmlHelper, который использует службу, которая обрабатывает некоторые вещи форматирования — это МОЖНО сделать в контроллере и поместить в модель, но это было бы излишним для службы исключительно для функций отображения)
3.
DependencyResolver
это буквально локатор служб с новым именем. Я действительно не вижу никаких преимуществ в его использовании над самим ядром … это просто еще один уровень косвенности? Я не уверен, что в этом есть законная необходимость, помимо того, что есть во внутренних компонентах MVC, но я полагаю, что там могут быть какие-то неясные примеры.4. @Aaronaught Это действительно просто еще один уровень. Если у вас есть ядро, отлично. Особенность DR в том, что он работает независимо от того, какой DI (поэтому, если вы хотите использовать Unity, AutoFac или что-то еще, что является прозрачным), и что он дает вам глобальный / статический. Но да, это буквально Service Locator. Для внутренних компонентов MVC он заменяет различные механизмы (например, ранее существовала фабрика контроллеров, механизм просмотра, modelbinder. Теперь сначала он будет запрашивать DR для всего)