Access hosting environment before building WebHost

2.9k Views Asked by At

In my Program.cs Main method, I would like to read user secrets, configure a logger and then build the WebHost.

public static Main(string[] args)
{

    string instrumentationKey = null; // read from UserSecrets

    Log.Logger = new LoggerConfiguration()
        .MinimumLevel.Debug()
        .WriteTo.ApplicationInsightsEvents(instrumentationKey)
        .CreateLogger();

    BuildWebHost(args).Run();
} 

I can get to the configuration by building my own, but I quickly end up in a mess trying to access hosting environment properties:

public static Main(string[] args)
{
    var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production";
    var configBuilder = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{envName}.json", optional: true, reloadOnChange: true);

    // Add user secrets if env.IsDevelopment().
    // Normally this convenience IsDevelopment method would be available 
    // from HostingEnvironmentExtensions I'm using a private method here.
    if (IsDevelopment(envName))
    {
        string assemblyName = "<I would like the hosting environment here too>"; // e.g env.ApplicationName
        var appAssembly = Assembly.Load(new AssemblyName(assemblyName));
        if (appAssembly != null)
        {
            configBuilder.AddUserSecrets(appAssembly, optional: true); // finally, user secrets \o/
        }
    }
    var config = configBuilder.Build();
    string instrumentationKey = config["MySecretFromUserSecretsIfDevEnv"];

    Log.Logger = new LoggerConfiguration()
        .MinimumLevel.Debug()
        .WriteTo.ApplicationInsightsEvents(instrumentationKey) // that.. escallated quickly
        .CreateLogger();

    // webHostBuilder.UseConfiguration(config) later on..
    BuildWebHost(args, config).Run();
}

Is there an easier way to access IHostingEnvironment before building the WebHost?

3

There are 3 best solutions below

1
Set On BEST ANSWER

In the main method, you cannot get the IHostingEnvironment instance before building the WebHost, as hosting is not yet created. And you cannot create a new valid instance properly, as it must be initialized using WebHostOptions`.


For application name you may use Assembly.GetEntryAssembly()?.GetName().Name


For environment name use what you currently do (I assume something like this is used in your IsDevelopment() method):

var environmentName = System.Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
bool isDevelopment = string.Equals(
           "Development",
            environmentName,
            StringComparison.OrdinalIgnoreCase);

See, methods like IHostingEnvironment.IsDevelopment() are extension methods that simply do string comparison internally:

    public static bool IsDevelopment(this IHostingEnvironment hostingEnvironment)
    {
        if (hostingEnvironment == null)
        {
            throw new ArgumentNullException(nameof(hostingEnvironment));
        }

        return hostingEnvironment.IsEnvironment(EnvironmentName.Development);
    }


    public static bool IsEnvironment(
        this IHostingEnvironment hostingEnvironment,
        string environmentName)
    {
        if (hostingEnvironment == null)
        {
            throw new ArgumentNullException(nameof(hostingEnvironment));
        }

        return string.Equals(
            hostingEnvironment.EnvironmentName,
            environmentName,
            StringComparison.OrdinalIgnoreCase);
    }

Note regarding AddJsonFile: as file name is sensitive in Unix OS, sometimes it's better to use $"appsettings.{envName.ToLower()}.json" instead of.

2
GlennSills On

I wanted to do something similar. I wanted to set Kestrel listen options based on the environment. I just save the IHostingEnvironment to a local variable while I am configuring the apps configuration. Then later on I use that variable to make a decision based on the environment. You should be able to follow this pattern to accomplish your goal.

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args)
    {
        IHostingEnvironment env = null;

        return WebHost.CreateDefaultBuilder(args)
              .UseStartup<Startup>()
              .ConfigureAppConfiguration((hostingContext, config) =>
              {
                  env = hostingContext.HostingEnvironment;

                  config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                          .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                  if (env.IsDevelopment())
                  {
                      var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
                      if (appAssembly != null)
                      {
                          config.AddUserSecrets(appAssembly, optional: true);
                      }
                  }

                  config.AddEnvironmentVariables();

                  if (args != null)
                  {
                      config.AddCommandLine(args);
                  }
              })
              .UseKestrel(options =>
              {
                  if (env.IsDevelopment())
                  {
                      options.Listen(IPAddress.Loopback, 44321, listenOptions =>
                      {
                          listenOptions.UseHttps("testcert.pfx", "ordinary");
                      });
                  }
                  else
                  {
                      options.Listen(IPAddress.Loopback, 5000);
                  }
              })
              .Build();
    }
}
0
Artur On

In .Net Core 2.0 you can do like this

var webHostBuilder = WebHost.CreateDefaultBuilder(args);
var environment = webHostBuilder.GetSetting("environment");