4

我有一个asp.net mvc 3 Web应用程序,它具有实现系统相关EFcontexts和服务的插件程序集。如何使用Unity DI加载具有依赖关系的程序集,然后注册内部结构

例如,我有,看起来像一般以下组件:

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 

使用统一引导程序并调用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'进程注册通配符程序集列表,然后继续在每个程序集中注册类型。有什么建议么?

回答

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)); 
+1

感谢您的洞察力。我能够非常整齐地将你的解决方案融入到我的架构中。 –

+0

另一种选择是让每个插件管理自己的容器实例。这使得子系统彼此隔离,但这只有在子系统之间很少或没有交互时才可能。 – Steven

0

这是无可否认的一个插件,但看看我的团结Automapper上的NuGet。它允许你做这种事情 - 你只需要提供一个类型或程序集名称的集合;它会根据接口 - 具体映射自动连接依赖关系。它也可以在内部类型上运行,所以你可以通过让你的接口公开并且把这些接口的提供者放在内部来做“正确的”DIP。

相关问题