如果Castle中不存在名称,则使用默认回退按名称解析组件

时间:2014-05-23 14:01:11

标签: c# castle-windsor

我有一个包含多个子目录的目录:

/Xml
  /Documents
  /Registrations
  /Stuff
  /...

用户可以在这些子目录中删除xml文件,并且在一些非活动时间之后我有一个被动FileSystemWatcher捕获文件(以确保文件已准备好处理)。

“Documents”文件夹需要与其他文件夹不同的进程,因此我创建了两个继承相同界面的组件:

public interface IXmlMessageHandler { void ProcessMessage(FileInformation fi); }

public class DocumentsXmlMessageHandler: IXmlMessageHandler { /* SNIP ... */ }

public class DefaultXmlMessageHandler: IXmlMessageHandler { /* SNIP ... */ }

我已经习惯了 Castle v3.2 中的类型化工厂,所以我决定使用我通常需要路由的相同模式:注册一个catch-all组件默认值,然后为特定行为提供其他组件(here is an exemple,其中讨论了Null对象模式)。不同之处在于我需要按文件夹而不是按类型进行路由,但是类型化工厂允许您在解析时定义组件名称。我在想的是创建名称可以与他们链接的文件夹匹配的组件,当找到不匹配的文件夹时会弹出默认组件。

所以我创建了一个类型工厂,工厂选择器,并注册了我的组件

public interface IXmlMessageHandlerFactory {
    IXmlMessageHandler RetrieveMessageHandler(FileInformation fi);
}

public class XmlHandlerFactorySelector : DefaultTypedFactoryComponentSelector {
    protected override string GetComponentName(System.Reflection.MethodInfo method, object[] arguments) {
        return (arguments[0] as FileInformation).FolderName.ToLower();
    }
}

Classes.FromAssemblyInThisApplication()
.BasedOn<IXmlMessageHandler>().WithService.AllInterfaces()
.Configure(c => {
    var name = c.Implementation.Name.Replace("XmlMessageHandler", string.Empty).ToLower();
    c.Named(name);
    if (name == "default")
    {
        c.IsDefault();
    }
})

当我使用来自“Documents”目录的FileInformation来调用我的类型工厂时,组件将被正确解析。但是当我使用任何其他目录名称调用类型化工厂时,它会因为无法找到名称而失败,但它似乎没有考虑到存在可以匹配它的默认实现的事实。

如果找不到名称,是否可以通过默认组件的回退来管理组件的命名解析?

2 个答案:

答案 0 :(得分:2)

在Castle V3的Breaking changes txt文件中,明确提到了这个问题:

  

更改 - 使用DefaultTypedFactoryComponentSelector时键入的工厂   按名称解析组件不会回退到按类型if解析   找不到具有该名称的组件,并将抛出异常   代替。

     
      
  • id - typedFactoryFallbackToResolveByTypeIfNameNotFound
  •   
  • 影响 - 中等
  •   
  • 可修复性 - 简单
  •   
     

description - 来自v2.5的原始行为可能导致案例中的错误   当命名组件未注册或名称拼写错误时   并且会选择一个错误的组件导致潜在的严重   应用程序中的问题。新版本适应快速失败的方法   这些案例给予开发人员即时反馈的配置   错。

     

修复 - 实际修复取决于您想要的行为部分:

     
      
  • 如果你关心后备行为,那就是按名称获取组件,如果不存在后退以按类型解析,那么你   注册工厂时可以明确指定:.AsFactory(new DefaultTypedFactoryComponentSelector(fallbackToResolveByTypeIfNameNotFound: true));
  •   

我真的不喜欢没有替代的“官方”方式这样做,因为该属性被标记为仅用于向后兼容并且不推荐使用它,但至少它可以工作。

如果你知道更好的方法,我会非常有兴趣听到它:)

答案 1 :(得分:0)

取而代之的是自定义选择器? 创建一个实现ITypedFactoryComponentSelector的类,并将其链接到您键入的工厂。

ITypedFactoryComponentSelector提供更多灵活性:您可以通过func访问容器作为返回参数