Skip to content

Instantly share code, notes, and snippets.

@cwe1ss
Last active November 25, 2021 10:57
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save cwe1ss/050a531e2711f5b62ab0 to your computer and use it in GitHub Desktop.
Save cwe1ss/050a531e2711f5b62ab0 to your computer and use it in GitHub Desktop.
Castle.Facilities.AspNetCoreIntegration
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Configure regular ASP.NET Core services
services.AddMvc();
// ...
// Send configuration to Castle Windsor
Container.Populate(services);
Container.BeginScope();
return Container.Resolve<IServiceProvider>();
}
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using Castle.Windsor;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
namespace Castle.Facilities.AspNetCoreIntegration
{
public static class WindsorRegistration
{
public static void Populate(this IWindsorContainer container,
IEnumerable<Microsoft.Extensions.DependencyInjection.ServiceDescriptor> descriptors)
{
container.Register(Component.For<IWindsorContainer>().Instance(container).OnlyNewServices());
container.Register(Component.For<IServiceProvider>().ImplementedBy<WindsorServiceProvider>());
container.Register(Component.For<IServiceScopeFactory>().ImplementedBy<WindsorServiceScopeFactory>());
// ASP.NET Core uses IEnumerable<T> to resolve a list of types.
// Since some of these types are optional, Windsor must also return empty collections.
container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel, allowEmptyCollections: true));
Register(container, descriptors);
}
private static void Register(IWindsorContainer container,
IEnumerable<Microsoft.Extensions.DependencyInjection.ServiceDescriptor> descriptors)
{
foreach (var descriptor in descriptors)
{
if (descriptor.ImplementationType != null)
{
container.Register(
Component.For(descriptor.ServiceType)
.ImplementedBy(descriptor.ImplementationType)
.ConfigureLifecycle(descriptor.Lifetime));
}
else if (descriptor.ImplementationFactory != null)
{
var service1 = descriptor;
container.Register(
Component.For(descriptor.ServiceType)
.UsingFactoryMethod(c =>
{
var serviceProvider = container.Resolve<IServiceProvider>();
return service1.ImplementationFactory(serviceProvider);
})
.ConfigureLifecycle(descriptor.Lifetime));
}
else
{
container.Register(
Component.For(descriptor.ServiceType)
.Named(descriptor.ServiceType.FullName)
.Instance(descriptor.ImplementationInstance)
.ConfigureLifecycle(descriptor.Lifetime));
}
}
}
private static ComponentRegistration<object> ConfigureLifecycle(
this ComponentRegistration<object> registrationBuilder,
ServiceLifetime serviceLifetime)
{
switch (serviceLifetime)
{
case ServiceLifetime.Singleton:
registrationBuilder.LifestyleSingleton();
break;
case ServiceLifetime.Scoped:
registrationBuilder.LifestyleScoped();
break;
case ServiceLifetime.Transient:
registrationBuilder.LifestyleTransient();
break;
}
return registrationBuilder;
}
}
}
using Castle.Windsor;
using System;
using System.Collections.Generic;
using System.Reflection;
namespace Castle.Facilities.AspNetCoreIntegration
{
public class WindsorServiceProvider : IServiceProvider
{
private readonly IWindsorContainer _container;
public WindsorServiceProvider(IWindsorContainer container)
{
_container = container;
}
public object GetService(Type serviceType)
{
// ASP.NET uses GetService<IEnumerable<TDesiredType>>() to get a collection.
// This must be resolved to IWindsorContainer.ResolveAll();
var typeInfo = serviceType.GetTypeInfo();
if (typeInfo.IsGenericType && serviceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))
{
var itemType = typeInfo.GenericTypeArguments[0];
return _container.ResolveAll(itemType);
}
// Microsoft.Extensions.DependencyInjection is built to handle optional registrations.
// However Castle Windsor throws ComponentNotFoundException when a type wasn't registered.
// For this reason we have to manually check if the type exists in Windsor.
if (_container.Kernel.HasComponent(serviceType))
{
return _container.Resolve(serviceType);
}
return null;
}
}
}
using Castle.MicroKernel.Lifestyle;
using Castle.Windsor;
using Microsoft.Extensions.DependencyInjection;
using System;
namespace Castle.Facilities.AspNetCoreIntegration
{
public 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 => _serviceProvider;
public void Dispose()
{
_scope.Dispose();
}
}
}
using Castle.Windsor;
using Microsoft.Extensions.DependencyInjection;
namespace Castle.Facilities.AspNetCoreIntegration
{
public class WindsorServiceScopeFactory : IServiceScopeFactory
{
private readonly IWindsorContainer _container;
public WindsorServiceScopeFactory(IWindsorContainer container)
{
_container = container;
}
public IServiceScope CreateScope()
{
return new WindsorServiceScope(_container);
}
}
}
@cwe1ss
Copy link
Author

cwe1ss commented Feb 6, 2016

This code is based on the following links:

I adjusted the code for RC1 and fixed some issues:

  • Components were added with .OnlyNewServices() which resulted in services that are supposed to exist multiple times not being added
  • GetService<IEnumerable>() was not resolved properly. I had to add special handling for IEnumerable<>
  • ASP.NET Core doesn't expect GetService() to result in an exception if the component wasn't registered. (they use it for optional dependencies). For this reason, I added a check to Kernel.HasComponent()

I'm not sure why the call to BeginScope() in Startup.cs is necessary - if it's missing, the first request fails. Seems like ASP.NET doesn't start the scope for the first request or some Scoped service is requested before it does.

Copy link

ghost commented Feb 24, 2016

great

@bluetianx
Copy link

ComponentRegistrationException:
I copy your code in my asp.net core

but An error occurred while starting the application.

ComponentRegistrationException: Component Microsoft.Extensions.Options.OptionsManager`1 could not be registered. There is already a component with that name. Did you want to modify the existing component instead? If not, make sure you specify a unique name.
Castle.MicroKernel.SubSystems.Naming.DefaultNamingSubSystem.Register(IHandler handler)

ComponentRegistrationException: Component Microsoft.Extensions.Options.OptionsManager`1 could not be registered. There is already a component with that name. Did you want to modify the existing component instead? If not, make sure you specify a unique name.
Castle.MicroKernel.SubSystems.Naming.DefaultNamingSubSystem.Register(IHandler handler)
Castle.MicroKernel.DefaultKernel.AddCustomComponent(ComponentModel model)
Castle.MicroKernel.Registration.ComponentRegistration.Castle.MicroKernel.Registration.IRegistration.Register(IKernelInternal kernel)
Castle.MicroKernel.DefaultKernel.Register(IRegistration[] registrations)
Castle.Windsor.WindsorContainer.Register(IRegistration[] registrations)
BlueBlog.Utility.WindsorRegistration.Register(IWindsorContainer container, IEnumerable descriptors) in WindsorRegistration.cs
+
container.Register(
BlueBlog.Utility.WindsorRegistration.Populate(IocContainer container, IEnumerable descriptors) in WindsorRegistration.cs
+
Register(container.Container, descriptors);
BlueBlog.Startup.ConfigureServices(IServiceCollection services) in Startup.cs
+
container.Populate(services);
System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()

@bluetianx
Copy link

How should I solve this error ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment