我相信您说的是注册程序集中的所有类型,其中可能需要使用不同的生活方式注册程序集中的某些类型。所以你有 IRepository 需要是 PerWebRequest 和 ITypeMapper 可以是单例。
我澄清一下,因为您也可能意味着您希望 IRepository 在代码中的一个位置成为 PerWebRequest,而在另一个位置成为单例。在不创建疯狂生活方式的情况下,您可以创建组件并将其注册为默认生活方式。如果您需要另一种生活方式,有时您可以创建一个新组件并从现有组件继承仅用于注册(如果这令人困惑,代码示例会显示这一点)。
我编写了示例,以便它适用于任何一种情况,并且我提供了几种不同的方法,所有方法都集中在一次配置多个项目的过滤能力上。
对于这个,我按类型调用特定组件的配置。它并不像您所说的那样“精力充沛”,但是如果您对该规则只有一些例外,则意图会更清楚。您会注意到您可以将配置链接在一起。除非是必需的,因为第二个配置将为第一个配置选择组件,因为我唯一的条件是服务基于 IService。这假设城堡按顺序处理配置。我相信这个假设是合理的,但有一段时间没有查看来源。
container.Register(
Classes.FromThisAssembly()
.BasedOn<IService>()
.ConfigureFor<MyComponentAsSingleton>(component => component.LifestyleSingleton())
.Configure(component => component.LifestylePerWebRequest()).Unless(type => container.Kernel.GetAssignableHandlers(type).Count() > 0));
这个使用属性来更一般地偏离正常的生活方式“PerWebRequest”
container2.Register(
Classes.FromThisAssembly()
.BasedOn<IService>()
.ConfigureIf(
//condition to check - do we have our custom Attribute?
registration => registration.Implementation.GetCustomAttributes(false).Any(attr => typeof(ShouldBeSingleton).IsAssignableFrom(attr.GetType())),
//if true register as singleton
component => component.LifestyleSingleton(),
//else register as per web request
component => component.LifestylePerWebRequest()
));
现在我已经为您提供了一些解决您当前问题的示例(据我了解),让我免费为您提供建议!
首先我不太喜欢WithService.FirstInterface()。正如智能感知所说,当您实现多个接口时,它是不确定的。任何开发人员都可以进来对类进行无害的接口更改,然后破坏系统。如果您可以使用 WithService.DefaultInterfaces() 侥幸逃脱,那么您将有一个更难搞砸的解决方案。默认接口只是告诉 Castle 在注册 Foo 组件时,如果它实现了名为 IFoo 的接口,则使用服务 IFoo。
其次,我相信如果您将注册逻辑划分为有凝聚力的单元,您可能不会遇到这个问题。关键是要有许多实现 IWindsorInstaller 的安装程序文件。在这些安装程序中,您只需注册(使用类或类型以保持企业化)对特定安装程序有意义的类型。您在同一个安装程序中存在多种生活方式问题的可能性非常低(如果您发现这种情况,您可能需要更多安装程序)
如果您采用这种方法,您最终可能会得到 RepositoryInstaller、ViewInstaller、ControllerInstaller 等。More on installers can be found on the castle documentation site
如果您愿意,您可以做的是为您的所有系统创建一个通用的 boostrapper,它可以查看应用程序目录并安装该目录中的所有安装程序。由于这不是你要求的,我将停止详细说明,但如果有兴趣,你可以联系我,我可以向你展示更多关于我在说什么的信息。
作为控制台应用程序的完整示例代码:
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MultipleLifecyles
{
[AttributeUsage(AttributeTargets.Class)]
public class ShouldBeSingleton : Attribute
{
}
public interface IService
{
void DoSomething();
}
public class MyComponent : IService
{
public void DoSomething()
{
throw new NotImplementedException();
}
}
[ShouldBeSingleton]
public class MyComponentAsSingleton : MyComponent
{
}
class Program
{
static void Main(string[] args)
{
//option 1
IWindsorContainer container = new WindsorContainer();
container.Register(
Classes.FromThisAssembly()
.BasedOn<IService>()
.ConfigureFor<MyComponentAsSingleton>(component => component.LifestyleSingleton())
.Configure(component => component.LifestylePerWebRequest()).Unless(type => container.Kernel.GetAssignableHandlers(type).Count() > 0));
IWindsorContainer container2 = new WindsorContainer();
container2.Register(
Classes.FromThisAssembly()
.BasedOn<IService>()
.ConfigureIf(
//condition to check - do we have our custom Attribute?
registration => registration.Implementation.GetCustomAttributes(false).Any(attr => typeof(ShouldBeSingleton).IsAssignableFrom(attr.GetType())),
//if true register as singleton
component => component.LifestyleSingleton(),
//else register as per web request
component => component.LifestylePerWebRequest()
));
Console.ReadLine();
}
}
}