namespace Microsoft.eShopOnContainers.Services.Catalog.API { using Autofac; using Autofac.Extensions.DependencyInjection; using global::Catalog.API.Infrastructure.Filters; using global::Catalog.API.IntegrationEvents; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Azure.ServiceBus; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus; using Microsoft.eShopOnContainers.BuildingBlocks.EventBus.Abstractions; using Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ; using Microsoft.eShopOnContainers.BuildingBlocks.EventBusServiceBus; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF; using Microsoft.eShopOnContainers.BuildingBlocks.IntegrationEventLogEF.Services; using Microsoft.eShopOnContainers.Services.Catalog.API.Infrastructure; using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.EventHandling; using Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.HealthChecks; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using RabbitMQ.Client; using System; using System.Data.Common; using System.Reflection; public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public IServiceProvider ConfigureServices(IServiceCollection services) { // Add framework services. services.AddApplicationInsightsTelemetry(Configuration); if (Configuration.GetValue("OrchestratorType").Equals("K8S")) { // Enable K8s telemetry initializer services.EnableKubernetes(); } services.AddHealthChecks(checks => { var minutes = 1; if (int.TryParse(Configuration["HealthCheck:Timeout"], out var minutesParsed)) { minutes = minutesParsed; } checks.AddSqlCheck("CatalogDb", Configuration["ConnectionString"], TimeSpan.FromMinutes(minutes)); var accountName = Configuration.GetValue("AzureStorageAccountName"); var accountKey = Configuration.GetValue("AzureStorageAccountKey"); if (!string.IsNullOrEmpty(accountName) && !string.IsNullOrEmpty(accountKey)) { checks.AddAzureBlobStorageCheck(accountName, accountKey); } }); services.AddMvc(options => { options.Filters.Add(typeof(HttpGlobalExceptionFilter)); }).AddControllersAsServices(); 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 }); 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); }); }); services.Configure(Configuration); // Add framework services. services.AddSwaggerGen(options => { options.DescribeAllEnumsAsStrings(); options.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info { Title = "eShopOnContainers - Catalog HTTP API", Version = "v1", Description = "The Catalog Microservice HTTP API. This is a Data-Driven/CRUD microservice sample", TermsOfService = "Terms Of Service" }); }); services.AddCors(options => { options.AddPolicy("CorsPolicy", builder => builder.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader() .AllowCredentials()); }); services.AddTransient>( sp => (DbConnection c) => new IntegrationEventLogService(c)); services.AddTransient(); if (Configuration.GetValue("AzureServiceBusEnabled")) { services.AddSingleton(sp => { var settings = sp.GetRequiredService>().Value; var logger = sp.GetRequiredService>(); var serviceBusConnection = new ServiceBusConnectionStringBuilder(settings.EventBusConnection); return new DefaultServiceBusPersisterConnection(serviceBusConnection, logger); }); } else { services.AddSingleton(sp => { var settings = sp.GetRequiredService>().Value; var logger = sp.GetRequiredService>(); var factory = new ConnectionFactory() { HostName = Configuration["EventBusConnection"] }; 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); }); } RegisterEventBus(services); var container = new ContainerBuilder(); container.Populate(services); return new AutofacServiceProvider(container.Build()); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { //Configure logs loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); loggerFactory.AddAzureWebAppDiagnostics(); 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.UseCors("CorsPolicy"); app.UseMvcWithDefaultRoute(); app.UseSwagger() .UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); }); ConfigureEventBus(app); } private void RegisterEventBus(IServiceCollection services) { if (Configuration.GetValue("AzureServiceBusEnabled")) { services.AddSingleton(sp => { var serviceBusPersisterConnection = sp.GetRequiredService(); var iLifetimeScope = sp.GetRequiredService(); var logger = sp.GetRequiredService>(); var eventBusSubcriptionsManager = sp.GetRequiredService(); var subscriptionClientName = Configuration["SubscriptionClientName"]; 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, retryCount); }); } services.AddSingleton(); services.AddTransient(); services.AddTransient(); } protected virtual void ConfigureEventBus(IApplicationBuilder app) { var eventBus = app.ApplicationServices.GetRequiredService(); eventBus.Subscribe(); eventBus.Subscribe(); } } }