DI容器代码组织

时间:2014-02-13 11:23:42

标签: c# dependency-injection domain-driven-design unity-container onion-architecture

我最近一直在使用依赖注入(Unity)来实现我的域层与任何基础架构问题之间的低耦合。

我最终在我的MVC引导程序中使用了很多的Unity容器代码。

一个小片段:

container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>("FirstContext", new PerResolveLifetimeManager(), new InjectionConstructor(new FirstContext()));
container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>("AnotherContext", new PerResolveLifetimeManager(), new InjectionConstructor(new AnotherContext()));

// User Aggregate
container.RegisterType<IEntityMapper<User, UserTable>, UserMapper>();
container.RegisterType<IUserRepository, UserRepository>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("FirstContext"),
        new ResolvedParameter<IEntityMapper<User, UserTable>>()
    )
);

// Token Aggregate
container.RegisterType<IEntityMapper<Token, TokenTable>, TokenMapper>();
container.RegisterType<ITokenRepository, TokenRepository>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("FirstContext"),
        new ResolvedParameter<IEntityMapper<Token, TokenTable>>()
    )
);

// Payment Aggregate
container.RegisterType<IReadOnlyEntityMapper<Payment, PaymentTable>, PaymentFactory>();
container.RegisterType<IPaymentRepository, PaymentRepository>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("FirstContext"),
        new ResolvedParameter<IReadOnlyEntityMapper<Payment, PaymentTable>>()
    )
);

// Customer Aggregate
container.RegisterType<IReadOnlyEntityMapper<Customer, CustomerTable>, CustomerMapper>();
container.RegisterType<ICustomerRepository, CustomerRepository>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("AnotherContext"),
        new ResolvedParameter<IReadOnlyEntityMapper<Customer, CustomerTable>>()
    )
);

// Country Aggregate
container.RegisterType<IReadOnlyEntityMapper<Country, CountryTable>, CountryMapper>();
container.RegisterType<ICountryRepository, CountryRepository>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("AnotherContext"),
        new ResolvedParameter<IReadOnlyEntityMapper<Country, CountryTable>>()
    )
);

// Province Aggregate
container.RegisterType<IReadOnlyEntityMapper<Province, ProvinceTable>, ProvinceMapper>();
container.RegisterType<IProvinceRepository, ProvinceRepository>(
    new InjectionConstructor(
        new ResolvedParameter<IUnitOfWork>("AnotherContext"),
        new ResolvedParameter<IReadOnlyEntityMapper<Province, ProvinceTable>>()
    )
);

有没有更好的方法来组织这个?

我似乎无法在网上找到任何示例/文章/指示。

1 个答案:

答案 0 :(得分:1)

通常,您要做的是为应用程序的每个逻辑组件创建“模块”,并在模块的Initialize方法中设置映射。在引导程序中,您可以设置要加载的模块。有多种方法可以做到这一点。您可以在代码,XML或使用DLL Discovery中明确地执行此操作。

通常,您不会在引导程序中设置映射。您只需确定要在引导程序中加载的内容,并允许模块设置所需的映射。

如果您的问题是如何阻止在代码中的任何地方完成映射(即没有container.RegisterInstance&lt; ...&gt;),据我所知,这是不可能的。有关如何映射接口的信息必须来自SOMEWHERE。

http://msdn.microsoft.com/en-us/library/gg405479(v=pandp.40).aspx

编辑:

为每个逻辑部分创建一个模块。我会为FirstContext和AnotherContext做一个。我通常为每个DLL放置一个模块,但没有什么能阻止你为每个DLL创建多个模块。这取决于你想要如何组织它。

FirstContextModule:

public class FirstContextModule : IModule
{
    private readonly IUnityContainer container;

    public FirstContextModule(IUnityContainer unityContainer)
    {
        this.container = unityContainer;
    }

    public void Initialize()
    {
        this.SetupContainer();
        this.SetupRegions();
    }

