【问题标题】:DI Container code organisationDI 容器代码组织
【发布时间】:2014-02-13 11:23:41
【问题描述】:

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

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

一个小sn-p:

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>>()
    )
);

有没有更好的组织方式?

我似乎在网上找不到任何示例/文章/方向。

【问题讨论】:

  • 我不是 Unity 人.. 但肯定有办法将这些模块化吗?有时我会被 Ninject 宠坏了。你可以创建 NinjectModules 来注册类型。还有 Ninject Conventions Extension.. 它消除了像这样单独绑定样板代码的需要。也许 Unity 有类似的东西?
  • 可能有(我也不是 Unity 人)但我似乎找不到任何东西。

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


【解决方案1】:

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

通常您不会在引导程序中设置映射。您只需决定要在引导程序中加载什么并允许模块设置它需要的映射。

如果您的问题是如何避免在代码中的任何地方进行映射(即没有 container.RegisterInstance<...>),据我所知这是不可能的。有关如何映射接口的信息必须来自 SOMEWHERE。

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

编辑:

为每个逻辑部分创建一个模块。我将为 FirstContext 和 AnotherContext 做一个。我通常为每个 DLL 放置一个模块,但没有什么能阻止您为每个 DLL 创建超过 1 个模块。由您决定如何组织它。

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
    }
}

另一个上下文模块:

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() 以仅添加您要使用的模块。

【讨论】:

  • 你会在哪里定义这些模块?任何代码都会很棒。谢谢
猜你喜欢
  • 2018-10-12
  • 2011-08-08
  • 2011-06-04
  • 2014-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多