Reputation: 29159
The following .Net core 2.0 console application got null value when running serviceProvider.GetService<Application>();
?
class Program
{
static void Main(string[] args)
{
var services = new ServiceCollection();
ConfigureServices(services);
var serviceProvider = services.BuildServiceProvider();
var app = serviceProvider.GetService<Application>(); // Got null value
Task.Run(() => app.Run()).Wait();
}
private static void ConfigureServices(IServiceCollection services)
{
ILoggerFactory loggerFactory = new LoggerFactory()
.AddConsole()
.AddDebug();
services.AddSingleton(loggerFactory); // Add first my already configured instance
services.AddLogging(); // Allow ILogger<T>
IConfigurationRoot configuration = GetConfiguration();
services.AddSingleton<IConfigurationRoot>(configuration);
// Support typed Options
services.AddOptions();
services.Configure<MyOptions>(configuration.GetSection("MyOptions")); // Error!
services.AddTransient<Application>();
}
private static IConfigurationRoot GetConfiguration()
{
return new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddXmlFile("App.config", optional: true).Build();
}
public class MyOptions
{
public string Name { get; set; }
}
public class Application
{
ILogger _logger;
MyOptions _settings;
public Application(ILogger<Application> logger, IOptions<MyOptions> settings)
{
_logger = logger;
_settings = settings.Value;
}
public async Task Run()
{
try
{
_logger.LogInformation($"This is a console application for {_settings.Name}");
}
catch (Exception ex)
{
_logger.LogError(ex.ToString());
}
}
}
}
Upvotes: 0
Views: 1819
Reputation: 3030
I think it looks good, you just need to provide a singleton for your options.
var options = new MyOptions();
configuration.GetSection("MyOptions").Bind(options);
services.AddSingleton<MyOptions>(options);
Then, shift your app to use that singleton.
public Application(ILogger<Application> logger, MyOptions settings)
EDIT: What about IOptions Pattern?
Seems like others have suggested that you can use that syntax if you import the 1.0.0-rc2-final version of Microsoft.Extensions.Options.ConfigurationExtensions, but that will cascade into other references as well. Might not be worth it just to late-bind the options class.
All Working (less IOptions)
If that's an ok approach, then there is some other code in that section that doesn't function. Cleaned up version below. Hope that helps.
class Program {
static void Main(string[] args) {
var services = new ServiceCollection();
ConfigureServices(services);
var serviceProvider = services.BuildServiceProvider();
var app = serviceProvider.GetService<Application>(); // Got null value
Task.Run(() => app.Run()).Wait();
}
private static void ConfigureServices(IServiceCollection services) {
ILoggerFactory loggerFactory = new LoggerFactory()
.AddConsole() // Error!
.AddDebug();
services.AddSingleton(loggerFactory); // Add first my already configured instance
services.AddLogging(); // Allow ILogger<T>
IConfigurationRoot configuration = GetConfiguration();
services.AddSingleton<IConfigurationRoot>(configuration);
// Support typed Options
var myOptions = new MyOptions();
configuration.GetSection("MyOptions").Bind(myOptions);
services.AddSingleton<MyOptions>(myOptions);
services.AddTransient<Application>();
}
private static IConfigurationRoot GetConfiguration() {
return new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddXmlFile("App.config", optional: true).Build();
}
public class MyOptions {
public string Name { get; set; }
}
public class Application {
ILogger _logger;
MyOptions _settings;
public Application(ILogger<Application> logger, MyOptions settings) {
_logger = logger;
_settings = settings;
}
public async Task Run() {
try {
_logger.LogInformation($"This is a console application for {_settings.Name}");
} catch (Exception ex) {
_logger.LogError(ex.ToString());
}
}
}
}
Upvotes: 3