【问题标题】:Castle Windsor Configuration: Set Order for FromAssembly.InDirectory for DecoratorsCastle Windsor 配置:为装饰器的 FromAssembly.InDirectory 设置顺序
【发布时间】:2013-08-26 08:47:00
【问题描述】:

我有一个 Windsor 服务和两个实现它的组件: 一个是“真实”服务,一个是“代理”(作为装饰器实现),将调用路由到“真实”服务或 Web 服务。

现在理想的情况是,如果找到代理 DLL,代理将用作装饰器。 如果它不存在,所有调用都将直接转到“真实”服务。

我目前正在使用“FromAssembly.InDirectory”来注册组件,这就像一个魅力。 但是,我认为这只是因为程序集恰好以正确的字母顺序命名,因此“真实”服务在“代理”(装饰器)之前注册。 (如果我错了,请纠正我。)

这对我来说看起来不太健壮。 有没有更好的方法来做到这一点,而无需手动配置配置文件中的每个组件?

我想要一个配置文件,我只会按正确的顺序列出程序集,并且这些文件中的所有组件都会自动注册(就像 FromAssembly.Named)。

或者——那会更好——一些机制可以自动确定哪个组件是装饰器(毕竟,它依赖于它实现的服务,而“真正的”服务没有),以及哪个一个是“真正的服务”,然后按照正确的顺序自动注册。

我当然可以自己实现后一种逻辑,但我不想重新发明轮子。

任何建议都将受到高度赞赏。 谢谢!

编辑: 这就是我到目前为止所拥有的。 如何确保命名默认组件(装饰器,如果有,则为默认组件),以便 WCF 工具可以通过其名称找到它? 我的意思是,我可以在装饰器部分添加一个“命名”调用,但是如果没有定义装饰器怎么办?

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        var currDomain = AppDomain.CurrentDomain;
        var webAppBinDir = currDomain.RelativeSearchPath;
        var assemblyDir = (!string.IsNullOrEmpty(webAppBinDir)) ? webAppBinDir : currDomain.BaseDirectory;

        container.Register(
            Classes.FromAssemblyInDirectory(new AssemblyFilter(assemblyDir, Mask))
                   .Where(ImplementsServiceContract)
                   .WithServiceSelect((x, y) => GetServices(x))
                   .ConfigureIf(IsDecorator, c => c.IsDefault(y => IsDecorating(c, y)))
            );
    }

    private static bool ImplementsServiceContract(Type type)
    {
        return GetServices(type).Any();
    }

    private static IEnumerable<Type> GetServices(Type type)
    {
        return type.GetInterfaces().Where(IsServiceContract);
    }

    private static bool IsServiceContract(Type type)
    {
        var ns = type.Namespace;
        return ns != null && ns.StartsWith(NamespacePrefix) && Attribute.IsDefined(type, typeof(ServiceContractAttribute));
    }

    private static bool IsDecorator(ComponentRegistration c)
    {
        Type component = c.Implementation;
        return GetServices(component).Any(x => IsDecorating(c, x));
    }

    private static bool IsDecorating(ComponentRegistration c, Type service)
    {
        Type component = c.Implementation;
        return service.Assembly != component.Assembly;
    }

【问题讨论】:

    标签: c# .net reflection castle-windsor decorator


    【解决方案1】:

    使用IsDefault作为装饰器

    doco

    如果您没有对该程序集的引用(为什么没有?),则使用 .ConfigureIf 并以某种方式匹配类型(可能按名称)

    【讨论】:

    • 谢谢!您将如何使其尽可能健壮且易于配置?如果包含程序集存在,我希望正确注册装饰器。但是 FromAssembly.InDirectory 依赖于字母顺序,不是吗?我应该编写自己的 InstallerFactory 吗?
    • 根据我的回答,如果您使用 IsDefault,则不再需要 InstallerFactory
    • 非常感谢您在编辑中的澄清,@krzysztof-kozmic!我已经编辑了我的原始问题以包含一个后续问题。也想看看吗? :)
    【解决方案2】:

    我在这种情况下的旧方法是在 web.config 或专用 xml 文件中注册声明符。 从 3.1 版开始,您可以为给定接口指定默认组件:使用命名约定策略将装饰器设置为默认组件变得非常容易,无论具体注册如何。

    我用来确保注册顺序的另一种方法(不仅仅是装饰器)是创建一个 InstallerFactory,这样您就可以轻松地推动安装程序的执行顺序。

    对不起,如果我没有提供任何代码示例...但是我现在正在休假

    【讨论】:

    • 你能详细说明一下这个“默认组件”吗?我应该在哪里设置?
    • 您是在谈论“后备组件”(docs.castleproject.org/Windsor.Whats-New-In-Windsor-31.ashx)吗?这对装饰师有帮助吗?我可以在一次调用中为所有组件使用它,还是仍然需要配置每个组件?
    • docs.castleproject.org/Windsor.Whats-New-In-Windsor-3.ashx 搜索组件现在可以“强制”成为其服务的默认值,而无需成为第一个注册的服务¶
    • 但是装饰器不应该是最先注册的组件吗? mikehadlow.blogspot.de/2010/01/… 官方文档提到使用 IHandlerSelector 指定顺序:docs.castleproject.org/Windsor.Decorators.ashx 但我不太确定这是否是我想要的。我有一个实现服务的组件和一个装饰器(每个服务 - 所以它可能总共有 10 个左右)。我想要的只是装饰器以尽可能少的配置“包装”/装饰默认组件,而无需任何解析循环。
    • 如果你真的需要实现装饰器模式,windsor 会在没有额外配置的情况下处理它以防止循环问题。最简单的场景是让 2 个组件实现相同的接口。装饰器实现将具有作为构造函数依赖相同的接口实例。 Windsor 使用为该接口注册的早期组件,但使用当前 One 来避免循环问题。我建议的 IsDefault 配置不是用于实现相同接口的嵌套组件,而是用于接口作为其他组件的依赖
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 2012-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多