我有一个包含多个子目录的目录:
/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
来调用我的类型工厂时,组件将被正确解析。但是当我使用任何其他目录名称调用类型化工厂时,它会因为无法找到名称而失败,但它似乎没有考虑到存在可以匹配它的默认实现的事实。
如果找不到名称,是否可以通过默认组件的回退来管理组件的命名解析?
答案 0 :(得分:2)
在Castle V3的Breaking changes txt文件中,明确提到了这个问题:
更改 - 使用
DefaultTypedFactoryComponentSelector
时键入的工厂 按名称解析组件不会回退到按类型if解析 找不到具有该名称的组件,并将抛出异常 代替。
- id - typedFactoryFallbackToResolveByTypeIfNameNotFound
- 影响 - 中等
- 可修复性 - 简单
description - 来自v2.5的原始行为可能导致案例中的错误 当命名组件未注册或名称拼写错误时 并且会选择一个错误的组件导致潜在的严重 应用程序中的问题。新版本适应快速失败的方法 这些案例给予开发人员即时反馈的配置 错。
修复 - 实际修复取决于您想要的行为部分:
- 如果你关心后备行为,那就是按名称获取组件,如果不存在后退以按类型解析,那么你 注册工厂时可以明确指定:
.AsFactory(new DefaultTypedFactoryComponentSelector(fallbackToResolveByTypeIfNameNotFound: true));
我真的不喜欢没有替代的“官方”方式这样做,因为该属性被标记为仅用于向后兼容并且不推荐使用它,但至少它可以工作。
如果你知道更好的方法,我会非常有兴趣听到它:)
答案 1 :(得分:0)
取而代之的是自定义选择器? 创建一个实现ITypedFactoryComponentSelector的类,并将其链接到您键入的工厂。
ITypedFactoryComponentSelector提供更多灵活性:您可以通过func访问容器作为返回参数