diff --git a/src/Services/Webhooks/Webhooks.API/Startup.cs b/src/Services/Webhooks/Webhooks.API/Startup.cs index 9d39da719..c3d470142 100644 --- a/src/Services/Webhooks/Webhooks.API/Startup.cs +++ b/src/Services/Webhooks/Webhooks.API/Startup.cs @@ -1,12 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Data.Common; -using System.IdentityModel.Tokens.Jwt; -using System.Linq; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Autofac; +using Autofac; using Autofac.Extensions.DependencyInjection; using HealthChecks.UI.Client; using Microsoft.ApplicationInsights.Extensibility; @@ -31,342 +23,345 @@ using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using RabbitMQ.Client; using Swashbuckle.AspNetCore.Swagger; +using System; +using System.Collections.Generic; +using System.Data.Common; +using System.IdentityModel.Tokens.Jwt; +using System.Reflection; +using System.Threading; using Webhooks.API.Infrastructure; using Webhooks.API.IntegrationEvents; using Webhooks.API.Services; namespace Webhooks.API { - public class Startup - { - public IConfiguration Configuration { get; } - - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - - public IServiceProvider ConfigureServices(IServiceCollection services) - { - services - .AddAppInsight(Configuration) - .AddCustomMVC(Configuration) - .AddCustomDbContext(Configuration) - .AddSwagger(Configuration) - .AddCustomHealthCheck(Configuration) - .AddHttpClientServices(Configuration) - .AddIntegrationServices(Configuration) - .AddEventBus(Configuration) - .AddCustomAuthentication(Configuration) - .AddSingleton() - .AddTransient() - .AddTransient() - .AddTransient() - .AddTransient(); - - var container = new ContainerBuilder(); - container.Populate(services); - return new AutofacServiceProvider(container.Build()); - } - - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) - { - loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); - - var pathBase = Configuration["PATH_BASE"]; - - if (!string.IsNullOrEmpty(pathBase)) - { - loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); - app.UsePathBase(pathBase); - } - - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - - app.UseCors("CorsPolicy"); - - ConfigureAuth(app); - - app.UseMvcWithDefaultRoute(); - - app.UseSwagger() - .UseSwaggerUI(c => - { - c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Webhooks.API V1"); - c.OAuthClientId("webhooksswaggerui"); - c.OAuthAppName("WebHooks Service Swagger UI"); - }); - - ConfigureEventBus(app); - } - - protected virtual void ConfigureAuth(IApplicationBuilder app) - { - /* - if (Configuration.GetValue("UseLoadTest")) - { - app.UseMiddleware(); - } - */ - - app.UseAuthentication(); - } - - protected virtual void ConfigureEventBus(IApplicationBuilder app) - { - var eventBus = app.ApplicationServices.GetRequiredService(); - eventBus.Subscribe(); - eventBus.Subscribe(); - eventBus.Subscribe(); - } - } - - static class CustomExtensionMethods - { - public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration) - { - services.AddApplicationInsightsTelemetry(configuration); - var orchestratorType = configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } - - return services; - } - - public static IServiceCollection AddCustomMVC(this IServiceCollection services, IConfiguration configuration) - { - services.AddMvc(options => - { - options.Filters.Add(typeof(HttpGlobalExceptionFilter)); - }) - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) - .AddControllersAsServices(); - - services.AddCors(options => - { - options.AddPolicy("CorsPolicy", - builder => builder - .SetIsOriginAllowed((host) => true) - .AllowAnyMethod() - .AllowAnyHeader() - .AllowCredentials()); - }); - - return services; - } - - public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration) - { - services.AddDbContext(options => - { - options.UseSqlServer(configuration["ConnectionString"], - sqlServerOptionsAction: sqlOptions => - { - sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); - //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency - sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); - }); - - // Changing default behavior when client evaluation occurs to throw. - // Default in EF Core would be to log a warning when client evaluation is performed. - options.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning)); - //Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval - }); - - return services; - } - - public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration) - { - services.AddSwaggerGen(options => - { - options.DescribeAllEnumsAsStrings(); - options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info - { - Title = "eShopOnContainers - Webhooks HTTP API", - Version = "v1", - Description = "The Webhooks Microservice HTTP API. This is a simple webhooks CRUD registration entrypoint", - TermsOfService = "Terms Of Service" - }); - - options.AddSecurityDefinition("oauth2", new OAuth2Scheme - { - Type = "oauth2", - Flow = "implicit", - AuthorizationUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize", - TokenUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/token", - Scopes = new Dictionary() - { - { "webhooks", "Webhooks API" } - } - }); - - options.OperationFilter(); - }); - - return services; - } - public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) - { - var subscriptionClientName = configuration["SubscriptionClientName"]; - - if (configuration.GetValue("AzureServiceBusEnabled")) - { - services.AddSingleton(sp => - { - var serviceBusPersisterConnection = sp.GetRequiredService(); - var iLifetimeScope = sp.GetRequiredService(); - var logger = sp.GetRequiredService>(); - var eventBusSubcriptionsManager = sp.GetRequiredService(); - - return new EventBusServiceBus(serviceBusPersisterConnection, logger, - eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); - }); - - } - else - { - services.AddSingleton(sp => - { - var rabbitMQPersistentConnection = sp.GetRequiredService(); - var iLifetimeScope = sp.GetRequiredService(); - var logger = sp.GetRequiredService>(); - var eventBusSubcriptionsManager = sp.GetRequiredService(); - - var retryCount = 5; - if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) - { - retryCount = int.Parse(configuration["EventBusRetryCount"]); - } - - return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); - }); - } - - services.AddSingleton(); - services.AddTransient(); - services.AddTransient(); - services.AddTransient(); - return services; - } - - public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration) - { - var accountName = configuration.GetValue("AzureStorageAccountName"); - var accountKey = configuration.GetValue("AzureStorageAccountKey"); - - var hcBuilder = services.AddHealthChecks(); - - hcBuilder - .AddCheck("self", () => HealthCheckResult.Healthy()) - .AddSqlServer( - configuration["ConnectionString"], - name: "WebhooksApiDb-check", - tags: new string[] { "webhooksdb" }); - - return services; - } - - public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration) - { - services.AddSingleton(); - services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(Timeout.InfiniteTimeSpan); - //add http client services - services.AddHttpClient("GrantClient") - .SetHandlerLifetime(TimeSpan.FromMinutes(5)); - //.AddHttpMessageHandler(); - return services; - } - - public static IServiceCollection AddIntegrationServices(this IServiceCollection services, IConfiguration configuration) - { - services.AddTransient>( - sp => (DbConnection c) => new IntegrationEventLogService(c)); - - if (configuration.GetValue("AzureServiceBusEnabled")) - { - services.AddSingleton(sp => - { - var logger = sp.GetRequiredService>(); - var serviceBusConnection = new ServiceBusConnectionStringBuilder(configuration["EventBusConnection"]); - return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger); - }); - } - else - { - services.AddSingleton(sp => - { - var logger = sp.GetRequiredService>(); - - var factory = new ConnectionFactory() - { - HostName = configuration["EventBusConnection"], - DispatchConsumersAsync = true - }; - - if (!string.IsNullOrEmpty(configuration["EventBusUserName"])) - { - factory.UserName = configuration["EventBusUserName"]; - } - - if (!string.IsNullOrEmpty(configuration["EventBusPassword"])) - { - factory.Password = configuration["EventBusPassword"]; - } - - var retryCount = 5; - if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) - { - retryCount = int.Parse(configuration["EventBusRetryCount"]); - } - - return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); - }); - } - - return services; - } - - public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) - { - // prevent from mapping "sub" claim to nameidentifier. - JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); - - var identityUrl = configuration.GetValue("IdentityUrl"); - - services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - - }).AddJwtBearer(options => - { - options.Authority = identityUrl; - options.RequireHttpsMetadata = false; - options.Audience = "webhooks"; - }); - - return services; - } - } + public class Startup + { + public IConfiguration Configuration { get; } + + public Startup(IConfiguration configuration) => Configuration = configuration; + + + public IServiceProvider ConfigureServices(IServiceCollection services) + { + services + .AddAppInsight(Configuration) + .AddCustomMVC(Configuration) + .AddCustomDbContext(Configuration) + .AddSwagger(Configuration) + .AddCustomHealthCheck(Configuration) + .AddHttpClientServices(Configuration) + .AddIntegrationServices(Configuration) + .AddEventBus(Configuration) + .AddCustomAuthentication(Configuration) + .AddSingleton() + .AddTransient() + .AddTransient() + .AddTransient() + .AddTransient(); + + var container = new ContainerBuilder(); + container.Populate(services); + return new AutofacServiceProvider(container.Build()); + } + + public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory, ILoggingBuilder loggingBuilder) + { + ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights(loggingBuilder, options => options.IncludeScopes = true); + + var pathBase = Configuration["PATH_BASE"]; + + if (!string.IsNullOrEmpty(pathBase)) + { + loggerFactory.CreateLogger("init").LogDebug($"Using PATH BASE '{pathBase}'"); + app.UsePathBase(pathBase); + } + + app.UseHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + + app.UseHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + + app.UseCors("CorsPolicy"); + + ConfigureAuth(app); + + app.UseMvcWithDefaultRoute(); + + app.UseSwagger() + .UseSwaggerUI(c => + { + c.SwaggerEndpoint($"{ (!string.IsNullOrEmpty(pathBase) ? pathBase : string.Empty) }/swagger/v1/swagger.json", "Webhooks.API V1"); + c.OAuthClientId("webhooksswaggerui"); + c.OAuthAppName("WebHooks Service Swagger UI"); + }); + + ConfigureEventBus(app); + } + + protected virtual void ConfigureAuth(IApplicationBuilder app) + { + /* + if (Configuration.GetValue("UseLoadTest")) + { + app.UseMiddleware(); + } + */ + + app.UseAuthentication(); + } + + protected virtual void ConfigureEventBus(IApplicationBuilder app) + { + var eventBus = app.ApplicationServices.GetRequiredService(); + eventBus.Subscribe(); + eventBus.Subscribe(); + eventBus.Subscribe(); + } + } + + static class CustomExtensionMethods + { + public static IServiceCollection AddAppInsight(this IServiceCollection services, IConfiguration configuration) + { + services.AddApplicationInsightsTelemetry(configuration); + var orchestratorType = configuration.GetValue("OrchestratorType"); + + if (orchestratorType?.ToUpper() == "K8S") + { + // Enable K8s telemetry initializer + services.AddApplicationInsightsKubernetesEnricher(); + } + if (orchestratorType?.ToUpper() == "SF") + { + // Enable SF telemetry initializer + services.AddSingleton((serviceProvider) => + new FabricTelemetryInitializer()); + } + + return services; + } + + public static IServiceCollection AddCustomMVC(this IServiceCollection services, IConfiguration configuration) + { + services.AddMvc(options => + { + options.Filters.Add(typeof(HttpGlobalExceptionFilter)); + }) + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) + .AddControllersAsServices(); + + services.AddCors(options => + { + options.AddPolicy("CorsPolicy", + builder => builder + .SetIsOriginAllowed((host) => true) + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials()); + }); + + return services; + } + + public static IServiceCollection AddCustomDbContext(this IServiceCollection services, IConfiguration configuration) + { + services.AddDbContext(options => + { + options.UseSqlServer(configuration["ConnectionString"], + sqlServerOptionsAction: sqlOptions => + { + sqlOptions.MigrationsAssembly(typeof(Startup).GetTypeInfo().Assembly.GetName().Name); + //Configuring Connection Resiliency: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency + sqlOptions.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorNumbersToAdd: null); + }); + + // Changing default behavior when client evaluation occurs to throw. + // Default in EF Core would be to log a warning when client evaluation is performed. + options.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning)); + //Check Client vs. Server evaluation: https://docs.microsoft.com/en-us/ef/core/querying/client-eval + }); + + return services; + } + + public static IServiceCollection AddSwagger(this IServiceCollection services, IConfiguration configuration) + { + services.AddSwaggerGen(options => + { + options.DescribeAllEnumsAsStrings(); + options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info + { + Title = "eShopOnContainers - Webhooks HTTP API", + Version = "v1", + Description = "The Webhooks Microservice HTTP API. This is a simple webhooks CRUD registration entrypoint", + TermsOfService = "Terms Of Service" + }); + + options.AddSecurityDefinition("oauth2", new OAuth2Scheme + { + Type = "oauth2", + Flow = "implicit", + AuthorizationUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/authorize", + TokenUrl = $"{configuration.GetValue("IdentityUrlExternal")}/connect/token", + Scopes = new Dictionary() + { + { "webhooks", "Webhooks API" } + } + }); + + options.OperationFilter(); + }); + + return services; + } + public static IServiceCollection AddEventBus(this IServiceCollection services, IConfiguration configuration) + { + var subscriptionClientName = configuration["SubscriptionClientName"]; + + if (configuration.GetValue("AzureServiceBusEnabled")) + { + services.AddSingleton(sp => + { + var serviceBusPersisterConnection = sp.GetRequiredService(); + var iLifetimeScope = sp.GetRequiredService(); + var logger = sp.GetRequiredService>(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); + + return new EventBusServiceBus(serviceBusPersisterConnection, logger, + eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope); + }); + + } + else + { + services.AddSingleton(sp => + { + var rabbitMQPersistentConnection = sp.GetRequiredService(); + var iLifetimeScope = sp.GetRequiredService(); + var logger = sp.GetRequiredService>(); + var eventBusSubcriptionsManager = sp.GetRequiredService(); + + var retryCount = 5; + if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) + { + retryCount = int.Parse(configuration["EventBusRetryCount"]); + } + + return new EventBusRabbitMQ(rabbitMQPersistentConnection, logger, iLifetimeScope, eventBusSubcriptionsManager, subscriptionClientName, retryCount); + }); + } + + services.AddSingleton(); + services.AddTransient(); + services.AddTransient(); + services.AddTransient(); + return services; + } + + public static IServiceCollection AddCustomHealthCheck(this IServiceCollection services, IConfiguration configuration) + { + var accountName = configuration.GetValue("AzureStorageAccountName"); + var accountKey = configuration.GetValue("AzureStorageAccountKey"); + + var hcBuilder = services.AddHealthChecks(); + + hcBuilder + .AddCheck("self", () => HealthCheckResult.Healthy()) + .AddSqlServer( + configuration["ConnectionString"], + name: "WebhooksApiDb-check", + tags: new string[] { "webhooksdb" }); + + return services; + } + + public static IServiceCollection AddHttpClientServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddSingleton(); + services.AddHttpClient("extendedhandlerlifetime").SetHandlerLifetime(Timeout.InfiniteTimeSpan); + //add http client services + services.AddHttpClient("GrantClient") + .SetHandlerLifetime(TimeSpan.FromMinutes(5)); + //.AddHttpMessageHandler(); + return services; + } + + public static IServiceCollection AddIntegrationServices(this IServiceCollection services, IConfiguration configuration) + { + services.AddTransient>( + sp => (DbConnection c) => new IntegrationEventLogService(c)); + + if (configuration.GetValue("AzureServiceBusEnabled")) + { + services.AddSingleton(sp => + { + var logger = sp.GetRequiredService>(); + var serviceBusConnection = new ServiceBusConnectionStringBuilder(configuration["EventBusConnection"]); + return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger); + }); + } + else + { + services.AddSingleton(sp => + { + var logger = sp.GetRequiredService>(); + + var factory = new ConnectionFactory() + { + HostName = configuration["EventBusConnection"], + DispatchConsumersAsync = true + }; + + if (!string.IsNullOrEmpty(configuration["EventBusUserName"])) + { + factory.UserName = configuration["EventBusUserName"]; + } + + if (!string.IsNullOrEmpty(configuration["EventBusPassword"])) + { + factory.Password = configuration["EventBusPassword"]; + } + + var retryCount = 5; + if (!string.IsNullOrEmpty(configuration["EventBusRetryCount"])) + { + retryCount = int.Parse(configuration["EventBusRetryCount"]); + } + + return new DefaultRabbitMQPersistentConnection(factory, logger, retryCount); + }); + } + + return services; + } + + public static IServiceCollection AddCustomAuthentication(this IServiceCollection services, IConfiguration configuration) + { + // prevent from mapping "sub" claim to nameidentifier. + JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub"); + + var identityUrl = configuration.GetValue("IdentityUrl"); + + services.AddAuthentication(options => + { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; + + }).AddJwtBearer(options => + { + options.Authority = identityUrl; + options.RequireHttpsMetadata = false; + options.Audience = "webhooks"; + }); + + return services; + } + } } \ No newline at end of file diff --git a/src/Web/WebSPA/Startup.cs b/src/Web/WebSPA/Startup.cs index 7a418c432..a23bd0c0b 100644 --- a/src/Web/WebSPA/Startup.cs +++ b/src/Web/WebSPA/Startup.cs @@ -1,161 +1,160 @@ using eShopOnContainers.WebSPA; +using HealthChecks.UI.Client; using Microsoft.ApplicationInsights.Extensibility; using Microsoft.ApplicationInsights.ServiceFabric; using Microsoft.AspNetCore.Antiforgery; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.Diagnostics.HealthChecks; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; using Microsoft.Extensions.Logging; using Newtonsoft.Json.Serialization; using StackExchange.Redis; using System; using System.IO; using WebSPA.Infrastructure; -using HealthChecks.UI.Client; -using Microsoft.AspNetCore.Diagnostics.HealthChecks; -using Microsoft.Extensions.Diagnostics.HealthChecks; namespace eShopConContainers.WebSPA { - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - private IHostingEnvironment _hostingEnv; - public Startup(IHostingEnvironment env) - { - _hostingEnv = env; - - var localPath = new Uri(Configuration["ASPNETCORE_URLS"])?.LocalPath ?? "/"; - Configuration["BaseUrl"] = localPath; - } - - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 - public void ConfigureServices(IServiceCollection services) - { - RegisterAppInsights(services); - - services.AddHealthChecks() - .AddCheck("self", () => HealthCheckResult.Healthy()) - .AddUrlGroup(new Uri(Configuration["PurchaseUrlHC"]), name: "purchaseapigw-check", tags: new string[] { "purchaseapigw" }) - .AddUrlGroup(new Uri(Configuration["MarketingUrlHC"]), name: "marketingapigw-check", tags: new string[] { "marketingapigw" }) - .AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }); - - services.Configure(Configuration); - - if (Configuration.GetValue("IsClusterEnv") == bool.TrueString) - { - services.AddDataProtection(opts => - { - opts.ApplicationDiscriminator = "eshop.webspa"; - }) - .PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys"); - } - - services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); - - services.AddMvc() - .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) - .AddJsonOptions(options => - { - options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); - }); - } - - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IAntiforgery antiforgery) - { - loggerFactory.AddApplicationInsights(app.ApplicationServices, LogLevel.Trace); - - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } - - app.UseHealthChecks("/liveness", new HealthCheckOptions - { - Predicate = r => r.Name.Contains("self") - }); - - app.UseHealthChecks("/hc", new HealthCheckOptions() - { - Predicate = _ => true, - ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse - }); - - // Configure XSRF middleware, This pattern is for SPA style applications where XSRF token is added on Index page - // load and passed back token on every subsequent async request - // app.Use(async (context, next) => - // { - // if (string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase)) - // { - // var tokens = antiforgery.GetAndStoreTokens(context); - // context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false }); - // } - // await next.Invoke(); - // }); - - //Seed Data - WebContextSeed.Seed(app, env, loggerFactory); - - var pathBase = Configuration["PATH_BASE"]; - if (!string.IsNullOrEmpty(pathBase)) - { - loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase); - app.UsePathBase(pathBase); - } - - app.Use(async (context, next) => - { - await next(); - - // If there's no available file and the request doesn't contain an extension, we're probably trying to access a page. - // Rewrite request to use app root - if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/api")) - { - context.Request.Path = "/index.html"; - context.Response.StatusCode = 200; // Make sure we update the status code, otherwise it returns 404 - await next(); - } - }); - - app.UseDefaultFiles(); - app.UseStaticFiles(); - - app.UseMvcWithDefaultRoute(); - } - - private void RegisterAppInsights(IServiceCollection services) - { - services.AddApplicationInsightsTelemetry(Configuration); - var orchestratorType = Configuration.GetValue("OrchestratorType"); - - if (orchestratorType?.ToUpper() == "K8S") - { - // Enable K8s telemetry initializer - services.AddApplicationInsightsKubernetesEnricher(); - } - if (orchestratorType?.ToUpper() == "SF") - { - // Enable SF telemetry initializer - services.AddSingleton((serviceProvider) => - new FabricTelemetryInitializer()); - } - } - } + public class Startup + { + public Startup(IConfiguration configuration) + => Configuration = configuration; + + public IConfiguration Configuration { get; } + + private readonly IHostingEnvironment _hostingEnv; + public Startup(IHostingEnvironment env) + { + _hostingEnv = env; + + var localPath = new Uri(Configuration["ASPNETCORE_URLS"])?.LocalPath ?? "/"; + Configuration["BaseUrl"] = localPath; + } + + // This method gets called by the runtime. Use this method to add services to the container. + // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 + public void ConfigureServices(IServiceCollection services) + { + RegisterAppInsights(services); + + services.AddHealthChecks() + .AddCheck("self", () => HealthCheckResult.Healthy()) + .AddUrlGroup(new Uri(Configuration["PurchaseUrlHC"]), name: "purchaseapigw-check", tags: new string[] { "purchaseapigw" }) + .AddUrlGroup(new Uri(Configuration["MarketingUrlHC"]), name: "marketingapigw-check", tags: new string[] { "marketingapigw" }) + .AddUrlGroup(new Uri(Configuration["IdentityUrlHC"]), name: "identityapi-check", tags: new string[] { "identityapi" }); + + services.Configure(Configuration); + + if (Configuration.GetValue("IsClusterEnv") == bool.TrueString) + { + services.AddDataProtection(opts => + { + opts.ApplicationDiscriminator = "eshop.webspa"; + }) + .PersistKeysToRedis(ConnectionMultiplexer.Connect(Configuration["DPConnectionString"]), "DataProtection-Keys"); + } + + services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); + + services.AddMvc() + .SetCompatibilityVersion(CompatibilityVersion.Version_2_2) + .AddJsonOptions(options => + { + options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + }); + } + + + // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. + public void Configure(IApplicationBuilder app, IHostingEnvironment env, Microsoft.Extensions.Logging.ILoggerFactory loggerFactory, IAntiforgery antiforgery, ILoggingBuilder loggingBuilder) + { + ApplicationInsightsLoggingBuilderExtensions.AddApplicationInsights(loggingBuilder, options => options.IncludeScopes = true); + + + if (env.IsDevelopment()) + { + app.UseDeveloperExceptionPage(); + } + else + { + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseHealthChecks("/liveness", new HealthCheckOptions + { + Predicate = r => r.Name.Contains("self") + }); + + app.UseHealthChecks("/hc", new HealthCheckOptions() + { + Predicate = _ => true, + ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse + }); + + // Configure XSRF middleware, This pattern is for SPA style applications where XSRF token is added on Index page + // load and passed back token on every subsequent async request + // app.Use(async (context, next) => + // { + // if (string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase)) + // { + // var tokens = antiforgery.GetAndStoreTokens(context); + // context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false }); + // } + // await next.Invoke(); + // }); + + //Seed Data + WebContextSeed.Seed(app, env, loggerFactory); + + var pathBase = Configuration["PATH_BASE"]; + if (!string.IsNullOrEmpty(pathBase)) + { + loggerFactory.CreateLogger().LogDebug("Using PATH BASE '{pathBase}'", pathBase); + app.UsePathBase(pathBase); + } + + app.Use(async (context, next) => + { + await next(); + + // If there's no available file and the request doesn't contain an extension, we're probably trying to access a page. + // Rewrite request to use app root + if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/api")) + { + context.Request.Path = "/index.html"; + context.Response.StatusCode = 200; // Make sure we update the status code, otherwise it returns 404 + await next(); + } + }); + + app.UseDefaultFiles(); + app.UseStaticFiles(); + + app.UseMvcWithDefaultRoute(); + } + + private void RegisterAppInsights(IServiceCollection services) + { + services.AddApplicationInsightsTelemetry(Configuration); + var orchestratorType = Configuration.GetValue("OrchestratorType"); + + if (orchestratorType?.ToUpper() == "K8S") + { + // Enable K8s telemetry initializer + services.AddApplicationInsightsKubernetesEnricher(); + } + if (orchestratorType?.ToUpper() == "SF") + { + // Enable SF telemetry initializer + services.AddSingleton((serviceProvider) => + new FabricTelemetryInitializer()); + } + } + } }