title: Implement Logging Using Serilog In ASP.NET Core 5.0 Application With Database
body: <p>In my asp.net core 5.0 app, whenever I am trying to perform logging using serilog and saving the logs to my database. However, when I run the api, it tells me:</p>
  <blockquote>
  <p>System.TypeInitializationException   HResult=0x80131534   Message=The
  type initializer for 'PaymentService.API.Program' threw an exception.
  Source=PaymentService.API   StackTrace:    at
  PaymentService.API.Program.get_Configuration() in API\Program.cs:line
  21    at PaymentService.API.Program.Main(String[] args) in
  API\Program.cs:line 34</p>
  <p>This exception was originally thrown at this call stack:
  [External Code]</p>
  <p>Inner Exception 1: FormatException: Could not parse the JSON file.</p>
  <p>Inner Exception 2: JsonReaderException: Expected depth to be zero at
  the end of the JSON payload. There is an open JSON object or array
  that should be closed. LineNumber: 7 | BytePositionInLine: 1.</p>
  </blockquote>
  <p>Which line 21 is:</p>
  <pre><code>public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
                              .SetBasePath(Directory.GetCurrentDirectory())
                              .AddJsonFile(&quot;appsettings.json&quot;, optional: false, reloadOnChange: true)
                              .AddJsonFile($&quot;appsettings.{Environment.GetEnvironmentVariable(&quot;ASPNETCORE_ENVIRONMENT&quot;) ?? &quot;Production&quot;}.json&quot;, optional: true)
                              .Build();
  </code></pre>
  <p>and Line 34 is:</p>
  <p><code>string connectionString = Configuration.GetConnectionString(&quot;Default&quot;);</code></p>
  <p><em>I am new to this, but do I have to make any configurations to &quot;ASPNETCORE_ENVIRONMENT&quot;?</em></p>
  <p><strong>After that, I was trying to add a custom column into the database named <code>CorrelationId</code> and send the <code>CorrelationId</code>'s to its specific column. I was following this <a href="https://www.c-sharpcorner.com/article/how-to-implementation-serilog-in-asp-net-core-5-0-application-with-database/" rel="nofollow noreferrer">tutorial</a> to do so, but I get stuck on step where they want to capture the user for the logs. I want to do the same but using the <code>CorrelationId</code> for the logs.</strong></p>
  <p><code>Program.cs</code>:</p>
  <pre><code>public class Program
      {
  
          public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
                              .SetBasePath(Directory.GetCurrentDirectory())
                              .AddJsonFile(&quot;appsettings.json&quot;, optional: false, reloadOnChange: true)
                              .AddJsonFile($&quot;appsettings.{Environment.GetEnvironmentVariable(&quot;ASPNETCORE_ENVIRONMENT&quot;) ?? &quot;Production&quot;}.json&quot;, optional: true)
                              .Build();
  
          public static void Main(string[] args)
          {
              
  
              string connectionString = Configuration.GetConnectionString(&quot;Default&quot;);
  
              var columnOptions = new ColumnOptions
              {
                  AdditionalColumns = new Collection&lt;SqlColumn&gt;
                  {
                      new SqlColumn(&quot;CorrelationId&quot;, SqlDbType.NVarChar)
                  }
              }; // through this columnsOptions we can dynamically add custom columns which we want to add in the db
  
              Log.Logger = new LoggerConfiguration()
                  .Enrich.FromLogContext()
                  .WriteTo.MSSqlServer(connectionString, sinkOptions: new MSSqlServerSinkOptions { TableName = &quot;PaymentLogs&quot; }
                  , null, null, LogEventLevel.Information, null, columnOptions: columnOptions, null, null)
                  .CreateLogger();
  
              CreateHostBuilder(args).Build().Run();
          }
  
          public static IHostBuilder CreateHostBuilder(string[] args) =&gt;
              Host.CreateDefaultBuilder(args)
                  .ConfigureWebHostDefaults(webBuilder =&gt;
                  {
                      webBuilder.UseStartup&lt;Startup&gt;().UseSerilog();
                  });
      }
  </code></pre>
  <p><code>Startup.cs</code>:</p>
  <pre><code>    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 =&gt;
              {
                  c.SwaggerDoc(&quot;v1&quot;, new OpenApiInfo { Title = &quot;PaymentService.API&quot;, Version = &quot;v1&quot; });
              });
  
              services.AddHttpContextAccessor();
          }
  
          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
          public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
          {
  
              app.UseMiddleware&lt;LogHeaderMiddleware&gt;();
  
              if (env.IsDevelopment())
              {
                  app.UseDeveloperExceptionPage();
                  app.UseSwagger();
                  app.UseSwaggerUI(c =&gt; c.SwaggerEndpoint(&quot;/swagger/v1/swagger.json&quot;, &quot;PaymentService.API v1&quot;));
              }
  
              app.UseHttpsRedirection();
  
              app.UseRouting();
  
              app.UseAuthorization();
  
    /*          app.Use(async (httpContext, next) =&gt; 
              {
                  var correlationId = httpContext.Session. // need to find a way to map correlationId and send it to the logs
              })*/
  
              app.UseEndpoints(endpoints =&gt;
              {
                  endpoints.MapControllers();
              });
          }
      }
  </code></pre>
  <p><code>appsettings.json</code></p>
  <pre><code>{
    &quot;ConnectionStrings&quot;: {
      &quot;Default&quot;: &quot;Data Source=.\\SQLExpress;Database=ElasticSearchService;Trusted_Connection=True;&quot;
    },
    &quot;Serilog&quot;: {
      &quot;MinimumLevel&quot;: &quot;Information&quot;,
    &quot;AllowedHosts&quot;: &quot;*&quot;
  }
  </code></pre>
  <p><code>PaymentController</code></p>
  <pre><code>[Route(&quot;api/[controller]&quot;)]
      [ApiController]
      public class PaymentController : ControllerBase
      {
  
          private readonly ILogger&lt;PaymentServicesController&gt; _logger;
  
          public PaymentServicesController(ILogger&lt;PaymentServicesController&gt; logger)
          {
              _logger = logger;
          }
  
          // GET: api/&lt;PaymentServices&gt;
          [HttpGet]
          [Route(&quot;payment&quot;)]
          public void MakePayment()
          {
  
              _logger.LogInformation(&quot;PAYMENT METHOD INVOLKED!!!&quot;);
  
  
          }
         
      }
  </code></pre>
  <p>Here <code>header</code> will hold the <code>correlationId</code> which I need so I can send it to the database.</p>
  <pre><code>public class LogHeaderMiddleware
      {
          private readonly RequestDelegate _next;
  
          public LogHeaderMiddleware(RequestDelegate next)
          {
              _next = next;
          }
  
          public async Task InvokeAsync(HttpContext context)
          {
              var header = context.Request.Headers[&quot;CorrelationId&quot;];
  
              if (header.Count &gt; 0)
              {
                  var logger = context.RequestServices.GetRequiredService&lt;ILogger&lt;LogHeaderMiddleware&gt;&gt;();
  
                  using (logger.BeginScope(&quot;{@CorrelationId}&quot;, header[0]))
                  {
                      await _next(context);
                  }
              }
              else
              {
                  await _next(context);
              }
          }
      }
  </code></pre>