简体   繁体   中英

Replace a service in servicecollection used by webhost in .net core

Ok, so I have a class instance being added to the services collection in startup.cs during runtime like so:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<WidgetProvider, BlueWidgetProvider>();
    }

However, while running I want the application to be able to replace the BlueWidgetProvider with a RedWidgetProvider . How would I go about doing this? I know you can use the Remove method on an IServicesCollection , but how would I expose this to my application? I can expose the IServiceProvider that has the WidgetProvider added like below, but I'm not sure how I'd go about accessing the underlying services collection.

    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .Build();

        Current.Services = host.Services;  //Here

        host.Run(Current.AppCancellationSource.Token);
    }

Well one method that's working for me is to cancel the host.Run method and recursively call Main again like this:

Make some setting change that tells startup to use a different widget provider when configuring services:

public void UseRedWidgetProvider() {
    database.UseRedWidgetProvider();
    Restart();
}

Method to cancel host.Run method:

public void Restart() 
{
    Current.AppCancellationSource.Cancel();
}

Static class to contain cancellation token:

public static class Current 
{
    public static CancellationTokenSource AppCancellationSource = new CancellationTokenSource();
}

Recursively start Main after cancellation token is invoked:

public static void Main(string[] args)
{
    var host = new WebHostBuilder()
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseIISIntegration()
        .UseStartup<Startup>()
        .Build();

    CoreCurrent.Protector = ActivatorUtilities.CreateInstance<DataProtect>(host.Services);

    Current.Services = host.Services;

    Current.SetDbConfigurationState();

    host.Run(Current.AppCancellationSource.Token);

    //reset token and call main again
    host.Dispose();
    Current.AppCancellationSource = new System.Threading.CancellationTokenSource();
    Main(args);
}

This appears to be working ok for me. Once I invoke the cancellation token the app appears to restart fairly quickly and the new widget provider is now used. Not entirely sure if this is a good practice or if there are any components that might be messed up.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM