我花了一些时间环顾四周,似乎没有一个明显的解决方案。
我从一个程序集中注册所有类型(大约有80种类型,接口在单独的程序集中)
public static void RegisterAllFromAssemblies(string a)
{
IoC.Container.Register(
AllTypes.FromAssemblyNamed(a)
.Pick()
.WithService.FirstInterface()
.Configure(o => o.LifeStyle.PerWebRequest)
);
}
现在说如果我想为其中一个对象使用不同的LifeStyle,我无法覆盖,因为我将获得 已经为给定密钥注册了一个组件 错误。
我已经研究了在注册后修改生活方式的各种方法,但到目前为止还没有能够做任何事情。
这里应该是什么理想的解决方案?我不想放弃AllTypes功能。
我想我可以在注册所有内容时指定 .Where 过滤器并跳过一些手动注册的对象,但这不是一个非常有企业的解决方案..
答案 0 :(得分:3)
我相信你所说的是在程序集中注册所有类型,其中程序集中的某些类型可能需要使用不同的生活方式进行注册。所以你有IRepository需要是一个PerWebRequest和ITypeMapper,它可以是一个单身。
我澄清,因为你也可能意味着你希望IRepository在你的代码中的一个位置是一个PerWebRequest而在另一个位置是一个单独的。在不创建疯狂生活方式的情况下,您可以创建组件并将其注册为默认生活方式。如果您有时需要另一种生活方式,您可以创建一个新组件并继承现有组件,仅用于注册(代码示例显示此情况,如果这令人困惑)。
我编写了示例,以便它适用于任何一种情况,我提供了几种不同的方法,所有方法都围绕着一次配置多个项目的过滤功能。
对于这个,我正在按类型调用特定组件的配置。它并不像你所说的那样“精力充沛”,但如果你只对规则有一些例外,那么意图就更清楚了。你会注意到你可以链接在一起配置。除非是必需的,因为第二个配置将为第一个配置选择组件,因为我唯一的条件是服务基于IService。这假设castle按顺序处理配置。我相信这个假设是合理的,但暂时没有看过来源。
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(),那么您将更难以解决问题。默认接口只是告诉城堡,在注册Foo组件时,如果它实现了一个名为IFoo的接口,则使用服务IFoo。
其次,我相信如果你将注册逻辑划分为内聚单元,你可能不会遇到这个问题。关键是要有许多实现IWindsorInstaller的安装程序文件。在这些安装程序内部,您只能注册(使用类或类型以保持企业仍然存在)对特定安装程序有意义的类型。您在同一个安装程序中有多种生活方式问题的可能性非常低(如果您发现这一点,则可能需要更多安装程序)
如果您遵循这种方法,最终可能会得到RepositoryInstaller,ViewInstaller,ControllerInstaller等。More on installers can be found on the castle documentation site
如果您需要,可以执行的操作是为您的所有系统提供一个通用的boostrapper,它可以查看应用程序目录并安装目录中的所有安装程序。因为这不是你要求的我会停止详细说明,但如果有兴趣你可以ping我,我可以告诉你更多我正在谈论的内容。
作为控制台应用的完整示例代码:
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();
}
}
}
答案 1 :(得分:1)
您可以先选择手动注册例外吗?如果是这样,手动注册的组件将不会被“AllTypes”重新注册(我建议你改用Classes)。 如果在“组”注册后手动注册组件,则会抛出异常,但反之亦然。
例如
//YourImplementation lives in assembly 'a'
IoC.Container.Register(
Component.For<YourInterface>().ImplementedBy<YourImplementation>().LifestyleSingleton()
);
IoC.Container.Register(
Classes.FromAssemblyNamed(a)
.Pick()
.WithService.FirstInterface()
.Configure(o => o.LifeStyle.PerWebRequest)
);