castle windsor学习-----Registering components by conventions
注册多个组件
1.one-by-one注册组件可能是一项非常重复的工作,可以通过Classes或Types注册一组组件(你可以指定一些特定的特征)
三个步骤
注册多个类型通常采取以下结构
container.Register(Classes.FromThisAssembly() .InSameNamespaceAs<RootComponent>() .WithService.DefaultInterfaces() .LifestyleTransient());
可以看成三个不同的步骤
1)选择程序集
第一步指定Windsor要扫描的程序集,可以使用如下方法(或者使用它的姊妹方法)
Classes.FromThisAssembly()...
2)选择要扫描的程序集后,你可以筛选一些类型来注册,选择下面三种方式
a. 通过基类型或者实现的接口
Classes.FromThisAssembly().BasedOn<IMessage>()
b. 通过命名空间筛选类型
Classes.FromAssemblyInDirectory(new AssemblyFilter("bin")).InNamespace("Acme.Crm.Extensions")
c. 通过任何一个条件筛选
Classes.FromAssemblyContaining<MyController>().Where( t=> Attribute.IsDefined(t, typeof(CacheAttribute)))
d. 获取所有的类型
Classes.FromAssemblyNamed("Acme.Crm.Services").Pick()
附加过滤和配置
通过上面筛选到了类型源,你也可以给它们添加额外的配置或过滤条件,下面我们讨论所有的api使用
BaseOn、Where、Pick 如果使用多次需谨慎
container.Register( Classes.FromThisAssembly() .BasedOn<IMessage>() .BasedOn(typeof(IMessageHandler<>)).WithService.Base() .Where(Component.IsInNamespace("Acme.Crm.MessageDTOs")) );
注册所有子类
container.Register( Classes.FromThisAssembly() .BasedOn<SmartDispatcherController>() .Configure(c => c.Lifestyle.Transient) );
记住 Of 、Pick和其他过滤方法只是缩小注册类型的范围
他们没有指定服务的提供者,也就是说上面的注册只是注册继承了SmartDispatcherController服务的自己类型,SmartDispatcherController并没有被注册
所以调用如下方法将出现异常
var controller = container.Resolve<SmartDispatcherController>();
选择组件的服务
默认的 组件的服务就是类型本身,一些场景下这是不够的,Windsor让你指定明确的服务类型
Base()
container.Register( Classes.FromThisAssembly() .BasedOn(typeof(ICommand<>)).WithService.Base(), Classes.FromThisAssembly() .BasedOn(typeof(IValidator<>)).WithService.Base() );
这里我们注册了所有实现ICommand<>和IValidator的类型。
DefaultInterfaces()
container.Register( Classes.FromThisAssembly() .InNamespace("Acme.Crm.Services") .WithService.DefaultInterfaces() );
FromInterface()
container.Register( Classes.FromThisAssembly() .BasedOn<IService>().WithService.FromInterface() );
AllInterfaces()
When a component implements multiple interfaces and you want to use it as a service for all of them, use WithService.AllInterfaces()
method.
Self()
To register the component implementation type explicitly as a service use WithService.Self()
Select()
If none of the above options suits you you can provide your own selection logic as a delegate and pass it to WithService.Select()
method.
Registering non-public types
By default only types visible from outside of the assembly will be registered. If you want to include non-public types, you have to start with specifying assembly first, and then call IncludeNonPublicTypes
container.Register( Classes.FromThisAssembly() .IncludeNonPublicTypes() .BasedOn<NonPublicComponent>() );
Configuring registration
container.Register( Classes.FromAssembly(Assembly.GetExecutingAssembly()) .BasedOn<ICommon>() .Configure(component => component.LifestyleTransient()) );
container.Register( Classes.FromAssembly(Assembly.GetExecutingAssembly()) .BasedOn<ICommon>() .LifestyleTransient() );
container.Register( Classes.FromAssembly(Assembly.GetExecutingAssembly()) .BasedOn<ICommon>() .LifestyleTransient() .Configure(component => component.Named(component.Implementation.FullName + "XYZ")) );
container.Register( Classes.FromThisAssembly() .BasedOn<ICommon>() .LifestyleTransient() .Configure( component => component.Named(component.Implementation.FullName + "XYZ") ) .ConfigureFor<CommonImpl1>( component => component.DependsOn(Property.ForKey("key1").Eq(1)) ) .ConfigureFor<CommonImpl2>( component => component.DependsOn(Property.ForKey("key2").Eq(2)) ) );
container.Register( Classes.FromThisAssembly() .BasedOn<ICommon>() .LifestyleTransient() .Configure( component => component.Named(component.Implementation.FullName + "XYZ") ) .ConfigureIf( x => x.Implementation.Name.StarsWith("Common"), component => component.DependsOn(Property.ForKey("key1").Eq(1)) ) );