protected virtual void ConfigureServices(IServiceCollection services, IConfiguration configuration, IHostEnvironment hostEnvironment, params Assembly[] assemblies) { var logger = new SerilogLoggerFactory(Log.Logger).CreateLogger <Host>(); logger.LogInformation("Starting service configuration of {appName}", appName); var redisConnectionString = configuration.GetValue("REDIS_CONNECTIONSTRING", string.Empty); if (!string.IsNullOrEmpty(redisConnectionString)) { logger.LogInformation("Configuring Redis cache"); services.AddStackExchangeRedisCache(options => { options.Configuration = redisConnectionString; }); services.AddDataProtection() .SetApplicationName(appName) .PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect(redisConnectionString), $"{appName}-data-protection-keys"); services.AddSingleton <IDistributedSemaphoreProvider>(new RedisDistributedSynchronizationProvider(ConnectionMultiplexer.Connect(redisConnectionString).GetDatabase())); } else { logger.LogInformation("Configuring in-memory cache"); var dataProtectionPath = configuration.GetValue("KEY_RING_PATH", string.Empty); services.AddDistributedMemoryCache(); var dpBuilder = services.AddDataProtection() .SetApplicationName(appName); if (!string.IsNullOrEmpty(dataProtectionPath)) { dpBuilder.PersistKeysToFileSystem(new DirectoryInfo(dataProtectionPath)); } services.AddSingleton <IDistributedSemaphoreProvider>(new WaitHandleDistributedSynchronizationProvider()); } services.AddDefaultHealthChecks(); services .AddHttpContextAccessor() .AddResponseCompression(opts => opts.EnableForHttps = true); var mvcBuilder = services.AddControllers(); foreach (var assembly in assemblies) { mvcBuilder.AddApplicationPart(assembly).AddControllersAsServices(); } services.AddAutoMapper((sp, cfg) => { cfg.ConstructServicesUsing(t => sp.GetRequiredService(t)); }, assemblies); services.AddCors(opts => opts.AddDefaultPolicy(policy => { // try to get array of origins from section array var corsOrigins = configuration.GetSection("cors:origins").GetChildren().Select(c => c.Value).ToArray(); // try to get array of origins from value if (!corsOrigins.Any()) { corsOrigins = configuration.GetValue("cors:origins", string.Empty).Split(','); } corsOrigins = corsOrigins.Where(o => !string.IsNullOrWhiteSpace(o)).ToArray(); if (corsOrigins.Any()) { policy.SetIsOriginAllowedToAllowWildcardSubdomains().WithOrigins(corsOrigins); } })); services.Configure <ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.All; options.KnownNetworks.Clear(); options.KnownProxies.Clear(); }); services.Configure <ExceptionHandlerOptions>(opts => opts.AllowStatusCode404Response = true); services.ConfigureComponentServices(configuration, hostEnvironment, logger, assemblies); services.AddOpenTelemetry(appName); // add background tasks if (configuration.GetValue("backgroundTask:enabled", true)) { logger.LogInformation("Background tasks are enabled"); services.AddBackgroundTasks(logger, assemblies); } else { logger.LogWarning("Background tasks are disabled and not registered"); } // add version providers services.AddTransient <IVersionInformationProvider, HostVersionInformationProvider>(); }