Blazor using Serilog: ArgumentException: 'An item with the same key has already been added. Key: ConnectionStrings'

Viewed 31

I like to implement log data from client (WASM) into a backend file using Serilog as descripted here. At my program.cs (server app) I got already that:

            Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
        #if RELEASE
                webBuilder.UseContentRoot(Directory.GetCurrentDirectory());
                webBuilder.UseIISIntegration();
        #endif
                webBuilder.UseStartup<Startup>();
            })

When I add the code for Serilog...:

            .UseSerilog().ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })

... I get the exception:

System.ArgumentException: 'An item with the same key has already been added. Key: ConnectionStrings'

The reason is because Startup is called two times and the config data are written two times and so the keys are already been added.

Do you know a way to solve this problem?
How I should manipulate the UseSerilog().ConfigureWebHostDefaults()?
Can I just delete one of both webBuilder.UseStartup();?
(Existing logic should remain and Serilog should be added).

1 Answers

The problem is the snippet :

.UseSerilog().ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            })

Just call UseSerilog(). The host was already configured earlier in :

 Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {

ConfigureWebHostDefaults as the name says configures the Host with its default DI, configuration and logging settings. Calling it twice would be a mistake no matter what - if the defaults were applied without error, Serilog would be removed from the pipeline. In this case, the same configuration settings are added to the Configuration dictionary, resulting in an exception.

If you want to call UseSerilog before ConfigureWebHostDefaults, actually place the call before it.

This is a snippet from my own hosted Blazor WASM project. Logging.ConfigureSerilog configures Serilog to log to files and a database table. Environment.OSVersion.Platform is used because at some point I developed the project on Mac and what to deploy on Windows, so I needed a way to specify Mac-specific settings

Host.CreateDefaultBuilder(args)
    .UseSerilog(Logging.ConfigureSerilog)
    .ConfigureAppConfiguration((hostingContext, config) =>
    {
            var env = hostingContext.HostingEnvironment.EnvironmentName;
            var os = Environment.OSVersion.Platform;
            config.AddJsonFile($"appsettings.{env}.{os}.json", true);
    })
    .ConfigureWebHostDefaults(webBuilder =>
    {
        webBuilder.UseStartup<Startup>();
    });
Related