在Castle中注册组件后更改ServiceOverride

时间:2013-05-21 22:55:48

标签: castle-windsor

我为服务注册了两个组件:

container.Register(
    Component.For<IDataStorage>().Named("FirstChoice").ImplementedBy...
    Component.For<IDataStorage>().Named("SecondChoice").ImplementedBy

然后我有一组派生自这个基类的组件,它取决于那些组件:

public abstract class BaseMessageHandler
{
    public IDataStorage FirstStorage {get; set;}

    public IDataStorage SecondStorage {get; set;}
}

如果我手动注册这些“处理程序”(从BaseMessageHandler派生),我会指定一个服务覆盖,指示我想要属性“FirstStorage”和“SecondStorage”的组件。类似的东西:

.Configure(x => x.DependsOn(
    ServiceOverride.ForKey("FirstStorage").Eq("FirstChoice"),
    ServiceOverride.ForKey("SecondStorage").Eq("SecondChoice"))

不幸的是,这个注册是由框架(NServiceBus)自动完成的。我知道如果我首先注册处理程序(在NServiceBus有机会之前),这些注册将会坚持下去。但是我不想尝试猜测并模仿NServiceBus的注册,而是想知道我是否可以在自定义IContributeComponentModelConstruction中指定服务覆盖。 这似乎是一个好地方,我能找到这些属性:

public class DataStorageOverrideContributor : IContributeComponentModelConstruction
{
    public void ProcessModel(Castle.MicroKernel.IKernel kernel, Castle.Core.ComponentModel model)
    {
        var dataStorageDependencies = model.Properties.Where(
            x => x.Dependency.TargetItemType == typeof(IDataStorage));

        foreach (var propertyDependency in dataStorageDependencies)
        {
            // now what??

但我不确定正确的方法:

  • 检查是否已指定服务覆盖(在这种情况下,我什么都不做)
  • 向属性依赖项添加服务覆盖。

这可以在IContributeComponentModelConstruction.ProcessModel方法中检查和处理ComponentModel吗?

1 个答案:

答案 0 :(得分:1)

我会在你的场景中使用一个子顺从解析器。您可以在下面看到有关如何使用它的代码。

古德勒克,

Marwijn。

公共接口IDataStorage     {     }

public class DataStore1 : IDataStorage
{
}

public class DataStore2 : IDataStorage
{
}

public class BaseMessageHandler
{
    public IDataStorage FirstStorage { get; set; }
    public IDataStorage SecondStorage { get; set; }
}

public class SubDependencyResolver : ISubDependencyResolver
{
    private readonly IKernel _kernel;

    public SubDependencyResolver(IKernel kernel)
    {
        _kernel = kernel;
    }

    public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
                           DependencyModel dependency)
    {
        return model.Implementation == typeof (BaseMessageHandler) && dependency.TargetType == typeof(IDataStorage);
    }

    public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
                          DependencyModel dependency)
    {
        var handlers = _kernel.GetHandlers(dependency.TargetType);
        switch (dependency.DependencyKey)
        {
            case "FirstStorage":
                return handlers.Single(h => h.ComponentModel.Implementation == typeof (DataStore1)).Resolve(context);
            case "SecondStorage":
                return handlers.Single(h => h.ComponentModel.Implementation == typeof(DataStore2)).Resolve(context);
        }
        return null;
    }
}

[TestFixture]
public class Tests
{
    [Test]
    public void SomeTest()
    {
        var container = new WindsorContainer();
        container.Kernel.Resolver.AddSubResolver(new SubDependencyResolver(container.Kernel));
        container.Register(
            Component.For<IDataStorage>().Named("FirstChoice").ImplementedBy<DataStore1>(),
            Component.For<IDataStorage>().Named("SecondChoice").ImplementedBy<DataStore2>(),
            Component.For<BaseMessageHandler>()
            );

        var messageHandler = container.Resolve<BaseMessageHandler>();
        Assert.AreEqual(typeof(DataStore1), messageHandler.FirstStorage.GetType());
        Assert.AreEqual(typeof(DataStore2), messageHandler.SecondStorage.GetType());
    }
}

您可以使用的替代方案:

case "FirstStorage":
   return handlers.Single(h => h.ComponentModel.Name == "FirstChoice").Resolve(context);
case "SecondStorage":
   return handlers.Single(h => h.ComponentModel.Name == "SecondChoice").Resolve(context);

解决组件名称而不是实现类型。