    private void SetupContainer()
    {
        container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>("FirstContext", new PerResolveLifetimeManager(), new InjectionConstructor(new FirstContext()));

        // User Aggregate
        container.RegisterType<IEntityMapper<User, UserTable>, UserMapper>();
        container.RegisterType<IUserRepository, UserRepository>(
            new InjectionConstructor(
                new ResolvedParameter<IUnitOfWork>("FirstContext"),
                new ResolvedParameter<IEntityMapper<User, UserTable>>()));

        // Token Aggregate
        container.RegisterType<IEntityMapper<Token, TokenTable>, TokenMapper>();
        container.RegisterType<ITokenRepository, TokenRepository>(
            new InjectionConstructor(
                new ResolvedParameter<IUnitOfWork>("FirstContext"),
                new ResolvedParameter<IEntityMapper<Token, TokenTable>>()));

        // Payment Aggregate
        container.RegisterType<IReadOnlyEntityMapper<Payment, PaymentTable>, PaymentFactory>();
        container.RegisterType<IPaymentRepository, PaymentRepository>(
            new InjectionConstructor(
                new ResolvedParameter<IUnitOfWork>("FirstContext"),
                new ResolvedParameter<IReadOnlyEntityMapper<Payment, PaymentTable>>()));
    }

    private void SetupRegions()
    {
        // Register the views
    }
}

<强> AnotherContextModule:

public class AnotherContextModule : IModule
{
    private readonly IUnityContainer container;

    public AnotherContextModule(IUnityContainer unityContainer)
    {
        this.container = unityContainer;
    }

    public void Initialize()
    {
        this.SetupContainer();
        this.SetupRegions();
    }

    private void SetupContainer()
    {
        container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>("AnotherContext", new PerResolveLifetimeManager(), new InjectionConstructor(new AnotherContext()));

        // Customer Aggregate
        container.RegisterType<IReadOnlyEntityMapper<Customer, CustomerTable>, CustomerMapper>();
        container.RegisterType<ICustomerRepository, CustomerRepository>(
            new InjectionConstructor(
                new ResolvedParameter<IUnitOfWork>("AnotherContext"),
                new ResolvedParameter<IReadOnlyEntityMapper<Customer, CustomerTable>>()));

        // Country Aggregate
        container.RegisterType<IReadOnlyEntityMapper<Country, CountryTable>, CountryMapper>();
        container.RegisterType<ICountryRepository, CountryRepository>(
            new InjectionConstructor(
                new ResolvedParameter<IUnitOfWork>("AnotherContext"),
                new ResolvedParameter<IReadOnlyEntityMapper<Country, CountryTable>>()));

        // Province Aggregate
        container.RegisterType<IReadOnlyEntityMapper<Province, ProvinceTable>, ProvinceMapper>();
        container.RegisterType<IProvinceRepository, ProvinceRepository>(
            new InjectionConstructor(
                new ResolvedParameter<IUnitOfWork>("AnotherContext"),
                new ResolvedParameter<IReadOnlyEntityMapper<Province, ProvinceTable>>()));
    }

    private void SetupRegions()
    {
        // Register the views
    }
}

引导程序:

public class Bootstrapper : UnityBootstrapper
{
    protected override void ConfigureModuleCatalog()
    {
        base.ConfigureModuleCatalog();

        ModuleCatalog moduleCatalog = (ModuleCatalog)this.ModuleCatalog;
        moduleCatalog.AddModule(typeof(FirstContextModule ));
        moduleCatalog.AddModule(typeof(AnotherContextModule ));
    }

    protected override DependencyObject CreateShell()
    {
        return this.Container.Resolve<Shell>();
    }

    protected override void InitializeShell()
    {
        base.InitializeShell();

        Application.Current.MainWindow = (Window)this.Shell;
        Application.Current.MainWindow.Show();
    }
}

现在它被分成了模块,假设你想要3个不同版本的应用程序:
1只使用FirstContext 1只使用AnotherContext 1同时使用FirstContext和AnotherContext

您需要做的就是将ConfigureModuleCatalog()更改为仅添加您要使用的模块。