.Net core 2.0 console program got null value when

2019-04-16 17:09发布

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());
            }
        }
    }
}

1条回答
Viruses.
2楼-- · 2019-04-16 17:21

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());
            }
        }
    }
}
查看更多
登录 后发表回答