好的,我想出了一个非常干净的方法来做到这一点!
首先,我们需要一个 的实现IHandlerSelector
,它可以根据我们对此事的意见选择一个处理程序,或者保持中立(通过返回null
,这意味着“没有意见”)。
/// <summary>
/// Emits an opinion about a component's lifestyle only if there are exactly two available handlers and one of them has a PerWebRequest lifestyle.
/// </summary>
public class LifestyleSelector : IHandlerSelector
{
public bool HasOpinionAbout(string key, Type service)
{
return service != typeof(object); // for some reason, Castle passes typeof(object) if the service type is null.
}
public IHandler SelectHandler(string key, Type service, IHandler[] handlers)
{
if (handlers.Length == 2 && handlers.Any(x => x.ComponentModel.LifestyleType == LifestyleType.PerWebRequest))
{
if (HttpContext.Current == null)
{
return handlers.Single(x => x.ComponentModel.LifestyleType != LifestyleType.PerWebRequest);
}
else
{
return handlers.Single(x => x.ComponentModel.LifestyleType == LifestyleType.PerWebRequest);
}
}
return null; // we don't have an opinion in this case.
}
}
我这样做是为了使意见非常有限。PerWebRequest
只有当恰好有两个处理程序并且其中一个有生活方式时,我才会发表意见;这意味着另一个可能是非 HttpContext 替代方案。
我们需要用 Castle 注册这个选择器。在开始注册任何其他组件之前,我会这样做:
container.Kernel.AddHandlerSelector(new LifestyleSelector());
最后,我希望我知道如何复制我的注册以避免这种情况:
container.Register(
AllTypes
.FromAssemblyContaining<EmailService>()
.Where(t => t.Name.EndsWith("Service"))
.WithService.Select(IoC.SelectByInterfaceConvention)
.LifestylePerWebRequest()
);
container.Register(
AllTypes
.FromAssemblyContaining<EmailService>()
.Where(t => t.Name.EndsWith("Service"))
.WithService.Select(IoC.SelectByInterfaceConvention)
.LifestylePerThread()
);
如果您能找到克隆注册的方法,改变生活方式并注册它们(使用container.Register
或IRegistration.Register
),请将其作为答案发布在这里!:)
更新:在测试中,我需要唯一地命名相同的注册,我这样做是这样的:
.NamedRandomly()
public static ComponentRegistration<T> NamedRandomly<T>(this ComponentRegistration<T> registration) where T : class
{
string name = registration.Implementation.FullName;
string random = "{0}{{{1}}}".FormatWith(name, Guid.NewGuid());
return registration.Named(random);
}
public static BasedOnDescriptor NamedRandomly(this BasedOnDescriptor registration)
{
return registration.Configure(x => x.NamedRandomly());
}