在多层应用程序中定位 Ninject 模块的位置 [英] Where to locate Ninject modules in a multi-tier application

查看:25
本文介绍了在多层应用程序中定位 Ninject 模块的位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序包括许多后端程序集(包括实体框架数据存储库层),这些程序集由许多前端程序集(包括 Windows 服务和 MVC3 Web 应用程序)共享.

My application includes a number of back-end assemblies (including an Entity Framework data repository layer) that are shared by a number of front-end assemblies (including a Windows service and an MVC3 web application).

我对 Ninject 绑定过程的理解是,每个包含可注入类型的程序集还应该包含一个 Ninject 模块,该模块定义这些类型的默认绑定.然后将定义的模块集加载到消费程序集的 Ninject 内核中.

My understanding of the Ninject binding process is that each assembly that contains injectable types should also contain an Ninject module that defines the default bindings for these types. The set of defined modules would then be loaded into the Ninject Kernel of the consuming assemblies.

但是,我遇到了问题,因为所需的绑定范围并不总是一致的.例如,我的MVC项目需要绑定到数据上下文InRequestScope,而Windows服务绑定到同一个类InThreadScope.

However, I am running into problems, since the required binding scope is not always consistent. For example, my MVC project needs to bind to the data context InRequestScope, whereas the Windows service binds to the same class InThreadScope.

我显然可以通过将所有模块重新定位到前端项目中来解决这个问题,从而为每个使用场景维护每个模块的单独副本,但这似乎很棘手,因为它在多个项目中复制了大部分模块内容.

I can obviously solve this problem by relocating all the modules into the front-end projects and thus maintain separate copies of each module for each usage scenario, but this seems hacky, since it duplicates much of the module content across multiple projects.

是否有关于模块应位于多层应用程序中的位置的最佳实践,以及我如何将其与绑定项目之间差异的需求相协调?

Is there a best practice about where modules should be located in a multi-tier application and how can I reconcile this with my need for binding differences between projects?

非常感谢您的建议,

蒂姆

推荐答案

对于具有单个应用程序的解决方案,一般建议是在应用程序项目(您的 Web 应用程序或 Web 服务项目)中注册您的容器.对于 Web 应用程序,这通常是 Global.asax Application_Start.这个将所有内容连接在一起的地方在 DI 术语中称为组合根.

For a solution with a single application, the general advice is to register your container in the application project (your web app, or web service project). For a web application this would typically be the Global.asax Application_Start. This place where you wire everything together is called the Composition Root in DI terminology.

使用多应用程序解决方案时,每个应用程序项目仍然只有一个组合根.这必须是,因为每个应用程序都有其独特的配置.另一方面,重复的代码总是不好的.当你引入一个新的抽象时,你不想改变三个地方.

With a multi-application solution, you would still have a single composition root per application project. This has to be, since every application has its unique configuration. On the other hand, duplicated code is always bad. You don't want to have to change three places when you introduce a new abstraction.

诀窍是将所有注册在项目层次结构中向下移动.例如,您可以定义一个依赖于您的业务层程序集(及以下)的引导程序集",并让它拥有那些未更改的程序集的所有注册.然后,应用程序的组合根可以使用该程序集来获取默认注册并使用特定于应用程序的依赖项对其进行扩展.

The trick is to move all registrations down the project hierarchy. For instance you can define a single 'bootstrap assembly' that depends on your business layer assemblies (and below) and let it have all the registrations for those assemblies that don't change. The composition roots of the applications can then use that assembly to get the default registrations and extend it with the application specific dependencies.

这样的事情可能看起来像这样:

Such a thing might look like this:

// MVC Composition root
public static void Bootstrap()
{
    var container = new Container();

    // Default registrations
    BusinessLayerBootstrapper.Bootstrap(container);

    // Application specific registrations
    container.Bind<IUserContext>().To<AspNetUserContext>();

    DependencyResolver.Current = 
        new ContainerDependencyResolver(container);
}

// Windows Service Composition root
public static void Bootstrap()
{
    var container = new Container();

    // Default registrations
    BusinessLayerBootstrapper.Bootstrap(container);

    // Application specific registrations
    container.Bind<IUserContext>().To<SystemUserContext>()
        .SingleScoped();

    // Store somewhere.
    Bootstrapper.Container = container;
}

// In the BL bootstrap assembly
public static class BusinessLayerBootstrapper
{
    public static void Bootstrap(Container container)
    {
        container.Bind<IDepenency>().To<RealThing>();
        // etc
    }
}

虽然您不需要有单独的引导程序程序集(您可以将此代码放在 BL 本身中),但这使您可以使业务层程序集不受容器的任何依赖.

Although you don't need to have a separate bootstrapper assembly (you can place this code in the BL itself), this allows you to keep your business layer assemblies free from any dependencies to your container.

另请注意,我只是在调用静态 Bootstrap() 方法,而不是使用 (Ninject) 模块.我试图让我的答案独立于框架,因为您的问题很笼统,而且所有 DI 框架的建议都是相同的.但是,如果需要,您当然可以使用 Ninject 模块功能.

Also note that I'm just calling a static Bootstrap() method, instead of using (Ninject) Modules. I tried to keep my answer independent of the framework, since your question is general and the advice will be the same for all DI frameworks. However, of course you can use the Ninject module feature if you want.

这篇关于在多层应用程序中定位 Ninject 模块的位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