Castle Windsor 确实是一个非常强大和成熟的依赖注入平台。它有很多内部扩展,实际上可以实现你的目标。请参阅此处注册内置工具的服务程序集。
我已经使用它近 5 年了,对我来说,以下方法是最好的方法:
// at the startup of the application
_container = (new WindsorContainer()
.AddHelperFacilities() // IWindsorContainer extension that comes from Framework.InversionOfControl
.AddWebApiAdapter() // IWindsorContainer extension that comes from Framework.InversionOfControl.WebApi
.InitializeDomainUsingConventions( // IWindsorContainer extension that comes from Framework.InversionOfControl
AppDomain.CurrentDomain, // domain for which container will be building registrations
"ApplicationName.*", // regext to speed up registration process by processing only services from application namespace
new WebApiControllersRegistrationConvention(), new DefaultRegistrationConvention())); // one or more conventions
// DefaultRegistrationConvention() comes from Framework.InversionOfControl
// WebApiControllersRegistrationConvention() comes from Framework.InversionOfControl.WebApi . A separate assembly to be referenced to avoid extra dependancies on Asp.NET WebApi assemblies
.Resolve<IApplication>.Start(); // resolves application specific entry point and launches the application
然后对于 Framework.InversionOfControl:
namespace Framework.InversionOfControl
{
public static class WindowsContainerExtensions
{
public static IWindsorContainer InitializeDomainUsingConventions(
this IWindsorContainer container, AppDomain appDomain, string commonNamespaceDenominatorMask, params IRegistrationConvention[] registrationConventions)
{
var assembliesToInitialize = new List<Assembly>();
var runtimeAssemblies = new List<Assembly> { Assembly.GetCallingAssembly() };
var processedAssemblies = new List<Assembly>();
runtimeAssemblies.AddRange(appDomain.GetAssemblies());
foreach (var assembly in runtimeAssemblies)
{
ProcessAssembly(assembly, assembliesToInitialize, processedAssemblies, commonNamespaceDenominatorMask, commonNamespaceDenominatorMask == null);
}
var allRuntimeTypes = new List<Type>();
foreach (var assembly in assembliesToInitialize)
{
var assemblyTypes = assembly.GetTypes().ToList();
var installerTypes = assemblyTypes.Where(t => !t.IsInterface && !t.IsAbstract && t.GetInterfaces().Contains(typeof(IWindsorInstaller))).ToArray();
if (installerTypes.Any())
{
foreach (var installer in installerTypes.Select(installerType => (IWindsorInstaller)Activator.CreateInstance(installerType)))
{
container.Install(installer);
}
}
else
{
allRuntimeTypes.AddRange(assemblyTypes);
}
}
foreach (var registrationConvention in registrationConventions)
{
registrationConvention.RegisterTypesUsingConvention(container, allRuntimeTypes);
}
return container;
}
private static void ProcessAssembly(Assembly assembly, List<Assembly> assemblies, List<Assembly> processedAssemblies, string commonNamespaceDenominatorMask, bool fullScan)
{
if (processedAssemblies.Any(x => x.FullName == assembly.FullName)) return;
if (assembly == typeof(WindowsContainerExtensions).Assembly) return;
processedAssemblies.Add(assembly);
var initialize = (new Regex(commonNamespaceDenominatorMask, RegexOptions.IgnoreCase)).Match(assembly.FullName).Success;
if (initialize && assemblies.Any(x => x.FullName == assembly.FullName))
{
initialize = false;
}
if (initialize)
{
assemblies.Add(assembly);
}
foreach (var referencedAssembliyNames in assembly.GetReferencedAssemblies())
{
var referencedAssembliyNames1 = referencedAssembliyNames;
if (assemblies.Any(x => x.FullName == referencedAssembliyNames1.FullName)) continue;
if (fullScan == false && (new Regex(commonNamespaceDenominatorMask, RegexOptions.IgnoreCase)).Match(assembly.FullName).Success == false) continue;
Assembly referencedAssembliy;
try
{
referencedAssembliy = Assembly.Load(referencedAssembliyNames);
}
catch
{
continue;
}
ProcessAssembly(referencedAssembliy, assemblies, processedAssemblies, commonNamespaceDenominatorMask, fullScan);
}
}
public static IWindsorContainer AddHelperFacilities(this IWindsorContainer container)
{
container.AddFacility<TypedFactoryFacility>();
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
container.Register(Component.For<IWindsorContainer>().ImplementedBy<WindsorContainer>());
container.Register(Component.For<IContainerAccessor>().ImplementedBy<ContainerAccessor>());
container.Resolve<IContainerAccessor>().Container = container;
return container;
}
}
public interface IRegistrationConvention
{
IWindsorContainer RegisterTypesUsingConvention(IWindsorContainer container, List<Type> assemblyTypes);
}
public class DefaultRegistrationConvention : IRegistrationConvention
{
/// <summary>
/// Register every service possible from the calling assembly with default singleton lifestyle
/// with the exception of ISomething Factory where the the ISomething GetSomething() where
/// Something that implements ISomething is registered with transient lifestyle
/// </summary>
public IWindsorContainer RegisterTypesUsingConvention(IWindsorContainer container, List<Type> assemblyTypes)
{
// Step 1: Factories installation.
// We register interfaces ending 'Factory' keyword like proxy (implementionless) factories.
var factoryServices = new List<Type>();
var factorySelector = new FullNameFactorySelector();
foreach (var factoryType in assemblyTypes.Where(t => t.Name.EndsWith("Factory") && t.IsInterface))
{
foreach (var method in factoryType.GetMethods())
{
if (method.Name.StartsWith("Get") == false) continue;
if (method.ReturnType.IsInterface == false) continue;
factoryServices.Add(method.ReturnType);
}
container.Register(Component.For(factoryType).AsFactory(factorySelector));
}
// Step 2: Rest of the services registrations
// transientServices list is populated with services that needs to has transient lifespan
// everything else needs to go as preconfigured lifestyle - lifeStyleType
var components = assemblyTypes.Where(t => !t.IsInterface && !t.IsAbstract);
foreach (var component in components)
{
// for every interface and implementation do registration
foreach (var service in component.GetInterfaces())
{
IRegistration registration;
Type service1 = service;
if (factoryServices.Any(x => x.FullName == service1.FullName))
{
if (component.IsGenericType)
{
// GetInterfaces() and GetMethod().ReturnType both returns Type.FullName = null
// Castle.Windsor fails to Resolve later generic types if registered type is with FullName = null,
// Workaround is to find the type with correct FullName from the 'assemblyTypes'
var serviceWithFullName = assemblyTypes.FirstOrDefault(x => x.Name == service1.Name);
if (serviceWithFullName == null) continue; // if null then the mapping is not supported by this convention
registration = Component.For(serviceWithFullName)
.ImplementedBy(component)
.LifestyleTransient()
.Named(serviceWithFullName.FullName + " / " + component.FullName);
}
else
{
registration = Component.For(service)
.ImplementedBy(component)
.LifestyleTransient()
.Named(service.FullName + " / " + component.FullName);
}
}
else
{
registration = Component.For(service)
.ImplementedBy(component)
.Named(service.FullName + " / " + component.FullName)
.LifeStyle.Is(LifestyleType.Singleton);
}
container.Register(registration);
}
}
return container;
}
}
}
以上所有功能都以模块化和可扩展的方式完成了 Castle Windsor 已经在做的事情,而不会限制 Castle Windsor 的功能。只需几行,它就可以按照约定注册整个应用程序,并允许添加特定约定,例如:Mvc、WebApi、AutoMapper、Wcf、Quartz 等