构建中型asp mvc - 使用ninject和创建对象

tom*_*omo 7 architecture asp.net-mvc ninject inversion-of-control

我正在使用asp.net mvc技术设计中型网站.所有业务逻辑都组织成IServices(如IDomainService,IUserService,IAuthService,ITrainingService).所有服务都使用IRepositories.我正在使用Ninject 1.5与控制器连接服务,它似乎工作得很好.

到目前为止,有一个主题我不知道如何处理.一些服务创建上下文(每个请求) - 例如,IDomainService创建IConserService所需的DomainContext(每个请求).ITrainingService仅在TrainingController中使用,只能由授权用户访问,ITrainingService需要UserContext(也可根据请求)知道谁正在接受培训.

这是我的第一个使用IoC容器的项目.是否有任何设计模式或代码架构如何解决?我想我可以使用ActionFilters来填充上下文对象,但是如何管理它们的生命周期以及将它们放在哪里可供IServices访问?(以一种优雅的方式)

Pet*_*yer 10

我在MVC应用程序中专门使用了Ninject.使用Ninject完成此任务的方法是配置或绑定依赖项.执行此操作时,您可以指定希望如何管理对象生存期.在大多数Web应用程序的情况下,您的对象将按照您在问题中指出的每个请求进行.

我在你的问题中注意到的一件事是你的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);
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,让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>();
  }
}
Run Code Online (Sandbox Code Playgroud)

Ninject有一个非常富有表现力的流畅的配置界面.请注意,每个语句基本上将具体类与其实现的接口相关联.语句中的"Using"短语向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 ...
}
Run Code Online (Sandbox Code Playgroud)

请记住,Ninject已经使用Ninject内核注册了所有控制器,因此在创建此控制器并调用其操作时,您将通过trainingService成员变量引用ITrainingService.

希望这可以帮助你.使用IoC容器有时会变得非常混乱.注意,我强烈建议您查看Ninject文档 - 它是对Ninject以及DI/IoC概念的精心编写的介绍.我也没有讨论过上面显示的AutoWiringModule; 然而,内特Kohari(Ninject的创建者)具有良好的写了在他的博客有关此功能.

祝好运!