public void ConfigureServices(IServiceCollection services) { var serializationSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver(), Formatting = Formatting.None }; JsonConvert.DefaultSettings = () => serializationSettings; using var vaultClient = new VaultClient.VaultClient(new VaultOptions { BaseUrl = new Uri(EnvironmentVariableHelper.Get("Vault:Endpoint", Configuration)), Engine = Configuration["Vault:Engine"], Role = Configuration["Vault:Role"] }); vaultClient.Login(EnvironmentVariableHelper.Get("Vault:Token", Configuration)).GetAwaiter().GetResult(); services.AddResponseCompression() .AddCors() .AddLocalization() .AddMemoryCache() .AddMemoryFlow() .AddStackExchangeRedisCache(options => { var host = EnvironmentVariableHelper.Get("Redis:Endpoint", Configuration); options.ConfigurationOptions = new ConfigurationOptions { EndPoints = { new DnsEndPoint(host, 6379) }, AsyncTimeout = 15000, // set to 15 seconds before we stop storing large objects in Redis }; }) .AddDoubleFlow() .AddCacheFlowJsonSerialization() .AddTracing(Configuration, options => { options.ServiceName = $"{HostingEnvironment.ApplicationName}-{HostingEnvironment.EnvironmentName}"; options.JaegerHost = HostingEnvironment.IsLocal() ? Configuration.GetValue <string>("Jaeger:AgentHost") : Configuration.GetValue <string>(Configuration.GetValue <string>("Jaeger:AgentHost")); options.JaegerPort = HostingEnvironment.IsLocal() ? Configuration.GetValue <int>("Jaeger:AgentPort") : Configuration.GetValue <int>(Configuration.GetValue <string>("Jaeger:AgentPort")); options.RedisEndpoint = Configuration.GetValue <string>(Configuration.GetValue <string>("Redis:Endpoint")); }) .AddUserEventLogging(Configuration, vaultClient); var(apiName, authorityUrl) = GetApiNameAndAuthority(Configuration, HostingEnvironment, vaultClient); services.ConfigureServiceOptions(Configuration, HostingEnvironment, vaultClient) .ConfigureHttpClients(Configuration, HostingEnvironment, vaultClient, authorityUrl) .ConfigureAuthentication(Configuration, HostingEnvironment, apiName, authorityUrl) .AddServices(HostingEnvironment, Configuration, vaultClient); services.AddHealthChecks() .AddDbContextCheck <EdoContext>() .AddRedis(EnvironmentVariableHelper.Get("Redis:Endpoint", Configuration)) .AddCheck <ControllerResolveHealthCheck>(nameof(ControllerResolveHealthCheck)); services.AddProblemDetailsErrorHandling(); services.AddApiVersioning(options => { options.AssumeDefaultVersionWhenUnspecified = false; options.DefaultApiVersion = new ApiVersion(1, 0); options.ReportApiVersions = true; }); services.AddSwaggerGen(options => { options.SwaggerDoc("agent", new OpenApiInfo { Title = "Happytravel.com Edo API for an agent app", Version = "v1.0" }); options.SwaggerDoc("admin", new OpenApiInfo { Title = "Happytravel.com Edo API for an admin app", Version = "v1.0" }); options.SwaggerDoc("property-owner", new OpenApiInfo { Title = "Happytravel.com Edo API for property owners", Version = "v1.0" }); options.SwaggerDoc("service", new OpenApiInfo { Title = "Happytravel.com service Edo API", Version = "v1.0" }); var xmlCommentsFileName = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlCommentsFilePath = Path.Combine(AppContext.BaseDirectory, xmlCommentsFileName); options.IncludeXmlComments(xmlCommentsFilePath); options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme { Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", Name = "Authorization", In = ParameterLocation.Header, Type = SecuritySchemeType.ApiKey }); options.AddSecurityRequirement(new OpenApiSecurityRequirement() { { new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }, Scheme = "oauth2", Name = "Bearer", In = ParameterLocation.Header, }, Array.Empty <string>() } }); // Use fully qualified object names options.CustomSchemaIds(x => x.FullName); }); services.AddSwaggerGenNewtonsoftSupport(); services.AddNotificationCenter(EnvironmentVariableHelper.Get("Redis:Endpoint", Configuration)); services.AddMvcCore(options => { options.Conventions.Insert(0, new LocalizationConvention()); options.Conventions.Add(new AuthorizeControllerModelConvention()); options.Conventions.Add(new ApiExplorerGroupPerVersionConvention()); options.Filters.Add(new MiddlewareFilterAttribute(typeof(LocalizationPipelineFilter))); options.Filters.Add(typeof(ModelValidationFilter)); AddODataMediaTypes(options); }) .AddAuthorization() .AddControllersAsServices() .AddMvcOptions(m => m.EnableEndpointRouting = true) .AddFormatterMappings() .AddNewtonsoftJson(options => options.SerializerSettings.Converters.Add(new StringEnumConverter())) .AddApiExplorer() .AddCacheTagHelper() .AddDataAnnotations() .AddOData(opt => opt.Filter().Select().OrderBy().SetMaxTop(100)); }