volosoft / castle-windsor-ms-adapter

Castle Windsor ASP.NET Core / Microsoft.Extensions.DependencyInjection Adapter
https://www.nuget.org/packages/Castle.Windsor.MsDependencyInjection
MIT License
85 stars 29 forks source link

ScopedWindsorServiceProvider should implement IDisposable #33

Open jdwoolcock opened 5 years ago

jdwoolcock commented 5 years ago

Description I am using Castle.Windsor.MsDependencyInjection with Microsoft.Extensions.Hosting HostBuilder. When the host is terminated the Windsor container is not disposed and the application fails to shutdown.

var host = new HostBuilder()
                .UseServiceProviderFactory(new WindsorServiceProviderFactory())
                .ConfigureContainer<IWindsorContainer>(hostContext, container) =>
                {
                                //Register Special Stuff
                })
                .RunConsoleAsync();

Proposed Solution

The following code changes resolve the issue

Make ScopedWindsorServiceProvider implement IDisposable

public void Dispose()
{
       _container.Dispose();
}

Dependencies Microsoft.Extensions.Hosting 2.2 Castle.Windsor.MsDependencyInjection 3.3.1

chrisheil commented 4 years ago

@hikalkan Did you ever find a solution to this? I am having the same issue. I see the IDisposable proposal was rejected, but that still leaves an issue of the Windsor container not being disposed of properly.

dquist commented 4 years ago

I solved this problem by creating a hosted service to manage the lifetime of the container. The container gets disposed on the ApplicationStopped event.

See: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-3.1#ihostapplicationlifetime

Inject the IHostApplicationLifetime (formerly IApplicationLifetime) service into any class to handle post-startup and graceful shutdown tasks. Three properties on the interface are cancellation tokens used to register app start and app stop event handler methods. The interface also includes a StopApplication method.

public class WindsorHostedService : IHostedService
{
    private readonly IWindsorContainer _container;
    private readonly IHostApplicationLifetime _applicationLifetime;

    public WindsorHostedService(IWindsorContainer container, IHostApplicationLifetime applicationLifetime)
    {
        _container = container ?? throw new ArgumentNullException(nameof(container));
        _applicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _applicationLifetime.ApplicationStopped.Register(OnStopping);

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    private void OnStopped()
    {
        _container.Dispose();
    }
}