Search code examples
c#castle-windsor

Can Castle Windsor register types from dynamic assemblies?


I have a dynamically generated assembly that has been created using Reflection.Emit. I am then trying to register controller types from that assembly using Windsor in the following way:

WindsorContainer.Register(Classes.FromAssembly(myDynamicAssembly).BasedOn<ApiController>().LifestylePerWebRequest());

When I try to navigate to an endpoint specified in the one of these controllers I get the following error:

[NotSupportedException: The invoked member is not supported in a dynamic assembly.]
System.Reflection.Emit.InternalAssemblyBuilder.GetExportedTypes() +68
Castle.Core.Internal.ReflectionUtil.GetAvailableTypes(Assembly assembly, Boolean includeNonExported) +74
Castle.MicroKernel.Registration.FromAssemblyDescriptor.&lt;SelectedTypes&gt;b__0(Assembly a) +21
System.Linq.&lt;SelectManyIterator&gt;d__14`2.MoveNext() +267
Castle.MicroKernel.Registration.FromDescriptor.Castle.MicroKernel.Registration.IRegistration.Register(IKernelInternal kernel) +296
Castle.MicroKernel.DefaultKernel.Register(IRegistration[] registrations) +72
Castle.Windsor.WindsorContainer.Register(IRegistration[] registrations) +50

Is it just not possible to register anything in a dynamic assembly or is there some other issue that I'm missing?

Note that without Windsor (ie using the default controller activator service) the assembly/controllers/endpoints works correctly. I can possibly use Windsor's DynamicProxy functionality instead of the Reflection.Emit approach but I would like to exhaust all possibilities with this current approach before I tackle that somewhat daunting task!


Solution

  • Nope, you aren't missing anything. Currently this is not supported by Windsor.

    As the stack trace indicates, where you do Classes.FromAssembly(myDynamicAssembly) Windsor uses Assembly.GetExportedTypes to look for types to register and as the documentation states, this method isn't supported on dynamic assemblies.

    Windsor uses GetExportedTypes to not have to waste time looking at non-public classes, since it by default only allow public classes to be registered.

    You can however override it by adding . IncludeNonPublicTypes() which doesn't use Assembly.GetExportedTypes and will stop the exception from occurring. The side-effect of that is, that now Windsor will register any potential non-public classes meeting your specified criteria (BasedOn<ApiController>() so if you want to avoid that you will have to filter those out yourself.

    So for completeness, here's how your registration will look:

    container.Register(
       Classes.FromAssembly(myDynamicAssembly)
          .IncludeNonPublicTypes()
          .BasedOn<ApiController>()
          .LifestylePerWebRequest());
    

    I guess there is no good reason why Windsor shouldn't handle dynamic assemblies out of the box, so perhaps you'd like to open an issue for it and have a crack at pull requesting it?