La inyección del constructor de un registrador en Startup funciona en versiones anteriores de ASP.NET Core porque se crea un contenedor DI separado para el host web. A partir de ahora, solo se crea un contenedor para el host genérico; consulte el anuncio de cambios importantes .
Inicio.cs
public class Startup { /// <summary> The configuration. </summary> public IConfiguration Configuration { get; } /// <summary> The web host environment. </summary> public IWebHostEnvironment WebHostEnvironment { get; } public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment) { Configuration = configuration; WebHostEnvironment = webHostEnvironment; } public void ConfigureServices(IServiceCollection services) { services.AddServices(Configuration); // This is a custom method, that adds multiple services to the container. } public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger) => app.UseComponents(env, Configuration, logger); }Ahora, según MSDN , he modificado mi Startup.cs de la siguiente manera:
public class Startup { /// <summary> The configuration. </summary> public IConfiguration Configuration { get; } public ILogger<Startup> Logger { get; set; } /// <summary> The web host environment. </summary> public IWebHostEnvironment WebHostEnvironment { get; } public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment) { Configuration = configuration; WebHostEnvironment = webHostEnvironment; } public void ConfigureServices(IServiceCollection services) { services.AddSingleton((container) => { var logger = container.GetRequiredService<ILogger<MyService>>(); return new Startup(Configuration, WebHostEnvironment) { Logger = logger }; }); // I know this is incorrect, but that my question- how do I correctly access logger in here? services.AddServices(Configuration, Logger); // Logger => null } public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger) => app.UseComponents(env, Configuration, logger); }StartupExtension.ConfigureServices.cs
public static partial class StartupExtension { #region Internal Method /// <summary> Adds all the services required by the DemoUsageApp. </summary> /// <param name="services">The services, <see cref="IServiceCollection"/>.</param> /// <param name="configuration">The configuration, <see cref="IConfiguration"/>.</param> /// <param name="logger">The logger, <see cref="ILogger{Startup}"/>.</param> /// <returns></returns> internal static IServiceCollection AddServices(this IServiceCollection services, IConfiguration configuration, ILogger logger) { services.AddDotNetCoreServices(configuration, logger); services.AddCrossCuttingServices(configuration, logger); return services; } #endregion Internal Method #region Private Methods /// <summary> Adds .NET Core services. </summary> /// <param name="services">The services, <see cref="IServiceCollection"/>.</param> /// <param name="configuration">The configuration, <see cref="IConfiguration"/>.</param> /// <param name="logger">The logger, <see cref="ILogger{Startup}"/>.</param> /// <returns></returns> private static IServiceCollection AddDotNetCoreServices(this IServiceCollection services, IConfiguration configuration, ILogger logger) { logger.LogInformation("---- Adding .NET Core components ----"); services.AddMvc(); services.AddControllers(); logger.LogInformation("---- Successfully added .NET Core components ----"); return services; } /// <summary> Adds Cross-Cutting services. </summary> /// <param name="services">The services, <see cref="IServiceCollection"/>.</param> /// <param name="configuration">The configuration, <see cref="IConfiguration"/>.</param> /// <param name="logger">The logger, <see cref="ILogger{Startup}"/>.</param> /// <returns></returns> private static IServiceCollection AddCrossCuttingServices(this IServiceCollection services, IConfiguration configuration, ILogger logger) { logger.LogInformation("---- Adding Cross-Cutting components ----"); services.AddSql(configuration, logger); //This is a extension methods, that adds Sql services (which are also completely custom) to the application. logger.LogInformation("---- Successfully added Cross-Cutting components ----"); return services; } #endregion Private Methods }Pregunta : ¿Cómo accedo a Logger en el método ConfigureServices de Startup.cs para poder pasarlo a otros métodos de extensión personalizados que agregan servicios personalizados al contenedor?
NOTA: Solución solicitada para Microsoft y Serilog Logger (opcional).
Actualización 1: como señaló @MathewBeck en su segundo comentario, ya tengo la siguiente estructura de Program.cs :
public class Program { #region Public Methods /// <summary> Main method, the entry-point of the application. </summary> /// <param name="args">The args <see cref="string[]"/></param> public static void Main(string[] args) { var host = CreateHostBuilder(args).Build(); var logger = host.Services.GetRequiredService<ILogger<Program>>(); logger.LogInformation("Host created."); host.Run(); } /// <summary> Creates the host builder. </summary> /// <param name="args">The args <see cref="string[]"/></param> /// <returns></returns> public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) //.ConfigureLogging(loggingBuilder => //{ // loggingBuilder.ClearProviders(); // loggingBuilder.AddConsole(); // loggingBuilder.AddDebug(); // loggingBuilder.AddEventLog(); // loggingBuilder.AddEventSourceLogger(); //}) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); webBuilder.UseConfiguration(GetConfiguration()); }); #endregion Public Methods #region Private Methods /// <summary> Gets the configuration. </summary> /// <returns></returns> private static IConfiguration GetConfiguration() { var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Development"; var builder = new ConfigurationBuilder() .AddJsonFile("appsettings.json", true, true) .AddJsonFile($"appsettings.{env}.json", true, true); return builder.Build(); } #endregion Private Methods }Si está utilizando NLog, la forma más fácil de iniciar sesión en su startup.cs es agregar propiedad privada.
private readonly NLog.ILogger _log;Luego, en tu constructor solo usa
_log = NLog.LogManager.GetCurrentClassLogger();He utilizado la función de activación de la clase Control Startup introducida en .NET 5.0 -
Para citar la documentación de MSDN:
Se agregó una sobrecarga adicional de UseStartup que permite que una aplicación proporcione un método de fábrica para controlar la activación de la clase Startup. Controlar la activación de la clase Startup es útil para pasar parámetros adicionales a Startup que se inicializan junto con el host.
public class Program { public static async Task Main(String[] args) { var loggerFactory = LoggerFactory .Create(builder => { builder.ClearProviders(); builder.AddConsole(); }); var logger = loggerFactory.CreateLogger<Program>(); var host = Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(context => new Startup(ILogger<Program> logger, /*based on the ctor of startup one can pass the required arguments here*/) }) .Build(); await host.RunAsync(); } }