"Microsoft.Extensions.DependencyInjection" and different concretes per environment

300 views Asked by At

"Microsoft.Extensions.DependencyInjection"

List of "environments"
  Production
  Uat
  Qa
  DevShared
  LocalDev

With DotNet (Framework/Classic) 4.6 or above (aka, "in the past", I used "Unity" with xml configuration. https://blogs.msdn.microsoft.com/miah/2009/04/03/testing-your-unity-xml-configuration/

(In the past before Dot Net core when using "Unity" IoC/DI)...When I had a need to have a concrete specific to an environment, I would tweak the concrete on the .xml. For instance, let's say my webApi needed authentication in production, uat, qa and dev-shared. but in dev-local, I do not want to deal with authentication all the time as I developed the webApi, I would have 2 concretes.

IAuthorizer

MyRealAuthorizer : IAuthorizer

MyDevLetEverythingThroughAuthorizer : IAuthorizer

and I would "register" one of them .. using xml.

My build process would alter the unity.xml (unity.config to be precise) and change out (via xml-update-tasks in msbuild)

MyDevLetEverythingThroughAuthorizer

to

MyRealAuthorizer

.

.....

Java Spring has "annotation" based:

import org.springframework.context.annotation.Profile;


@Profile("localdev")
public class MyDevLetEverythingThroughAuthorizer implements IAuthorizer {


@Profile("!localdev")
public class MyRealAuthorizer implements IAuthorizer {

But that does not honor the "Composite Root" pattern : (Mark Seeman http://blog.ploeh.dk/2011/07/28/CompositionRoot/ )

.......

So now I'm entering the world of DotNetCore. Everything has been going smooth. But I finally hit a situation where I need a dev-friendly concrete vs a non-dev "real" concretes.

Xml isn't available (to my best knowledge) with "Microsoft.Extensions.DependencyInjection".

I'm not sure of the best practice with DotNetCore in this situation.

I would prefer to honor the Composite Root pattern.

Basically, the below......but respecting the environments.

asp.net'ish

    public void ConfigureServices(Microsoft.Extensions.DependencyInjection.IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        /* need this for "local-dev" */
        services.AddScoped<IAuthorizer, MyDevLetEverythingThroughAuthorizer>();

        /* need this for everything EXCEPT "local-dev" */
        services.AddScoped<IAuthorizer, MyRealAuthorizer>();

    }

(not asp.net) dot.net core'ish too

    private static System.IServiceProvider BuildDi()
    {
        //setup our DI
        IServiceProvider serviceProvider = new ServiceCollection()
            .AddLogging()
            /* need this for "local-dev" */
            .AddSingleton<IAuthorizer, MyDevLetEverythingThroughAuthorizer>()

            /* need this for everything EXCEPT "local-dev" */
            .AddSingleton<IAuthorizer, MyRealAuthorizer>()              

APPEND

This article and snipplet help me understand the "what is built in" portion a little better:

https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments?view=aspnetcore-2.2

Environments ASP.NET Core reads the environment variable ASPNETCORE_ENVIRONMENT at app startup and stores the value in IHostingEnvironment.EnvironmentName. You can set ASPNETCORE_ENVIRONMENT to any value, but three values are supported by the framework: Development, Staging, and Production. If ASPNETCORE_ENVIRONMENT isn't set, it defaults to Production.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    if (env.IsProduction() || env.IsStaging() || env.IsEnvironment("Staging_2"))
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseMvc();
}

The

env.IsEnvironment("Staging_2") (akin to env.IsEnvironment("MyCustomValue") ) is the trick I guess.

APPEND:

This SOF question made it more clear for Asp.Net Core.

How to set aspnetcore_environment in publish file?

And ways you can set the environment variable without actually setting a (machine) environment variable!

2

There are 2 answers

4
Neville Nazerane On

Your question seems to be talking about two things: setting configuration from XML files and managing services using IServiceCollection. For .net core web applications, these happen in two stages:

  1. A key value pair is consolidated from various pre-defined and custom sources (including json, XML, environment). All preset .net core web templates do this in program.cs.

  2. The key value pair collection is sent to the Startup class that can be accessed via DI from the IConfiguration variable. Check this link for more information.

With this being the process, all config files are added before the ConfigureServices method is called in the Startup class. If you would like to add XML files to this configuration, you can set the following code in your program.cs:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
    // additional code
        .UseConfiguration(
            new ConfigurationBuilder()
            .AddXmlFile("file.xml", true) // second param is if file is optional
            .Build()
        )
    // end of additional code
        .UseStartup<Startup>();

If you want to access your environment, if they are set as environment variables, you can use one of the Environment.Get... functions.

Regarding your service, I am not sure in what way you are trying to access your XML, but you can always inject the IConfiguration as the simplest solution if you need to. However, I would advise against exposing your entire configuration to your services and have a look at setting up options with the help of this documentation

4
amiry jd On
public void ConfigureServices(IServiceCollection services, IHostingEnvironment environment) {
        if (environment.IsDevelopment()) {
            // bla bla bla
        } else {
            // bla bla bla
        }
        // register no-matter-which-environment services
}