Ответ 1
Кажется, у вас много вопросов, на что нужно ответить здесь, поэтому я постараюсь сделать все возможное.
В соответствии с вашим текущим вопросом я попытаюсь "составить" упрощенную архитектуру вашей текущей реализации:
- Уровень домена: Ядро вашего домена, место вашего бизнеса и т.д.
- Уровень инфраструктуры:. Здесь находятся ваши службы, например:
WindowsHardwareService
- IOC. Я склонен называть это как сборку
DependencyResolution
.
- IOC. Я склонен называть это как сборку
- UI: приложение MVC
Предположим, что все это выше, мы можем заявить, что ваши приложения Composition Root
или Entry point
- это пользовательский интерфейс Проект MVC. Одно из основных понятий, использующее DI Container
, которое вы инициализируете его в Composition Root
, устанавливает/выполняет все необходимые привязки и регистрации здесь. Основное намерение сделать это в точке входа - избежать Service Locator
anti-pattern.
Используя DI Container
, вы не new()
реализуете свои реализации класса или получаете ядро, а скорее запрашиваете зарегистрированную зависимость, следуя правилу Inversion Of Control
или также известен как принцип Голливуда.
После курса философии мы можем, наконец, перейти к некоторой фактической реализации.
Создание Ninject module: в вашей сборке IOC, позвоните по этому вызову файл как ServiceModule.cs
using Ninject.Modules;
public class ServiceModule : NinjectModule
{
public override void Load()
{
Bind<IHardwareService>().To<WindowsHardwareService>();
Bind<IStatusApi>().To<StatusApiController>();
}
}
Это будет Ninject module
, который вы зарегистрируете/загрузите в Composition Root
.
Теперь о корне композиции: в UI проектах MVC NinjectWebCommon.cs
У вас может быть метод, который отвечает за загрузку ваших модулей, как показано ниже.
private static void RegisterServices(IKernel kernel)
{
var modules = new List<INinjectModule>
{
new ServiceModule()
//, new FooModule()
//, new BarModule()
};
kernel.Load(modules);
}
И, наконец, ваш DashboardController
в UI MVC:
public class DashboardController : Controller
{
private readonly IHardwareService _hardwareService;
public DashboardController(IHardwareService hardwareService)
{
_hardwareService = hardwareService;
}
}
В этот момент попросите зарегистрированную реализацию IHardwareService
в конструкторе контроллеров. DI Container
выполнит грязное задание и передаст вам экземпляр, с которым вы сможете работать позже в своем контроллере.
Заметка о интерфейсах. Я склоняю их к собственной сборке, где я просто храню интерфейсы, например: Project.Domain.Interfaces
или Project.Infrastructure.Interfaces
, где каждая из этих сборок содержит только домен или интерфейсы инфраструктуры.
Ссылки между сборками:
Чтобы сопоставить все это, UI ссылается только на сборку IOC и сборку интерфейсов, которая содержит интерфейсы, которые вы связали в своем Ninject module
.
Суммируя все вышесказанное:
Ваши классы и интерфейсы сами по себе являются просто частями, которые склеиваются с помощью контейнера DI.
Надеюсь, я немного это выяснил.
EDIT:, как хороший совет, который @AndreySarafanov указал в комментариях, если вам нужны разные реализации интерфейса, который вы запрашиваете в конструкторе, вы можете использовать Ninject Factory. Для получения дополнительной информации вы можете обратиться к этому.