Skip to content

Commit

Permalink
Merge pull request #540 from generik0/feature/535-Improve-IServicePro…
Browse files Browse the repository at this point in the history
…viderFactory-Implemenation

Change WindsorServiceProviderFactory to follow SOLID behaviour
  • Loading branch information
jonorossi authored Aug 31, 2020
2 parents 4953b55 + 907308b commit 662efa6
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
//Microsoft namespace is intentional - suggested by Microsoft
namespace Microsoft.Extensions.Hosting
{
using System;

using Castle.Windsor;
using Castle.Windsor.Extensions.DependencyInjection;

Expand All @@ -29,5 +31,40 @@ public static IHostBuilder UseWindsorContainerServiceProvider(this IHostBuilder
{
return hostBuilder.UseServiceProviderFactory<IWindsorContainer>(new WindsorServiceProviderFactory());
}

/// <summary>
/// Uses <see name="IWindsorContainer" /> as the DI container for the host
/// </summary>
/// <param name="hostBuilder">Host builder</param>
/// <param name="factoryArgs">Ctor arguments for the creation of the factory</param>
/// <returns>Host builder, creates instance of factory passed as generic</returns>
public static IHostBuilder UseWindsorContainerServiceProvider<T>(this IHostBuilder hostBuilder, params object[] factoryArgs)
where T : WindsorServiceProviderFactoryBase
{
return hostBuilder.UseServiceProviderFactory<IWindsorContainer>((T)Activator.CreateInstance(typeof(T), factoryArgs));
}

/// <summary>
/// Uses <see name="IWindsorContainer" /> as the DI container for the host
/// </summary>
/// <param name="hostBuilder">Host builder</param>
/// <param name="serviceProviderFactory">Instance of WindsorServiceProviderFactoryBase to be used as ServiceProviderFactory</param>
/// <returns>Host builder</returns>
public static IHostBuilder UseWindsorContainerServiceProvider<T>(this IHostBuilder hostBuilder, T serviceProviderFactory)
where T : WindsorServiceProviderFactoryBase
{
return hostBuilder.UseServiceProviderFactory<IWindsorContainer>(serviceProviderFactory);
}

/// <summary>
/// Uses <see name="IWindsorContainer" /> as the DI container for the host
/// </summary>
/// <param name="hostBuilder">Host builder</param>
/// <param name = "container">Windsor Container to be used for registrations, please note, will be cleared of all existing registrations</param>
/// <returns>Host builder</returns>
public static IHostBuilder UseWindsorContainerServiceProvider(this IHostBuilder hostBuilder, IWindsorContainer container)
{
return hostBuilder.UseServiceProviderFactory<IWindsorContainer>(new WindsorServiceProviderFactory(container));
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2004-2020 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

namespace Castle.Windsor.Extensions.DependencyInjection.Extensions
{
using System.Reflection;

using Castle.MicroKernel.Registration;

public static class ServiceDescriptorExtensions
{
public static IRegistration CreateWindsorRegistration(this Microsoft.Extensions.DependencyInjection.ServiceDescriptor service)
{
if (service.ServiceType.ContainsGenericParameters)
{
return RegistrationAdapter.FromOpenGenericServiceDescriptor(service);
}
else
{
var method = typeof(RegistrationAdapter).GetMethod("FromServiceDescriptor", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(service.ServiceType);
return method.Invoke(null, new object[] { service }) as IRegistration;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ namespace Castle.Windsor.Extensions.DependencyInjection

internal class WindsorScopeFactory : IServiceScopeFactory
{
private readonly IWindsorContainer _container;
private readonly IWindsorContainer scopeFactoryContainer;

public WindsorScopeFactory(IWindsorContainer container)
{
_container = container;
scopeFactoryContainer = container;
}

public IServiceScope CreateScope()
{
var scope = ExtensionContainerScope.BeginScope(ExtensionContainerScope.Current);

//since WindsorServiceProvider is scoped, this gives us new instance
var provider = _container.Resolve<IServiceProvider>();
var provider = scopeFactoryContainer.Resolve<IServiceProvider>();

return new ServiceScope(scope, provider);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,20 @@

namespace Castle.Windsor.Extensions.DependencyInjection
{
using System;

using Castle.Windsor.Extensions.DependencyInjection.Extensions;
using Castle.Windsor.Extensions.DependencyInjection.Scope;

using Microsoft.Extensions.DependencyInjection;

public class WindsorServiceProviderFactory : IServiceProviderFactory<IWindsorContainer>
public sealed class WindsorServiceProviderFactory : WindsorServiceProviderFactoryBase
{
private readonly ExtensionContainerRootScope rootScope;

public WindsorServiceProviderFactory()
{
rootScope = ExtensionContainerRootScope.BeginRootScope();
}

public IWindsorContainer CreateBuilder(IServiceCollection services)
{
var container = services.CreateContainer(this);
return container;
CreateRootContainer();
CreateRootScope();
}

public IServiceProvider CreateServiceProvider(IWindsorContainer container)
public WindsorServiceProviderFactory(IWindsorContainer container)
{
return container.Resolve<IServiceProvider>();
SetRootContainer(container);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright 2004-2020 Castle Project - http://www.castleproject.org/
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


namespace Castle.Windsor.Extensions.DependencyInjection
{
using System;

using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor.Extensions.DependencyInjection.Extensions;
using Castle.Windsor.Extensions.DependencyInjection.Resolvers;
using Castle.Windsor.Extensions.DependencyInjection.Scope;

using Microsoft.Extensions.DependencyInjection;

public abstract class WindsorServiceProviderFactoryBase : IServiceProviderFactory<IWindsorContainer>
{
internal ExtensionContainerRootScope rootScope;
protected IWindsorContainer rootContainer;

public virtual IWindsorContainer Container => rootContainer;

public virtual IWindsorContainer CreateBuilder(IServiceCollection services)
{
return BuildContainer(services, rootContainer);
}

public virtual IServiceProvider CreateServiceProvider(IWindsorContainer container)
{
return container.Resolve<IServiceProvider>();
}

protected virtual void CreateRootScope()
{
rootScope = ExtensionContainerRootScope.BeginRootScope();
}

protected virtual void CreateRootContainer()
{
SetRootContainer(new WindsorContainer());
}

protected virtual void SetRootContainer(IWindsorContainer container)
{
rootContainer = container;
AddSubSystemToContainer(rootContainer);
}

protected virtual void AddSubSystemToContainer(IWindsorContainer container)
{
rootContainer.Kernel.AddSubSystem(
SubSystemConstants.NamingKey,
new SubSystems.DependencyInjectionNamingSubsystem()
);
}

protected virtual IWindsorContainer BuildContainer(IServiceCollection serviceCollection, IWindsorContainer windsorContainer)
{
if (rootContainer == null)
{
CreateRootContainer();
}
if (rootContainer == null) throw new ArgumentNullException("Could not initialize container");

if (serviceCollection == null)
{
return rootContainer;
}

RegisterContainer(rootContainer);
RegisterProviders(rootContainer);
RegisterFactories(rootContainer);

AddSubResolvers();

RegisterServiceCollection(serviceCollection, windsorContainer);

return rootContainer;
}

protected virtual void RegisterContainer(IWindsorContainer container)
{
container.Register(
Component
.For<IWindsorContainer>()
.Instance(container));
}

protected virtual void RegisterProviders(IWindsorContainer container)
{
container.Register(Component
.For<IServiceProvider, ISupportRequiredService>()
.ImplementedBy<WindsorScopedServiceProvider>()
.LifeStyle.ScopedToNetServiceScope());
}

protected virtual void RegisterFactories(IWindsorContainer container)
{
container.Register(Component
.For<IServiceScopeFactory>()
.ImplementedBy<WindsorScopeFactory>()
.LifestyleSingleton(),
Component
.For<IServiceProviderFactory<IWindsorContainer>>()
.Instance(this)
.LifestyleSingleton());
}

protected virtual void RegisterServiceCollection(IServiceCollection serviceCollection,IWindsorContainer container)
{
foreach (var service in serviceCollection)
{
rootContainer.Register(service.CreateWindsorRegistration());
}
}

protected virtual void AddSubResolvers()
{
rootContainer.Kernel.Resolver.AddSubResolver(new RegisteredCollectionResolver(rootContainer.Kernel));
rootContainer.Kernel.Resolver.AddSubResolver(new OptionsSubResolver(rootContainer.Kernel));
rootContainer.Kernel.Resolver.AddSubResolver(new LoggerDependencyResolver(rootContainer.Kernel));
}
}
}

0 comments on commit 662efa6

Please sign in to comment.