asp.net-mvc - 构建中等大小的 asp mvc - 使用 ninject 和创建对象

标签 asp.net-mvc architecture inversion-of-control ninject

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

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

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

最佳答案

我在 MVC 应用程序中专门使用了 Ninject。您使用 Ninject 完成此操作的方式是配置或绑定(bind)您的依赖项。当你这样做时,你指定你希望如何管理你的对象生命周期。在网络应用程序的大多数情况下,您的对象将按照您在问题中指出的每个请求。

我在您的问题中注意到的一件事是您的 DomainContext 是由 IDomainService 对象创建的,并被其他对象使用。如果域服务对象是 DomainContext 的一种工厂,那么您不会有太大问题——这将成为您如何配置 Ninject 以提供具体对象和注入(inject)依赖项的练习。

以下是有关如何构建应用程序的一般指导——请记住,我对您的接口(interface)和类没有完全了解:

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 Controller 类并将它们注册到容器中。这意味着现在可以通过 Ninject 注入(inject)对这些 Controller 的依赖项,因为它已成为应用程序的 Controller 提供程序。 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 有一个非常富有表现力的流畅的配置界面。上面请注意,每个语句基本上都将具体类与其实现的接口(interface)相关联。语句中的“使用”短语向 Ninject 内核表明该对象将仅在请求的生命周期内存活。因此,例如,这意味着任何时候在同一请求期间从 Ninject 内核请求 IDomainService 对象时,都会返回相同的对象。

至于您的上下文对象,我正在尝试您的域服务创建这些上下文并充当某种工厂。在这方面,我通过从 IDomainService 中获取名为 CurrentDomainContext 的属性的值来绑定(bind)上面的 DomainContext 类实例。这就是上面的 lambda 所完成的。 Ninject 中“ToMethod”绑定(bind)的好处是您可以访问 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 内核注册了所有 Controller ,因此当创建此 Controller 并调用它的操作时,您将通过 trainingService 成员变量获得对 ITrainingService 的引用。

希望这可以帮助你。使用 IoC 容器有时会变得相当困惑。请注意,我强烈建议您查看 Ninject documentation -- 这是一篇写得很好的关于 Ninject 以及 DI/IoC 概念的介绍。我也省略了上面显示的 AutoWiringModule 的讨论;但是,Nate Kohari(Ninject 的创建者)拥有 a good write-up在他的博客上关于这个功能。

祝你好运!

关于asp.net-mvc - 构建中等大小的 asp mvc - 使用 ninject 和创建对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1158284/

相关文章:

architecture - 在 ntier 应用程序中传递数据

scala-将自类型注释类传递给子对象

c# - 使用 MEF 时是否有任何 Prism "Post-build"事件或方法?

c# - 使用 CQRS 方法处理并发

caching - 如何计算三级缓存的有效 CPI

c# - 为什么我的 WindsorContainer 不能解析 IWindsorContainer?

asp.net-mvc - 适用于 Web 的 Azure 应用程序见解,在 Power BI 中显示唯一用户

javascript - 为什么我的 List<string> 没有从 $ajax 调用的 MVC Controller 返回

asp.net - Response.Flush 破坏页面缓存

asp.net-mvc - Azure 移动服务与 Web API