我在 MVC 应用程序中专门使用了 Ninject。您使用 Ninject 完成此操作的方式是配置或绑定您的依赖项。当你这样做时,你指定你希望如何管理你的对象生命周期。在网络应用程序的大多数情况下,您的对象将按照您在问题中指出的每个请求。
我在您的问题中注意到的一件事是您的DomainContext是由IDomainService对象创建的,并被其他对象使用。如果域服务对象是DomainContext的一种工厂,那么您不会有太大问题——这将成为您如何配置 Ninject 以提供具体对象和注入依赖项的练习。
以下是有关如何构建应用程序的一般指导——请记住,我对您的接口和类没有完全了解:
public class GlobalApplication : NinjectHttpApplication {
protected override void RegisterRoutes(RouteCollection routes) {
// Your normal route registration goes here ...
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = "" }
);
}
// This function is resposible for creating a Ninject kernel. This is where
// the magic starts to happen.
protected override IKernel CreateKernel() {
var modules = new IModule[] {
new AutoWiringModule(),
new AutoControllerModule(
Assembly.GetExecutingAssembly()),
new ServiceModule()
};
return new StandardKernel(modules);
}
}
请注意,让 Ninject 工作的最简单方法是从NinjectHttpApplication类派生您的应用程序类。您需要将RegisterRoutes更改为覆盖方法,并且还需要实现一个名为CreateKernel的方法。CreateKernel方法负责返回 Ninject 内核,它本身就是 IoC 容器。
在CreateKernel方法中,Ninject 提供的AutoControllerModule扫描程序集以查找 MVC 控制器类并将它们注册到容器中。这意味着现在可以通过 Ninject 注入对这些控制器的依赖项,因为它已成为应用程序的控制器提供程序。ServiceModule类是您需要创建的类,以便向 Ninject 注册所有服务。我猜它看起来像这样:
internal class ServiceModule : StandardModule {
public override void Load() {
Bind<IDomainService>()
.To<MyDomainService>()
.Using<OnePerRequestBehavior>();
Bind<DomainContext>()
.ToMethod( ctx => ctx.Kernel.Get<IDomainService>().CurrentDomainContext )
.Using<OnePerRequestBehavior>();
Bind<IService>()
.To<MyServiceType>()
.Using<OnePerRequestBehavior>();
}
}
Ninject 有一个非常富有表现力的流畅的配置界面。上面请注意,每个语句基本上都将具体类与其实现的接口相关联。语句中的“使用”短语向 Ninject 内核表明该对象将仅在请求的生命周期内存活。因此,例如,这意味着任何时候在同一请求期间从 Ninject 内核请求IDomainService对象时,都会返回相同的对象。
至于您的上下文对象,我正在尝试您的域服务创建这些上下文并充当某种工厂。在这方面,我通过从IDomainService中获取名为CurrentDomainContext的属性的值来绑定上面的DomainContext类实例。这就是上面的 lambda 所完成的。Ninject 中“ToMethod”绑定的好处是您可以访问 Ninject 激活上下文对象,该对象允许您使用内核解析对象。这正是我们为了获取当前域上下文所做的事情。
接下来的步骤是确保您的对象正确接受依赖项。例如,您说ITrainingService仅在TrainingController类中使用。因此,在这种情况下,我将确保TrainingController具有接受ITrainingService参数的构造函数。在该构造函数中,您可以将对ITrainingService的引用保存在成员变量中。如:
public class TrainingController : Controller {
private readonly ITrainingService trainingService;
public TrainingController(ITrainingService trainingService) {
this.trainingService = trainingService;
}
// ... rest of controller implementation ...
}
请记住,Ninject 已经向 Ninject 内核注册了所有控制器,因此当创建此控制器并调用它的操作时,您将通过 trainingService 成员变量获得对ITrainingService的引用。
希望这可以帮助你。使用 IoC 容器有时会变得相当混乱。请注意,我强烈建议您查看Ninject 文档——这是对 Ninject 以及 DI/IoC 概念的很好的介绍。我也省略了上面显示的 AutoWiringModule 的讨论;但是,Nate Kohari(Ninject 的创建者)在他的博客上写了一篇关于此功能的精彩文章。
祝你好运!