Does structuremap allow you to do constructor injection in a lazy fashion?
Meaning not creating the object which is injected until it is used?
UPDATE: StructureMap v3 implements this out of the box, so this trick is no longer necessary.
StructureMap version 2 doesn't, but with a few tricks you can get it to do what I believe you are looking for. First of all, you can already wire up Lazy<T> instances manually like this:
container = new Container(x =>
{
x.Scan(y =>
{
y.TheCallingAssembly();
y.WithDefaultConventions();
});
x.For<Lazy<IFoo>>().Use(y => new Lazy<IFoo>(y.GetInstance<Foo>));
x.For<Lazy<IBar>>().Use(y => new Lazy<IBar>(y.GetInstance<Bar>));
x.For<Lazy<IBaz>>().Use(y => new Lazy<IBaz>(y.GetInstance<Baz>));
});
This works just fine, but you have to register each and every type individually. It would be nicer if you could take advantage of a more convention-based approach. Ideally, the following syntax would be nice.
x.For(typeof(Lazy<>)).Use(typeof(Lazy<>));
This syntax actually works... somewhat. Unfortunately, at runtime, StructureMap will attempt to find the "greediest" constructor for Lazy<T> and settle on public Lazy(Func<T> valueFactory, bool isThreadSafe). Since we didn't tell it what to do with the boolean isThreadSafe parameter, it will throw an exception when it tries to resolve `Lazy'.
The documentation for Lazy states that the "thread safety mode" of the default Lazy(Func<T> valueFactory) constructor is LazyThreadSafetyMode.ExecutionAndPublication, which just so happens to be what you get by passing true into the isThreadSafe parameter of the constructor above. So, if we could just tell StructureMap to pass true for isThreadSafe, we would get the same behavior as if we called the constructor we actually wanted to use in the first place (e.g. Lazy(Func<T> valueFactory)).
Simply registering x.For(typeof(bool)).Use(y => true) would be very reckless and dangerous since we would be telling StructureMap to go ahead and use the value true for any boolean anywhere. Instead, we need to tell StructureMap what value to use for just this one boolean parameter, which we can do like this.
x.For(typeof(Lazy<>)).Use(typeof(Lazy<>))
.CtorDependency<bool>("isThreadSafe").Is(true);
StructureMap now knows to use the value of "true" for the isThreadSafe parameter when resolving Lazy<T>. We can now use Lazy<T> in constructor parameters, and get the behavior I believe you were looking for.
You can read about the Lazy class in more detail here.
Yes, it does. The latest version of StructureMap (2.6.x) is compiled against .NET Framework 3.5, and so does not have access to the Lazy<T> type introduced in .NET 4. However, it does support the same functionality - "not creating the object which is injected until it is used". Instead of depending on a Lazy<T>, you depend on a Func<T>. No special container registration is required.
I've included a sample program that creates the following output:
Created Consumer
Consuming
Created Helper
Helping
Sample.cs:
class Program
{
static void Main(string[] args)
{
var container = new Container(x =>
{
x.For<IConsumer>().Use<Consumer>();
x.For<IHelper>().Use<Helper>();
});
var consumer = container.GetInstance<IConsumer>();
consumer.Consume();
}
}
public class Consumer : IConsumer
{
private readonly Func<IHelper> _helper;
public Consumer(Func<IHelper> helper)
{
_helper = helper;
Console.WriteLine("Created Consumer");
}
public void Consume()
{
Console.WriteLine("Consuming");
_helper().Help();
}
}
public interface IConsumer
{
void Consume();
}
public interface IHelper
{
void Help();
}
public class Helper : IHelper
{
public Helper()
{
Console.WriteLine("Created Helper");
}
public void Help()
{
Console.WriteLine("Helping");
}
}
Related
I'm trying to use the AutoMapper for model-viewmodel mapping and wanted to have the mapping configuration executed once in the static constructor of the type. The static constructor of a type is not invoked when Mapper.Map (AutoMapper) is invoked with that type.
My understanding is that the Mapper.Map would try to access the type, its members through reflection and on the first attempt of the usage the static constructor would be called. This is something basic but challenges my understanding. The code snippet is provided.
class SampleViewModel
{
static SampleViewModel()
{
Mapper.Initialize(cfg => cfg.CreateMap<Sample, SampleViewModel>().ReverseMap());
}
public SampleViewModel()
{
}
public int PropertyA { get; set; }
public int PropertyB { get; set; }
}
Sample s = new Sample { PropertyA = 10, PropertyB = 20 };
var obj = Mapper.Map<SampleViewModel>(s); // fails
Isn't the static constructor called (if provided) when the type and members are accessed through reflection for the first time?
You're not accessing any members of SampleViewModel - it's not enough to just reference the type itself.
Mapper.Map only accesses its own internal "dictionary" of mappings - before it could ever get to a point where it deals with a SampleViewModel, it fails. The static constructor never runs, so it cannot add "itself" into the Mapper.
Now, if this didn't involve reflection, you would be right that the static constructor would be called - simply because it would happen during the compilation of the method containing the access, e.g.:
var obj = Mapper.Map<SampleViewModel>(s);
Console.WriteLine(obj.SomeField);
In this case, since the method is referencing a field on SampleViewModel, the static constructor for SampleViewModel will be invoked during JIT compilation of the containing method, and as such, the Mapper.Map<SampleViewModel>(s) line will execute correctly, since the mapping is now present. Needless to say this is not the proper solution to your problem. It would just make the code absolutely horrible to maintain :)
DISCLAIMER: Even though this might fix the problem right now, it depends on a non-contractual behaviour in the current implementation of MS.NET on Windows. The contract specifies that the type initializer is invoked before any access to a member of the type, but that still means that a valid implementation of CIL might only call the type initializer after Mapper.Map, as long as it happens before obj.SomeField - and even then, it might be that obj.SomeField gets optimized away if the compiler can ensure it is safe to do so. The only real way to enforce the call of the type initializer is to call RuntimeHelpers.RunClassConstructor, but by that point, you could just as well add a static Init method or something.
The real problem is that you shouldn't really initialize stuff like this in a static constructor in the first place. Mappings should be set in some kind of deterministic initialization process, say, an explicitly invoked InitMappings method. Otherwise you're opening yourself to a huge can of Heisenbugs, not to mention subtle changes in the CLR breaking your whole application for no apparent reason.
Static constructors just aren't meant for "registration", just the initialization of the type itself - anything else is an abuse, and will cause you (or the .NET compatibility team) trouble.
Static constructors run at an implementation-defined time just before the first instance of that class is created, or before any static member of that type is accessed. See When is a static constructor called in C#?.
The mapper tries to find a mapping before doing its work of instantiating the class to map into, and thus can't find a mapping, because the class was never instantiated before that moment.
Just move your mapping initialization code into a AutoMapperBootstrap.cs file or something, and call that in your application initialization.
".. The static constructor of a type is not invoked when Mapper.Map (AutoMapper) is invoked with that type..."
I tested your scenario and observed that the static constructor is indeed being called before the first instance of the object is created.
C# Programming Guide: Static Constructors
I also went ahead and modified the sample code by adding a GetMapper function which returns an IMapper. This might seem like an overkill for day-to-day simple mapping, but if we need an object to give us its mapper, perhaps we can get it from a static method.
One can easily move the responsibility of creating the Mapper object to a factory or a DI container which, for the sake of simplicity, I did not include here.
Worth noting that in this example, the static fields are initialized before the static constructor which is called right after the static read-only fields are initialized.
Uses AutoMapper v12.0 and .Net Core 3.1.
public class SimpleObjectToMap
{
private static readonly MapperConfiguration _simpleObjMapperConfig = new MapperConfiguration(
config => config.CreateMap<SimpleObjectToMap, ObjectToBeMappedTo>());
private static readonly IMapper _mapper = new Mapper(_simpleObjMapperConfig);
private int _propertyA;
public int PropertyA
{
get
{
Console.WriteLine("ObjectToMap.PropertyA.Get");
return _propertyA;
}
set { _propertyA = value; }
}
static SimpleObjectToMap()
{
Console.WriteLine("*** ObjectToMap static ctor called ***");
}
public static IMapper GetMapper()
{
return _mapper;
}
}
public class ObjectToBeMappedTo
{
static ObjectToBeMappedTo()
{
Console.WriteLine("*** ObjectToBeMappedTo static ctor called ***");
}
private int _propertyA;
public int PropertyA
{
get { return _propertyA; }
set
{
Console.WriteLine("ObjectToBeMappedTo.PropertyA.Set");
_propertyA = value;
}
}
}
public class TestObjectMappingWithStaticCtor
{
public void TestWithStaticCtor()
{
SimpleObjectToMap objToMap = new SimpleObjectToMap { PropertyA = 27 };
var mappedObject = SimpleObjectToMap.GetMapper().Map<ObjectToBeMappedTo>(objToMap);
}
}
I have an abstract factory which creates some service represented by IService interface. In the factory I have two Create methods, because at one of them I allow the consumer to pass an existing IServiceLogger instance to be used by the constructed service tree.
public interface IMyServiceFactory {
IMyService Create(IServiceLogger loggerInstance);
IMyService Create();
}
Because an IServiceLogger should be shared among the service tree, I use the InCallScope when binding it to a concrete implementation.
How can I implement this scenario with Ninject? I've tried the following approaches.
1. Manually create a factory implementation
internal class MyServiceFactory : IMyServiceFactory {
private IResolutionRoot _kernel;
public MyServiceFactory
public IMyService Create(IServiceLogger loggerInstance) {
// what should go here? how can I pass the existing instance to Ninject Get method and make Ninject to use it for the whole resolution tree, just as it were created by Ninject and used as InCallScope?
}
// this one is trivial...
pulbic IMyService Create() {
return _kernel.Get<IMyService>();
}
}
UPDATE
Actually I've found a messy and not too safe way for this. I can get the current bindings via GetBindings, then Rebind IServiceLogger ToConstant, then Get the IMyService instance, and finally restore the original bindings with AddBinding. I don't like it, it feels stinky and what's worse, it's not thread-safe, because another thread can request for a IMyService in the middle of this code and hence use the local temporary binding.
2. Use Ninject.Extensions.Factory
Just use the ToFactory binding, but that's not working, because it just tries to use the parameter as a simple constructor argument (if applicable), and not as an object for the whole resolution tree.
I would give more control to the Kernel of Ninject and do not create a class for the factory at all.
And use Func binding in Ninject like this:
Bind<Func<IMyService>>().ToMethod(s => CreateService);
By binding of the ILoggerService or not binding this you can controll centrally whether you have logger or not in your service.(try by just comment it out)
Here implementation of the Bootstrapper:
public class Bootstrapper
{
private IKernel _kernel = new StandardKernel();
public Bootstrapper()
{
_kernel.Bind<MyStuff>().ToSelf();
_kernel.Bind<IServiceLogger>().To<ServiceLogger>();
_kernel.Bind<IMyService>().To<MyService>();
_kernel.Bind<Func<IMyService>>().ToMethod(s => CreateService);
}
public IKernel Kernel
{
get
{
return _kernel;
}
set
{
_kernel = value;
}
}
private IMyService CreateService()
{
if(_kernel.GetBindings(typeof(IServiceLogger)).Any())
{
return _kernel.Get<IMyService>(new ConstructorArgument("logger", _kernel.Get<IServiceLogger>()));
}
return _kernel.Get<IMyService>();
}
}
Implementation of consumer class for the factory:
internal class MyStuff
{
private readonly Func<IMyService> _myServiceFactory;
public MyStuff(Func<IMyService> myServiceFactory)
{
_myServiceFactory = myServiceFactory;
_myServiceFactory.Invoke();
}
}
Simple implementation of MyService:
internal class MyService
:IMyService
{
public MyService()
{
Console.WriteLine("with no parameters");
}
public MyService(IServiceLogger logger)
{
Console.WriteLine("with logger parameters");
}
}
Simple ServiceLogger:
internal class ServiceLogger
:IServiceLogger
{
public ServiceLogger()
{
}
}
internal interface IServiceLogger
{
}
IMPORTANT UPDATE
While my original answer gave me a working solution, by an accidental InteliSense navigation I've just found that there is a built-in tool for exactly this issue. I just have to use the built-in TypeMatchingArgumentInheritanceInstanceProvider which does this, and even more, because there are no more needs for naming conventions due to the parameter type matching.
It would be good to have a more detailed documentation about these options, or maybe it's just me who can't find it currently.
ORIGINAL ANSWER
I tried a few ways, and ended up with a slightly different, kind of a convention based approach utilizing Ninject's context parameter inheritance.
The convention is used at constructor argument naming through the dependency tree. For example whenever an IServiceLogger instance is injected to a service class, the argument should be called serviceLogger.
With the above convention in mind, I've tested the following approach. Firstly I've implemented a custom instance provider for the factory extension. This custom provider overrides the mechanism for creating constructor parameters for the context to let the developer specify several named arguments which should be set as inherited. This way all the parameters with the specified names will inherit through the whole request graph during the get operation.
public class ParameterInheritingInstanceProvider : StandardInstanceProvider
{
private readonly List<string> _parametersToInherit = new List<string>();
public ParameterInheritingInstanceProvider(params string[] parametersToInherit)
{
_parametersToInherit.AddRange(parametersToInherit);
}
protected override IConstructorArgument[] GetConstructorArguments(MethodInfo methodInfo, object[] arguments)
{
var parameters = methodInfo.GetParameters();
var constructorArgumentArray = new IConstructorArgument[parameters.Length];
for (var i = 0; i < parameters.Length; ++i)
constructorArgumentArray[i] = new ConstructorArgument(parameters[i].Name, arguments[i], _parametersToInherit.Contains(parameters[i].Name));
return constructorArgumentArray;
}
}
Then after at binding configuration I just threw it in with the corresponding parameter name.
kernel.Bind<IMyServiceFactory>().ToFactory(() => new ParameterInheritingInstanceProvider("serviceLogger"));
Finally I reviewed parameter naming, and for exampled changed loggerInstance in the factory interface to serviceLogger to match the convention.
This solution is still not the nicest one as it has several limitations.
It is error prone. One can make bugs which are hard to track by not keeping the naming convention, because currently it silently fails if the convention does not match. This could be improved probably, I'll think about it later.
It handles only constructor injection, however this should not be a big issue as that's the suggested technique. For example I almost never do other kind of injections.
I realise this was asked a long time ago but I was looking to do the same sort of thing myself and finally worked out that you can use the IParameter array passed to the Get() method to specify a ContructorArgument to use only for the current Get() call. This allowed me to use a specific constructor value when creating a Hangfire Job allowing the Hangfire job to use a different database connection on each invocation if required.
EnvironmentName forcedEnv = new EnvironmentName() { Name = dbName };
// For this instantiation, set the 'envName' parameter to be the one we've specified for this job
var instance = ResolutionExtensions.Get((IResolutionRoot) _kernel, jobType,
new IParameter[] {new ConstructorArgument("envName", forcedEnv, true)});
return instance;
By setting the shouldInherit value to true you can ensure the value gets passed down the resolution chain. So it get's passed to any objects in the dependency tree that use that argument (but only for this particular instantiation).
I'm trying to find out the best (nicest) way to pass an argument to the constructor of a child object of an auto-resolved parameter.
Why?
Because I have a program that does almost all its computations against the same "production" database (defined in the config file, so no argument required). But now needs to run some work on a 'copy' of this database. Therefore requiring a different connection string.
The connection string can be supplied on the constructor, and is not known at compile time. The problem is that I can't (or do not know how to) simply access this constructor because it is buried deep inside the generated items.
Consider the following (simplified) code snippet:
public class Example
{
protected readonly IGenerateSomethingFactory Factory;
public Example(IGenerateSomethingFactory factory)
{
Factory = factory;
}
public Task DoSomething(string ConnectionString, string a, string b)
{
//needs to run somehow using the supplied connection string ...
return Task.Run(() => Factory.CreateSomething().Execute(a, b));
//= Task.Run(() => new Something(new UnitOfWork(new DataContext(ConnectionString))).Execute(a, b));
}
public Task DoSomething(string a, string b)
{
//needs to run using the default connection string (defined in config)
return Task.Run(() => Factory.CreateSomething().Execute(a, b));
}
}
The problem lays in the first DoSomething(...) function.
Note: The Castle Windsor installer looks like this:
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IGenerateSomethingFactory>().AsFactory());
container.Register(Classes.FromThisAssembly().InNamespace("x").WithService.FirstInterface());
}
}
I'm looking for a solution that:
is thread safe
is easy to understand (if not easy to think of)
allows refactoring (so no named arguments like "conString" )
does not require changes to other non-relevant code
(i.e. setting properties public ... )
does not call new or container.Resolve<>()
I have been looking into selection handlers, but have not really found what I was looking for.
PS: I'm using Castle Windsor 3.3.0
PPS: this is my first question, I can provide more example code but thought I should restrict to the minimum ... so let me know if I need to do so.
From your example, it looks like all you need to do is add a parameter to your typed factory's CreateSomething method:
public interface IGenerateSomethingFactory
{
ISomething CreateSomething(string connectionString);
}
Then add that as a parameter to your ISomething implementation:
public class Something : ISomething
{
public Something(string connectionString)
{
}
}
Note how the parameter to CreateSomething and Something's constructor are named the same. This is the default behavior for parameter matching.
Now, you just pass the value along in your call to DoSomething:
public Task DoSomething(string ConnectionString, string a, string b)
{
return Task.Run(() => Factory.CreateSomething(ConnectionString).Execute(a, b));
}
Based on your added code, what you're trying to do isn't immediately possible. In a nutshell, you have this resolution hierarchy:
IGenerateSomethingFactory.Create(string constring)
Something.ctor(IUnitOfWork uow)
UnitOfWork.ctor(IDataContext context)
DataContext.ctor(string constring)
You're trying to pass the argument from the call to Create down to the constructor of DataContext.
For a way to enable this, see my answer (to my own question). I do this by changing the default behavior of Windsor to pass the factory creation parameters down to all objects being resolved instead of just the first.
First, create this class to change this behavior:
public class DefaultDependencyResolverInheritContext : DefaultDependencyResolver
{
protected override CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
{
if (parameterType.ContainsGenericParameters)
{
return current;
}
return new CreationContext(parameterType, current, true);
}
}
Then supply it when creating the container:
var kernel = new DefaultKernel(
new DefaultDependencyResolverInheritContext(),
new NotSupportedProxyFactory());
var container = new WindsorContainer(kernel, new DefaultComponentInstaller());
That's it. Now when you call your Create method, the constring parameter will be passed down to all objects being registered. Obviously this can cause problems if you have parameters that are the same name! In your case, this is an "ambient" parameter (my term) so you could just document this behavior/parameter name and call it a day.
I'd love to see another approach to this, save for creating factories for all the intermediate types.
So we have ran into what seems like a very common issue with StructureMap and IoC containers in general I assume. Bidirectiona/Circuar dependencies.
Given the following code, it is currently causing a circular dependency since we have it 'autowiring' properties.
public class ServiceA:IServiceA
{
public IServiceB ServiceBDependency {get;set;}
}
public class ServiceB:IServiceB
{
public IServiceA ServiceADependency {get;set;}
}
I see the 'dependency' of each of these on eachother, however, I feel that as a property, they are not true dependencies which is what separates them from using constructor injection.
It seems that there should be a way for these services to be resolved...and then have the properties injected after the objects have been created?
I know of various ways to get around this, including the true clean way of rearchitecting my services, but i am curious as to what options I have with instantiation and service registration with StructureMap. It seems like a fairly common issue that would need a solution.
I'd like to show you my approach. I am using only the setter injection. And we often have many objcets referencing each other, in our web app. E.g. IUserFacade requires IUserState on user creation while IUserState requires IUserFacade on userState deletion (to check for constraint).
e.g.:
public interface IUserFacade
{
... // User facade Add, Update, Delete
IUserStateFacade { set; }
}
public interface IUserStateFacade
{
...
IUserFacade { set; }
}
In reality, we have many objects with cross references, and even more complicated. And it would really be very costy, if all the referenced objects should be created each time, even if not used during the request. We need the "lazy", the proxy objects to be placed in the setters.
The way how to do it, is a mix of the: 1) StructureMap (IoC top) and 2) Castle (proxying top) libraries. Below I will show some snippets of objects needed for this solution. More could be found inside open source project Catharsis
Wrapper. This object would be injected into each Property by SM (StructureMap) instead of real implementor. It is the sleeping implementation. It is waiting for a first call. If it will never happen (IUserFacade is deleting user, no need to access referenced IUserStateFacade during such request) this wrapper will sleep for ever (request). Once touched, SM will create the real object and Wrapper will pass all calls to that.
The Castle interceptor:
public class Wrapper : IInterceptor
{
object _lazy;
protected readonly Type Type;
public Wrapper(Type type)
{
Type = type;
}
public void Intercept(IInvocation invocation)
{
if (_lazy.IsNull()) // lazily instantiate the instance
{
_lazy = ObjectFactory.GetInstance(Type);
}
try
{
var method = invocation.Method;
if (method.ContainsGenericParameters)
{
method = method.MakeGenericMethod(invocation.GenericArguments);
}
invocation.ReturnValue = method.Invoke(_lazy, invocation.Arguments);
}
catch (TargetInvocationException ex)
{
// PublishingManager.Publish(.... // publish exception
throw;
}
}
}
ProxyInstance. Now, we need an object, clear and understandable to SM. That object will be mapped to all interfaces (IUserFacade...) Instead of returning implementation of the UserFacade.
We can also use our custom AOP filters here.
This ProxyInstance will be provided with the real implementor type, and building up the Wrapper.
The StructureMap Instance:
public class ProxyInstance : Instance
{
protected readonly ProxyGenerator Factory = new ProxyGenerator();
protected readonly Type ConcreteType;
public ProxyInstance(Type type)
{
ConcreteType = type; // the type for our Wrapper, the real implementation
}
protected override object build(Type pluginType, BuildSession session)
{
var aopFilters =
// my custom way how to inject more AOP filters
AopFilterManager.GetFilters()
// the core for us, one of the interceptors is our Wrapper
.Union(new[] { new Wrapper(ConcreteType) })
.ToArray();
// Castle will emit a proxy for us, but the Wrapper will do the job
var proxy = Factory
.CreateClassProxy(ConcreteType, AopFilterManager.AopOptions, aopFilters);
return proxy;
}
And now just use some standard way how to map it in the SM (I am using custom ProxyConvention but it is out of the scope here). Let's use simplified explicit mapping:
registry
.For<IUserFacade>()
.HybridHttpOrThreadLocalScoped()
.Use(new ProxyInstance(typeof(UserFacade)));
...
Also, each of our objects created via SM, implements IService. So, the default setter injection could be set like this:
registry.SetAllProperties
(
set => set.TypeMatches
(
type => type
.GetInterfaces()
.Any(i => i.IsEquivalentTo(typeof(IService)))
)
);
From that moment, when we need to work with a IUserFacade (the direct ObjectFactory call, or accessed via Wrapper), we recieve the real implementor. All its properties (setter injection) will be pre-populated with our ProxyInstance / Wrapper.
If any of these properties is accessed, e.g. IUserStateFacade the same (discribed above for IUserFacade) will happen again.
Because the Lifecycle is Thread or Request based, we have only one implementor in runtime/web request
Because we do inject the Wrappers while using setter injection, no issues with circular infinite loops. Only the first level is injected each time
The following code passes as-is with Castle.Windsor 2.5.3 but fails after upgrading to 3.1.0
The exception is an InvalidProxyConstructorArgumentsException and it states "Can not instantiate proxy of class: Test. Could not find a parameterless constructor."
static void Main(string[] args)
{
var container = new WindsorContainer();
container.Register(Component.For<Interceptor>(),
Component.For<Test>().UsingFactoryMethod(() => new Test(""))
.Interceptors<Interceptor>());
var test = container.Resolve<Test>(); //THROWS IN 3.1.0
}
}
public class Test
{
public readonly string S;
public Test(string s)
{
S = s;
}
}
public class Interceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
invocation.Proceed();
}
}
In my real code Test is a MongoDatabase that is being constructed using a factory method and injected into a Repository.
In my real code I'm also using an inheritor to an AbstractFacility to register the interceptor. This way I don't have to register the interceptor for each component. Both forms of interceptor usage seem to work/fail (in 2.5.3/3.1.0) the same way on later resolution. For reference here is a shortened version of the facility:
public class Facility : AbstractFacility
{
protected override void Init() { Kernel.ComponentRegistered += KernelComponentRegistered; }
static void KernelComponentRegistered(string key, IHandler handler)
{
if (typeof(IInterceptor).IsAssignableFrom(handler.ComponentModel.Implementation)) return;
handler.ComponentModel.Interceptors.AddIfNotInCollection(InterceptorReference.ForKey("SomeInterceptor"));
}
}
I looked at the Castle.Windsor source code and the throwing code is expecting to wrap a proxy around the class it is given which is why it's looking for a parameterless constructor. However in 2.5.3 I think the proxy generation code never got executed and the container resolves (correctly in my mind) to a non-proxy version of Test/MongoDatabase
So two questions I guess:
1) What's changed?
2) How do I keep my interceptor registration without generating a proxy for the object resolved by the factory method? Or I guess how does a proxy get generated using a factory method for the component...
In 2.5.3, Windsor appears to be silently failing to apply the interceptor. In 3.1.0, Windsor throws an exception when it can't apply the interceptor to the type that you've registered. Windsor uses their Dynamic Proxy library to support interceptors (AOP) by generating proxies of the instances that you ask for. So the problem in both versions is that the class you're giving it cannot be turned into a dynamic proxy because it does not have a no-arg constructor. I would consider the behavior in 3.1.0 to be more correct since if you were expecting the interceptor to be applied, it would be a lot more difficult to figure out what the problem is.
If you want to maintain the behavior from 2.5.3 where it fails silently, just add a check to see if the type can be proxied before you register the interceptor in your facility. There's probably a better of doing it, but here's what I came up with:
try
{
ProxyGenerator generator = new ProxyGenerator();
generator.CreateClassProxy(handler.ComponentModel.Implementation);
handler.ComponentModel.Interceptors.AddIfNotInCollection(InterceptorReference.ForType<MyInterceptor>());
}
catch {}
This is terrible code in so many ways, but it will recreate the behavior that you're used to. Just be careful that it doesn't bite you down the road when there's a different class that you actually want the interceptor on and are struggling to figure out why it's not being called.
Stefan put me on the right track. The fact that the interceptor wasn't being assigned to Test in 2.5.3 is a bug/feature disguised as a bug. The 3.1.0 behaviour is more correct, and forces you to be explicit about what you want an interceptor on. Since my actual code involved a Facility, here is the solution that fixes the issue:
public class Facility : AbstractFacility
{
protected override void Init() { Kernel.ComponentRegistered += KernelComponentRegistered; }
static readonly List<Type> TypesNotToIntercept = new List<Type>
{
typeof(IInterceptor), //Don't intercept Interceptors
typeof(MulticastDelegate), //Func<> and the like
typeof(LateBoundComponent), //Resolved with a factory, such as MongoDatabase
};
static void KernelComponentRegistered(string key, IHandler handler)
{
if (TypesNotToIntercept.Any(type => type.IsAssignableFrom(implementation));
return;
handler.ComponentModel.Interceptors.AddIfNotInCollection(InterceptorReference.ForKey("SomeInterceptor"));
}
}