I am experiencing an issue where options loaded from config into constructors via IOptionsMonitor are populated when I run my application in Visual Studio, but NOT populated if I run the built .exe from a command prompt.
I must be missing some fundamental thing to do with config but I just can't work it out.
Any help would be appreciated as I'm at a loss and have been struggling with this for some time now....
I have put together the code at the bottom to show what I am seeing.
When I run this in Visual Studio, the output is:
When I run the built .exe in a command window, the output is:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
namespace ConsoleApp1;
public static class Program
{
#region Public interface
public static void Main()
{
try
{
var host = BuildHost();
var test = host.Services.GetRequiredService<Consumer>();
test.DoSomething();
}
finally
{
Console.ReadLine();
}
}
#endregion
#region Private interface
private static IHost BuildHost()
{
var host = Host.CreateDefaultBuilder()
.ConfigureServices((context, services) =>
{
services.Configure<SampleOptions>(context.Configuration.GetSection("SampleOptions"));
services.AddSingleton<Consumer, Consumer>();
})
.Build();
return host;
}
#endregion
}
public class SampleOptions
{
public int? IntegerProperty { get; set; }
}
public class Consumer
{
public Consumer(IOptionsMonitor<SampleOptions> optionsMonitor)
{
OptionsMonitor = optionsMonitor;
}
private IOptionsMonitor<SampleOptions> OptionsMonitor { get; }
public void DoSomething()
{
var options = OptionsMonitor.CurrentValue;
if (!options.IntegerProperty.HasValue)
Console.WriteLine("options.IntegerProperty is NULL");
else
Console.WriteLine("options.IntegerProperty is not NULL");
}
}
I have an "appsettings.json" file as per below (set to "Copy If Newer"):
{
"SampleOptions": {
"IntegerProperty": 1
}
}
UPDATE: HostingEnvironment
I added the code below and that confirmed that the issue is to do with the current directory as suggested in the comments:
var hostingEnvironment = host.Services.GetRequiredService<IHostEnvironment>();
Console.WriteLine($"hostingEnvironment.EnvironmentName: {hostingEnvironment.EnvironmentName}");
Console.WriteLine($"hostingEnvironment.ContentRootPath: {hostingEnvironment.ContentRootPath}");
Command window output:
UPDATE:
The fix was to set the ContentRoot:
private static IHost BuildHost()
{
return Host.CreateDefaultBuilder()
.UseContentRoot(AppContext.BaseDirectory)
.ConfigureServices((context, services) =>
{
services.Configure<SampleOptions>(context.Configuration.GetSection("SampleOptions"));
services.AddSingleton<Consumer, Consumer>();
})
.Build();
}
Case closed.
Reference from J M's solution:
Need to add .UseContentRoot(AppContext.BaseDirectory)
like this:
private static IHost BuildHost()
{
return Host.CreateDefaultBuilder()
.UseContentRoot(AppContext.BaseDirectory)
.ConfigureServices((context, services) =>
{
services.Configure<SampleOptions>(context.Configuration.GetSection("SampleOptions"));
services.AddSingleton<Consumer, Consumer>();
})
.Build();
}