4

我有一个 asp.net mvc 3 Web 应用程序,它具有实现系统相关 EFcontexts 和服务的插件程序集。

例如,我有一个通常如下所示的程序集:

System1Controller : IController // from System.Web.Mvc

ISystem1Service {
    IList<System1Type> GetOperation(string something);
}

System1Service : ISystem1Service 
{
    private ISystem1Entities context;
    public System1Service(ISystem1Entities context)
    {
        this.context = context;
    }
}

ISystem1Entities
{
    IDbSet<System1Type> Operations { get; set; }
}

System1Entities : DbContext, ISystem1Entities

使用 Unity Bootstrapper 并调用 Bootstrapper.Initialize() 可用于以下 BuildUnityContainer() 实现

private static IUnityContainer BuildUnityContainer()
{
    var theContainer = new UnityContainer();
    var connectionString = ConfigurationManager.ConnectionStrings["WebAppConnectionString"];
    if (connectionString == null)
    {
        throw new ApplicationException("The ConnectionString is not defined.");
    }

    // register all your components with the container here
    // it is NOT necessary to register your controllers
    theContainer.RegisterType<ISystem1Entities, System1Entities>(
        new HierarchicalLifetimeManager(), 
        new InjectionConstructor(connectionString.ConnectionString));

    theContainer.RegisterType<ISystem1Service, System1Service>();

    var factory = new UnityControllerFactory(theContainer);
    ControllerBuilder.Current.SetControllerFactory(factory);

    return theContainer;
}

我想重构引导程序,以便我可以在编译时加载“未知”程序集,注册其中包含的类型,并允许 Web 应用程序根据需要引用控制器、服务、上下文。

我查看了Unity AutoRegistraion项目,它似乎让我接近了我想要的实现,但我不确定如何实现以下想法:

BootStrapper.BuildUnityConfiguration
    Initialize Container
    RegisterMyAssemblies()

我希望“RegisterMyAssemblies”进程注册程序集的通配符列表,然后继续在每个单独的程序集中注册类型。有什么建议么?

4

2 回答 2

5

您不应该尝试使用应用程序的主引导程序(组合根)来配置这些插件程序集,因为这很难做到正确。很难做到正确,因为主程序不知道要注册哪些类型,以及这些类型应该在多长的生命周期内注册。

相反,让每个插件程序集都有它自己的引导程序方法,并将应用程序的容器实例传递给这个插件引导程序。

例如,您可以IBootstrapper在核心程序集中定义一个接口,并让每个插件程序集实现该接口。例如:

public class System1Bootstrapper : IBootstrapper
{
    void IBootstrapper.Bootstrap(IUnityContainer container)
    {
        var conString = ConfigurationManager
            .ConnectionStrings["WebAppConnectionString"];

        if (conString == null)
        {
            throw new ApplicationException(
                    "The ConnectionString is not defined.");
        }

        // register all your components with the container here
        // it is NOT necessary to register your controllers
        container.RegisterType<ISystem1Entities, System1Entities>(
            new HierarchicalLifetimeManager(), 
            new InjectionConstructor(conString.ConnectionString));

        container.RegisterType<ISystem1Service, System1Service>();
    }
}

在应用程序的组合根目录中,您现在可以简单地添加以下代码来注册所有插件类型:

var pluginBootstrappers =
    from Assembly assembly in BuildManager.GetReferencedAssemblies()
    from type in assembly.GetExportedTypes()
    where typeof(IBootstrapper).IsAssignableFrom(type)
    select (IBootstrapper)Activator.CreateInstance(type);

pluginBootstrappers.ToList().ForEach(b => b.Bootstrap(container));
于 2012-10-08T14:56:06.137 回答
0

这无疑是一个插件,但请查看我在 NuGet 上的 Unity Automapper。它允许你做这种事情——你只需为它提供一个类型或程序集名称的集合;它将根据接口 - 具体映射自动连接依赖项。它还对内部类型进行操作,因此您可以通过公开您的接口和这些接口的提供者来进行“适当的” DIP。

于 2012-10-09T09:53:20.437 回答