【问题标题】:Setting different Castle Windsor lifestyle from different applications using the same installer使用相同的安装程序从不同的应用程序设置不同的温莎城堡生活方式
【发布时间】:2014-04-20 22:52:41
【问题描述】:

我不知道最好的方法是使用相同的安装程序为不同的应用程序注册不同的生活方式。

我有一个使用 Castle Windsor IoC 的 Web 项目。有些事情的范围是使用 PerWebRequest 生活方式。这些类在各自项目中的安装程序中注册。

到目前为止一切都很好,但我正在考虑将一些东西移到 windowsService 来做一些预定的东西。此服务将解析与 Web 项目相同的域,但当类注册到 PerWebRequest 生活方式时会出现问题。我想将其更改为服务的范围,但保持它在 Web 应用程序中的状态。配置是在保存在相应程序集中的安装程序中完成的。

安装程序不知道哪个应用程序正在尝试注册,但根据安装程序是从 Web 应用程序还是 Windows 服务注册的,注册需要具有不同的生活方式。

现在我已经恢复到一个丑陋的黑客,直到我得到更好的解决方案。

private static bool scopeLifetime = false;
public static void SetScopedLifetime()
{
    scopeLifetime = true;
}

public void Install(IWindsorContainer container, IConfigurationStore store)
{
    var registrations = Classes.FromThisAssembly()
        .WithService.DefaultInterfaces();

    if (scopeLifetime)
    {
        container.Register(registrations.LifestyleScoped());
    }
    else
    {
        container.Register(registrations.LifestylePerWebRequest());
    }
}

在安装人员不需要知道上下文的情况下,告诉温莎我想做什么的正确方法是什么?

【问题讨论】:

  • 安装程序不能重复使用。让它们保持简单、简洁和专注。
  • 但是什么是更好的解决方案,创建具有不同生活方式的安装程序副本(违反 DRY,并且通过不注册每个安装程序使程序集扫描更加困难),或者将安装程序移动到一个地方我们知道上下文(将内部细节的责任转移到另一个项目)?听起来都不太好。我是否错过了解决此问题的另一种方法?
  • 干燥是一个规则。不是法律。并且安装程序应该在每个应用程序的根程序集中,这样扫描就不会成为问题

标签: c# castle-windsor


【解决方案1】:

Krzysztof Kozmic 的评论是当场的,但是通过让仅存在于每个代码库中的组件注入组件生活方式的价值来“作弊”是可能的。

假设您的公共库中存在一个接口,具有以下签名:

public interface ISetLifestyle
{
    BasedOnDescriptor SetLifestyle(BasedOnDescriptor descriptor);
}

并在您的每个特定组件(即服务和网络应用程序)中实现

// this class exists only in your webapp
public class SetLifestyleOnWebApp: ISetLifestyle
{
    public BasedOnDescriptor SetLifestyle(BasedOnDescriptor descriptor)
    {
        return descriptor.LifestylePerWebRequest();
    }
}

// this class exists only in your windows service
public class SetLifestyleOnService : ISetLifestyle
{
    public BasedOnDescriptor SetLifestyle(BasedOnDescriptor descriptor)
    {
        return descriptor.LifestyleTransient(); // or whatever scope you need
    }
}

在您的常用配置中,您可以先注册ISetLifestyle 服务,然后使用它来定义组件的生活方式。

container.Register(Classes.FromAssemblyInThisApplication().BasedOn<ISetLifestyle>().WithServiceBase());
var myCustomLifestyleSetter = container.Resolve<ISetLifestyle>();

var customLifestyleRegistrations = myCustomLifestyleSetter.SetLifestyle(Classes.FromThisAssembly().Pick().WithServiceDefaultInterfaces());
container.Register(customLifestyleRegistrations);

您需要确保

  • 每个应用程序都定义了一个 ISetLifestyle 服务,或者总是可以找到一个默认的服务
  • 应用程序之间具有共同生活方式的类不会传递给此方法

我不知道这是否是个好主意,因为它掩盖了配置,但它回答了您的问题

【讨论】:

    【解决方案2】:

    在对城堡框架进行了更多练习之后,我想指出一个更好的方法来处理这个问题。有一个名为IContributeComponentModelConstruction 的接口可让您在组件注册后对其进行操作。它在每次注册后使用,因此可用于在您的组件配置上投放广泛的网络。 Mark Seeman 巧妙地描述了您的特殊问题in a blog post

    鉴于此安装程序:

    public class FooInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container,
            IConfigurationStore store)
        {
            container.Register(Component.For<IFoo>().ImplementedBy<Foo>().LifeStyle.Transient);
        }
    }
    

    您可能想在另一个环境中改变生活方式,因此创建一个IContributeComponentModelConstruction 的实例并将其添加到容器中

    public class SingletonEqualizer :
        IContributeComponentModelConstruction
    {
        public void ProcessModel(IKernel kernel, 
            ComponentModel model)
        {
            model.LifestyleType = LifestyleType.Singleton;
        }
    }
    
    /*  ---  */
    
    var container = new WindsorContainer();
    container.Kernel.ComponentModelBuilder
        .AddContributor(new SingletonEqualizer()); // before the intaller is called
    container.Install(new FooInstaller());
    

    每个组件都将改变其生活方式;您还可以根据正在注册的组件优化行为。回想起来,我真的认为这是对您问题的最佳答案。

    【讨论】:

    • 从痛苦的经验中我可以建议,这种方法将最明确地破坏事物,例如类型工厂。
    • @miracledev 你能详细说明一下吗?我很好奇你的评论;我知道有些城堡组件的配置可能很繁琐,有时可能有点僵硬,但到目前为止我还没有遇到任何“破损”
    • 使用网络解决方案并且需要或多或少地使用相同的注册来为控制台应用程序测试某些东西我尝试了这种方法。它破坏了解决方案中的 TypedFactory 并带有非常神秘的错误消息:“找不到有关工厂方法 {0} 的信息。这很可能是一个错误。请报告它”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多