Castle Windsor: Register class with internal constructor?
A Castle Windsor question: Is it possible to register a class that has an internal constructor with the co开发者_开发知识库ntainer?
Thanks Joni
Yes, it is possible. Default component activator looks only for public constructors. You can either provide custom component activator for that component that would take internal constructor into account, or use for example factory to activate the component:
var container = new WindsorContainer()
.AddFacility<FactorySupportFacility>()
.Register( Component.For<Foo>()
.UsingFactoryMethod( () => new Foo() ) );
var foo = container.Resolve<Foo>();
However you should really reconsider making the .ctor internal in the first place. It is really rarely a good idea to do so, especially when you're exposing the class as a component to the outside world anyway.
Following the accepted answer's advice, I was able to extend the DefaultComponentActivator
class to work with protected
constructors (it still does not work with private
or internal
; the code below works fine, that is, but something else in the DynamicProxy creation chain fails).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Castle.Core;
using Castle.MicroKernel;
using Castle.MicroKernel.ComponentActivator;
using Castle.MicroKernel.Context;
namespace /* YourNameSpaceHere */
{
[Serializable]
public class NonPublicComponentActivator : DefaultComponentActivator
{
public NonPublicComponentActivator(ComponentModel model, IKernelInternal kernel, ComponentInstanceDelegate onCreation, ComponentInstanceDelegate onDestruction)
: base(model, kernel, onCreation, onDestruction)
{ /* do nothing */ }
private readonly List<Type> loadedTypes = new List<Type>();
protected override ConstructorCandidate SelectEligibleConstructor(CreationContext context)
{
lock (loadedTypes)
{
if (!loadedTypes.Contains(context.RequestedType))
{
loadedTypes.Add(context.RequestedType);
// Add the missing non-public constructors too:
var ctors = context.RequestedType.GetConstructors
(
BindingFlags.NonPublic | BindingFlags.Instance
);
foreach (var ctor in ctors)
{
Model.AddConstructor
(
new ConstructorCandidate
(
ctor,
ctor.GetParameters().Select(pi => new ConstructorDependencyModel(pi)).ToArray()
)
);
}
}
}
return base.SelectEligibleConstructor(context);
}
}
}
Then, on your container you register this against a ComponentRegistration
object via the generic Activator
method, so my container.Register call looks something like this:
_container.Register
(
// . . .
AllClasses.FromThisAssembly().BasedOn<ISomeInterface>()
.Configure
(
c => c.LifeStyle.Transient
.Interceptors<MyInterceptor>()
.Activator<NonPublicComponentActivator>() // <--- REGISTERED HERE
),
// . . .
);
Hope that helps someone!
It is easier to avoid the issue by having the class be internal and its constructor public, then you can register it with IncludeNonPublicTypes().
// All other classes
Classes.FromThisAssembly()
.IncludeNonPublicTypes() // Internal types
.Where(x => !x.IsAbstract)
.Configure(x => x.Named(Guid.NewGuid().ToString()))
精彩评论