0

"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!

granadaCoder
  • 26,328
  • 10
  • 113
  • 146
  • 1
    https://andrewlock.net/configuring-environment-specific-services-in-asp-net-core/ – Daniel A. White Dec 03 '18 at 19:08
  • Ok, I will check that out. Looks like they have 3 "pre defined" environments, but the ability to add custom ones. IsDevelopment(IHostingEnvironment) IsProduction(IHostingEnvironment) IsStaging(IHostingEnvironment) IsEnvironment(IHostingEnvironment, String) – granadaCoder Dec 03 '18 at 19:12
  • I think something is missing in your sentence "For instance, if my webApi ...." in the third para. could you double check that sentence? – Neville Nazerane Dec 03 '18 at 19:50

2 Answers2

1
public void ConfigureServices(IServiceCollection services, IHostingEnvironment environment) {
        if (environment.IsDevelopment()) {
            // bla bla bla
        } else {
            // bla bla bla
        }
        // register no-matter-which-environment services
}
amiry jd
  • 27,021
  • 30
  • 116
  • 215
0

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

Neville Nazerane
  • 6,622
  • 3
  • 46
  • 79
  • I appreciate the input. However, I did state in the original question "I used "Unity" with xml configuration." Aka, the xml portion is "in the past" when I used Unity IoC/DI. And it just defined how I did it in the past with Dotnet-Framework (not Core). I will edit my question text to emphasis this point. – granadaCoder Dec 03 '18 at 22:39
  • I had seen this point and brushed through the link. Basically, everything I have seen and used in .NET Framework that was in xml like the web.config, have all its functionalities handled in these two ways. In other words, what those xmls used to offer are generally split into the add services and `IConfiguration` features. You generally need to see specifically what you were trying to achieve in your DI and check how to translate those into these two – Neville Nazerane Dec 04 '18 at 02:38
  • basically all you need is `MyDevLetEverythingThroughAuthorizer` should be used for dev envoirnment and `MyRealAuthorizer` must be the definition of `IAuthorizer` for the other? – Neville Nazerane Dec 04 '18 at 02:40
  • in response to the "basically" question........yes. but keep in mind i have two "dev" environments. "devlocal" (aka "my machine")......and "devshared" (aka, where devs put code that runs...NOT in "my machine"). its splitting hairs, but just emphasizing the point. – granadaCoder Dec 04 '18 at 13:16