Background:
I've used Castle Windsor with Installers and Facilities according to the Castle Windsor tutorial with earlier versions of MVC (pre-6) and WebAPI.
ASP.NET (5) Core has included some Dependency Injection support but I still haven't figured out exactly how to wire it up, and the few samples I have found look a lot different than how I've used it before (with the installers/facilities). Most examples predate ASP.NET (5) cores recent release and some seem to have outdated information.
It seems to have changed quite radically from the previous versions composition root setup, and not even Microsoft.Framework.DependencyInjection.ServiceProvider
can resolve all of the dependencies when I set it as the Castle Windsor DI fallback. I'm still digging into the details but there isn't much up to date information.
My attempt to use Castle Windsor for DI
I've found an adapter like this: Github Castle.Windsor DI container.
Startup.cs
private static IWindsorContainer container;
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerfactory)
{
container = new WindsorContainer();
app.UseServices(services =>
{
// ADDED app.ApplicationServices FOR FALLBACK DI
container.Populate(services, app.ApplicationServices);
container.BeginScope();
return container.Resolve<IServiceProvider>();
});
// ... default stuff
WindsorRegistration.cs
I added a few lines to add a Castle Windsor ILazyComponentLoader
fallback.
using Castle.MicroKernel.Lifestyle;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using Castle.Windsor;
using Microsoft.Framework.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Notes.Infrastructure
{
/// <summary>
/// An adapted current autofac code to work with Castle.Windsor container.
/// https://github.com/aspnet/Home/issues/263
/// </summary>
public static class WindsorRegistration
{
public static void Populate(
this IWindsorContainer container,
IEnumerable<IServiceDescriptor> descriptors,
IServiceProvider fallbackProvider // ADDED FOR FALLBACK DI
)
{
// ADDED FOR FALLBACK DI
// http://davidzych.com/2014/08/27/building-the-castle-windsor-dependency-injection-populator-for-asp-net-vnext/
// Trying to add a fallback if Castle Windsor doesn't find the .NET stuff
var fallbackComponentLoader = new FallbackLazyComponentLoader(fallbackProvider);
container.Register(Component.For<ILazyComponentLoader>().Instance(fallbackComponentLoader));
// Rest as usual from the Github link
container.Register(Component.For<IWindsorContainer>().Instance(container));
container.Register(Component.For<IServiceProvider>().ImplementedBy<WindsorServiceProvider>());
container.Register(Component.For<IServiceScopeFactory>().ImplementedBy<WindsorServiceScopeFactory>());
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel));
Register(container, descriptors);
}
private static void Register(
IWindsorContainer container,
IEnumerable<IServiceDescriptor> descriptors)
{
foreach (var descriptor in descriptors)
{
if (descriptor.ImplementationType != null)
{
// Test if the an open generic type is being registered
var serviceTypeInfo = descriptor.ServiceType.GetTypeInfo();
if (serviceTypeInfo.IsGenericTypeDefinition)
{
container.Register(Component.For(descriptor.ServiceType)
.ImplementedBy(descriptor.ImplementationType)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
else
{
container.Register(Component.For(descriptor.ServiceType)
.ImplementedBy(descriptor.ImplementationType)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
}
else if (descriptor.ImplementationFactory != null)
{
var service1 = descriptor;
container.Register(Component.For(descriptor.ServiceType)
.UsingFactoryMethod<object>(c =>
{
var builderProvider = container.Resolve<IServiceProvider>();
return
service1.ImplementationFactory(builderProvider);
})
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
else
{
container.Register(Component.For(descriptor.ServiceType)
.Instance(descriptor.ImplementationInstance)
.ConfigureLifecycle(descriptor.Lifecycle)
.OnlyNewServices());
}
}
}
private static ComponentRegistration<object> ConfigureLifecycle(
this ComponentRegistration<object> registrationBuilder,
LifecycleKind lifecycleKind)
{
switch (lifecycleKind)
{
case LifecycleKind.Singleton:
registrationBuilder.LifestyleSingleton();
break;
case LifecycleKind.Scoped:
registrationBuilder.LifestyleScoped();
break;
case LifecycleKind.Transient:
registrationBuilder.LifestyleTransient();
break;
}
return registrationBuilder;
}
private class WindsorServiceProvider : IServiceProvider
{
private readonly IWindsorContainer _container;
public WindsorServiceProvider(IWindsorContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
return _container.Resolve(serviceType);
}
}
private class WindsorServiceScopeFactory : IServiceScopeFactory
{
private readonly IWindsorContainer _container;
public WindsorServiceScopeFactory(IWindsorContainer container)
{
_container = container;
}
public IServiceScope CreateScope()
{
return new WindsorServiceScope(_container);
}
}
private class WindsorServiceScope : IServiceScope
{
private readonly IServiceProvider _serviceProvider;
private readonly IDisposable _scope;
public WindsorServiceScope(IWindsorContainer container)
{
_scope = container.BeginScope();
_serviceProvider = container.Resolve<IServiceProvider>();
}
public IServiceProvider ServiceProvider
{
get { return _serviceProvider; }
}
public void Dispose()
{
_scope.Dispose();
}
}
}
}
First hiccup and resolution attempt
From that example I was getting:
An exception of type 'Castle.MicroKernel.ComponentNotFoundException' occurred in Castle.Windsor.dll but was not handled in user code Additional information: No component for supporting the service Microsoft.Framework.Runtime.IAssemblyLoaderEngine was found
It wasn't available looking in the debugger at the Castle Fallback - Microsoft.Framework.DependencyInjection.ServiceProvider
(table of services).
From http://davidzych.com/tag/castle-windsor/ I have tried to add a Fallback since Windsor couldn't resolve all of the ASP.NET dependencies.
FallbackLazyComponentLoader.cs
/// <summary>
/// https://github.com/davezych/DependencyInjection/blob/windsor/src/Microsoft.Framework.DependencyInjection.Windsor/FallbackLazyComponentLoader.cs
/// </summary>
public class FallbackLazyComponentLoader : ILazyComponentLoader
{
private IServiceProvider _fallbackProvider;
public FallbackLazyComponentLoader(IServiceProvider provider)
{
_fallbackProvider = provider;
}
public IRegistration Load(string name, Type service, IDictionary arguments)
{
var serviceFromFallback = _fallbackProvider.GetService(service);
if (serviceFromFallback != null)
{
return Component.For(service).Instance(serviceFromFallback);
}
return null;
}
}
It was seemingly necessary (to inject all the .NET dependencies)
I could comment out startup.cs app.UseBrowserLink(); to get rid of the IAssemblyLoaderEngine exception.
if (string.Equals(env.EnvironmentName, "Development", StringComparison.OrdinalIgnoreCase))
{
//app.UseBrowserLink(); //
Now I run into an exception:
An exception of type 'System.Reflection.TargetInvocationException' occurred in mscorlib.dll but was not handled in user code
Trying to get the service: {Name = "IUrlHelper" FullName = "Microsoft.AspNet.Mvc.IUrlHelper"}
public IRegistration Load(string name, Type service, IDictionary arguments)
{
var serviceFromFallback = _fallbackProvider.GetService(service);
How to move forward?
What is wrong with this attempt to wire up Castle Windsor DI into ASP.NET (5) Core?
IApplicationBuilder.UseServices()
which you're using in your sample code is no longer included in ASP.NET 5. It's been removed in one of the beta versions. @jason-li's answer provides an alternative. – Maccabean