Как получить доступ к службе в ASP.NET Core перед созданием WebHost? - PullRequest
0 голосов
/ 26 мая 2019

Предположим, что у нас есть следующее Program.cs:

public static class Program
{
    public static async Task Main(string[] args)
    {
        await CreateWebHostBuilder(args).Build().RunAsync();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args)
    {
        return WebHost
            .CreateDefaultBuilder(args)
            .ConfigureKestrel(options => { options.AllowSynchronousIO = false; })
            .ConfigureFanciness()
            .ConfigureLogging(ConfigureApplicationLogging)
            .UseStartup<Startup>();
    }

    private static void ConfigureApplicationLogging(WebHostBuilderContext context, ILoggingBuilder loggingBuilder)
    {
        var loggingConfiguration = context.Configuration.GetSection("Logging");

        loggingBuilder.AddConfiguration(loggingConfiguration);

        // var fancyService = SomehowGet<IFancyService>();
        // if (fancyService.IsEnabled)
        //     loggingBuilder.AddEventLog(loggingConfiguration);
    }

    public static IWebHostBuilder ConfigureFanciness(this IWebHostBuilder hostBuilder)
    {
        return hostBuilder.ConfigureServices(delegate (WebHostBuilderContext context, IServiceCollection services)
        {
            var fancinessConfiguration = context.Configuration.GetSection("Fanciness");
            services.Configure<FancinessSettings>(fancinessConfiguration);
            services.AddSingleton<IFancyService, FancyService>();

            // var fancyService = SomehowGet<IFancyService>();
            // fancyService.Initialize();
        });
    }
}

и следующее FancyService.cs:

public sealed class FancyService : IFancyService
{
    private readonly ILogger<FancyService> logger;
    private readonly IOptions<FancinessSettings> settings;

    public FancyService(ILogger<FancyService> logger, IOptions<FancinessSettings> settings)
    {
        this.logger = logger;
        this.settings = settings;
    }

    public bool IsEnabled { get; private set; }

    public void Initialize()
    {
        // do the initialization work and set IsEnabled to some value
    }
}

Как показано в файлах примеров, loggingBuilder.AddEventLog(loggingConfiguration) зависитна IFancyService.IsEnabled, который устанавливается при вызове IFancyService.Initialize().

Для этого мне нужен доступ к экземпляру IFancyService;Есть ли способ достичь этого?

Ответы [ 2 ]

0 голосов
/ 29 мая 2019

Как обсуждалось в комментариях, если ваш FancyService не имеет зависимости конструктора от ILogger<>:

public sealed class FancyService : IFancyService
{ 
    public FancyService(IOptions<FancinessSettings> settings)
    { ... }

для инициализации IFancyService, просто используйте фабрику реализации , чтобы создать IFancyService экземпляр:

public static IWebHostBuilder ConfigureFanciness(this IWebHostBuilder hostBuilder)
{
    return hostBuilder.ConfigureServices(delegate (WebHostBuilderContext context, IServiceCollection services)
    {
        var fancinessConfiguration = context.Configuration.GetSection("Fanciness");
        services.Configure<FancinessSettings>(fancinessConfiguration);
        services.AddSingleton<IFancyService, FancyService>(sp =>{
            var fancy=ActivatorUtilities.CreateInstance(sp,typeof(FancyService)) as FancyService;
            fancy.Initialize();      
            return fancy;
        });
    });
}

Тот же прием можно использовать и для регистрации провайдера логгеров. Поскольку служба ILogger<> зависит от IEnumberable<ILoggerProvider>, мы могли бы зарегистрировать экземпляр ILoggerProvider, который предоставляет дополнительный INullLogger для настройки поведения ведения журнала в соответствии с текущим IFancyService:

private static void ConfigureApplicationLogging(WebHostBuilderContext context, ILoggingBuilder loggingBuilder)
{
    var loggingConfiguration = context.Configuration.GetSection("Logging");

    var descriptor=ServiceDescriptor.Singleton<ILoggerProvider,NullLoggerProvider>(sp =>{
        var provider = NullLoggerProvider.Instance;
        var fancy = sp.GetRequiredService<IFancyService>();
        if(fancy.IsEnabled)      
        {
            loggingBuilder.AddDebug();
            loggingBuilder.AddEventLog(loggingConfiguration);
            loggingBuilder.AddEventSourceLogger(); 
            // ... add more configuration as you like
        }else{
            loggingBuilder.AddConsole();
        }
        return provider;
    });
    loggingBuilder.Services.TryAddEnumerable(descriptor);
    loggingBuilder.AddConfiguration(loggingConfiguration);
}

В качестве примечания, будьте внимательны, как только регистратор будет построен, не меняйте IFancyService.IsEnabled. Это связано с тем, что сервис ILogger<> зарегистрирован как одноэлементный и никогда не менялся после создания.

0 голосов
/ 27 мая 2019

После вызова services.AddSingleton<IFancyService, FancyService>() вы можете получить экземпляр FancyService, построив ServiceProvider:

private static void ConfigureApplicationLogging(WebHostBuilderContext context, ILoggingBuilder loggingBuilder)
{
    var fancyService = loggingBuilder.Services.BuildServiceProvider().GetService<IFancyService>();
    fancyService.Initialize();
    var loggingConfiguration = context.Configuration.GetSection("Logging");

    loggingBuilder.AddConfiguration(loggingConfiguration);

    if (fancyService.IsEnabled)
        loggingBuilder.AddEventLog(loggingConfiguration);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...