'Access IHost across application classes globally

Below is an example code for CreateHostBuilder. Asp.net core host takes care of resolving dependency through constructor and middleware.

If we want to resolve it for our custom classes which does not get invoked through controller or the main method, how can we get the instance of the host across applications. Is it a good way to store it as a static variable Or there is some better way to do that?

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();

        using (var serviceScope = host.Services.CreateScope())
        {
            var services = serviceScope.ServiceProvider;

            try
            {
                var serviceContext = services.GetRequiredService<MyScopedService>();
                // Use the context here
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred.");
            }
        }

        await host.RunAsync();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}


Solution 1:[1]

Old question, but never answered....

I've found this necessary normally when working with code that has been converted to newer versions of .net and I need the services in an existing static class. What I've done in the past is expose the host created by builder as a public static property of the program class. For some projects, IHost doesn't work. Eg, a recent AWS Lambda project has a local entry point and lambda entry point, one is IHost and one is IWebHost, and those two don't share a common interfaces. So I added a static "IServiceProvider Services" property to the Startup class and set it to app.ApplicationServices in the Configure routine so that other classes could access that. This is specifically recommended by Microsoft as "Avoid static access to services. For example, avoid capturing IApplicationBuilder.ApplicationServices as a static field or property for use elsewhere." (https://docs.microsoft.com/en-us/dotnet/core/extensions/dependency-injection-guidelines)

Another option I've used is to add a static method to your classes that can be called right after host startup to inject the host into the class. Right after IHost.Build, I added a routine called something like "InjectHost" that had a call for each class I wanted to inject into.

Lately, I've started getting fancy. I wrote the following startup code and a custom attribute do do my own injection. Technically, the custom attribute isn't even necessary. It's a nod toward optimization, but mostly it's there to make it explicit that certain classes will be injected so that the new code doesn't have a chance to screw with any other DI workarounds previous developers may have put in.

public static class StaticDI {
    ///<summary>Add app.UseStaticDI to your "Configure" method to enable the dependency injection into static classes.</summary>
    public static IApplicationBuilder UseStaticDI(this IApplicationBuilder app) {
        var services = app.ApplicationServices;

        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
        foreach (var assembly in assemblies) {
            //The attribute isn't technically required, I'm just hoping it speeds up startup.  If you don't want to
            //use it, just remove the .Where.
            var types = assembly.GetTypes().Where(x => x.IsDefined(typeof(StaticDIAttribute)));
            foreach(var type in types) {
                var fields = type.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
                foreach (var field in fields) {
                    var diObject = services.GetService(field.FieldType);
                    if (diObject != null) {
                        field.SetValue(null, diObject);
                    }
                }
            }
        }

        return app;
    }
}
///<summary>Add this to static classes to enable dependency injection</summary>
public class StaticDIAttribute:Attribute {
    
}

Just call "app.UseStaticDI" from your configure method to do the injection.

But in general, always keep in mind that the point of DI is to not use static, it replaces your statics. So the "proper" response is to convert everything to instance classes, based on an interface, preferably with a new static class to house your "AddBlahServices" extension method.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 user34314