使用相同的安装程序设置不同应用程序中的Castle Windsor生活方式

时间:2014-03-15 15:08:16

标签: c# castle-windsor

我有一个问题,即找出使用相同安装程序为不同应用程序注册不同生活方式的最佳方法。

我有一个使用Castle Windsor IoC的网络项目。有些东西的范围是使用PerWebRequest生活方式。这些类在各个项目中向安装人员注册。

到目前为止一切都很好,但我正在考虑将一些东西移到windowsService来做一些预定的事情。此服务将解析与Web项目相同的域,但在使用PerWebRequest生活方式注册类时会遇到麻烦。我想将此更改为Scoped服务,但保持它在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());
    }
}

如果没有安装人员需要了解上下文,告诉windsor我想做什么的正确方法是什么?

2 个答案:

答案 0 :(得分:1)

经过对城堡框架的更多练习,我想指出一个更好的方法来处理这个问题。有一个名为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());

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

答案 1 :(得分:0)

Krzysztof Kozmic的评论当场,但有可能&#34;作弊&#34;通过让组件生活方式的值由仅存在于每个代码库中的组件注入。

让我们说公共库中存在一个接口,具有以下签名:

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

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

// 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服务,或者始终可以找到默认服务
  • 应用程序之间具有共同生活方式的类不会传递给此方法

我不知道这是不是一个好主意,因为它模糊了配置,但它回答了你的问题