ILogger никогда не имеет значения null в контроллере api

#c# #asp.net-core #serilog

Вопрос:

Я искал возможность интегрировать Serilog в новую реализацию API с использованием net core 5. Насколько я понимаю, это работает так, что он переопределяет базовую реализацию ILogger и добавляет дополнительные функции, которые все хороши и работают так, как ожидалось.

Проблема, с которой я сталкиваюсь, заключается в том, что даже без указания реализации ведения журнала в моем запуске зависимость ILogger от контроллеров никогда не бывает нулевой. Хотя этот вопрос может показаться странным, я пытаюсь понять, откуда взялся этот экземпляр ILogger по умолчанию.

Проблему можно воспроизвести, создав новый API net core 5 в Visual Studio, с помощью которого можно получить пример контроллера погоды и один метод Get (). В этом примере контроллер имеет зависимость ILogger в конструкторе, как показано ниже;

  public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }
 

Который затем может быть использован в действии;

  [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            _logger.LogInformation("Testing");

            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }
 

В примере приведены следующие файлы program.cs и startup.cs;

   public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication2", Version = "v1" });
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication2 v1"));
            }

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }

 public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
 

Нигде в этом коде мы, похоже, не добавляем/определяем регистратор, и я пытаюсь понять, откуда это взялось.

В моей собственной реализации у меня есть зависимость от ILogger в других классах, которая работает в контексте вызова из API, но терпит неудачу при вызове с помощью модульного теста, как (в настоящее время) Я явно не определяю ILogger в приспособлении.

Итак, где же ILogger инициализируется в примере API?

Примеры других API имеют следующий код в конструкторе, но если logger никогда не имеет значения null, то…..

  _logger = logger ?? throw new ArgumentNullException(nameof(logger));
 

Комментарии:

1. ILogger<T> это из инфраструктуры ведения журнала, которая автоматически вводится хостом, созданным с Host.CreateDefaultBuilder помощью . Вы можете увидеть более подробную информацию здесь: docs.microsoft.com/en-us/aspnet/core/fundamentals/host/…

2. Кроме того, контейнер DI в .NET Core не может вводить null , поэтому null проверка полезна только в том случае, если вы хотите переключиться на другую систему DI, которая вводит значение null для отсутствующих служб

3. @CamiloTerevinto Идеально, спасибо

Ответ №1:

Вызов Host.CreateDefaultBuilder добавляет значения по умолчанию для ведения журнала. Чтобы удалить эти значения по умолчанию, вы можете сделать это:

 Host.CreateDefaultBuilder(args)
  .ConfigureLogging(logging =>
  {
    logging.ClearProviders();
    // Add your own logging provider here.
  })
 

Более подробную информацию можно найти здесь: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-5.0

Комментарии:

1. Удаление поставщиков не удаляет экземпляр ILogger, это просто означает, что коллекция регистраторов пуста, и, хотя при попытке внести что-либо в журнал не генерируется никаких исключений, записи в журнале не создаются.