Castle Windsor仅在许多项目中执行某些类型的安装程序

时间:2017-06-12 23:53:40

标签: dependency-injection castle-windsor

我们有一个庞大的单片遗留应用程序,大约有45个项目,有几个不同的组合根(控制台,web,api应用程序)。大多数组件注册都是在应用程序的组合根和许多WindsorInstallers中完成的。我们希望从解决方案中的每个项目的组合根和WindsorInstallers中删除组件注册,这样我们在添加新项目时就不再需要修改组合根,每个项目都应该负责自己的组件注册。我们希望逐步改变我们的代码库,因为我尝试让Castle Windsor扫描我们所有的程序集并运行我们所有的安装程序,但这导致了无数的问题,需要随着时间的推移进行调查。

总而言之,我们正在寻找一种只运行某些安装程序的方法,因此我们可以随着时间的推移修复损坏的安装程序,但所有新安装程序都会自动使用。以下是我前进的方法,但无法弄清楚甚至不知道是否可能。

所有组合根都会有这样的东西,以便所有安装程序始终运行。

container.Install(
            FromAssembly.InDirectory(new AssemblyFilter(HttpRuntime.BinDirectory))
        );

但是我希望这个安装代码只运行IAutoInstaller类型的安装程序。通过这种方式,我可以通过将接口更改为IAutoInstaller来返回并修复我的旧安装程序,然后永远不需要修改组合根。

public interface IAutoInstaller : IWindsorInstaller
{

}

public class ScheduledPaymentInstaller : IAutoInstaller
{

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromAssemblyNamed("DryFly.ScheduledPayments")
            .Pick()
            .WithServiceDefaultInterfaces().LifestylePerWebRequest());

    }
}

总之,我所追求的是一种从组合根目录自动执行某些安装程序的方法,这样当我添加新项目时,我不需要修改该代码。我只需要为新项目添加一个新的安装程序。有没有不同的方法来解决这个问题,还是可以通过Castle Windsor来完成?

1 个答案:

答案 0 :(得分:0)

这是可能的,但不是很漂亮:

var container = new WindsorContainer();
var installers = AppDomain.CurrentDomain
         .GetAssemblies() // Load all assemblies in the current application domain
         .SelectMany(s => s.GetTypes()) // project all types contained in all assemblies into a single collection
         .Where(type => typeof(IAutoInstaller).IsAssignableFrom(type) && type.IsClass) // find all types that implement IAutoInstaller and are classes (this filters out the interface itself)
         .Select(Activator.CreateInstance) // project all types into instances - this relies on all of them containing a parameterless constructor
         .Cast<IAutoInstaller>(); // project the Ienumerable<object> into an Ienumerable<IAutoInstaller>

foreach (var installer in installers)
{
    installer.Install(container, container.Kernel.ConfigurationStore);
}

这里有一个很大的警告,那就是你的安装程序必须有一个无参数构造函数才能实现。如果出于某种原因不是这种情况,那么你的问题就变得难以解决。

不幸的是,IWindsorInstaller接口仅强制执行期望容器本身的方法,以及IConfigurationStore的实现。因此,即使您没有使用配置存储,您仍然需要提供它。幸运的是,当您使用默认构造函数实例化WindsorContainer时,它会使用DefaultConfigurationStore实现连接默认内核。这允许你只传入它。

但是,如果您使用的是自定义配置存储(例如使用XML配置解释程序时),并且此配置存储由另一个容器或与当前容器相关的父容器或子容器拥有,并且您需要访问特定安装程序中特定商店的值,您必须将该特定商店引用传递给安装程序。

正如您可以从商店周围的警告列表中看到的那样,您可以安全地传递内核默认值,甚至可以安全地传递DefaultConfigurationStore