using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using LCU.API.Collections.RepoApi.Configuration; using LCU.API.Collections.RepoApi.DataAccess; using LCU.API.Collections.RepoApi.Domain; using LCU.API.Collections.RepoApi.Domain.FloorPricing; using LCU.API.Collections.RepoApi.Extensions; using LCU.API.Collections.RepoApi.HostedServices; using LCU.API.Collections.RepoApi.MockServices; using LCU.API.Collections.RepoApi.Services; using LCU.API.Collections.RepoApi.Services.AutoIms; using LCU.API.Collections.RepoApi.Services.Producer; using LCU.Shared.Collections.RepoApiLib.Models; using LCU.Shared.Collections.RepoApiLib.Persistence; using LCU.Shared.Collections.RepoApiLib.Repositories; using LCU.Shared.Collections.RepoApiLib.Security; using LCU.Shared.Collections.RepoApiLib.WebServices.AutoIMS; using LCU.Shared.Collections.RepoApiLib.WebServices.NADA; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Swashbuckle.AspNetCore.Swagger; using LCU.API.Collections.RepoApi.Models; using LCU.Shared.Realtime.QueueLib.Models; using LCU.Shared.Realtime.QueueLib.Scheduler; using Microsoft.FeatureManagement; using LCU.Shared.Collections.RepoApiLib.Utilities; namespace LCU.API.Collections.RepoApi { [ExcludeFromCodeCoverage] public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { SqlOptionsConfig sqlOptionsConfig = new SqlOptionsConfig(); Configuration.GetSection("Connections").GetSection("SQL").GetSection("SQLOptions").Bind(sqlOptionsConfig); services.AddDbContext(options => { options.UseSqlServer( Configuration.GetSection("Connections").GetSection("SQL").GetSection("RepoDB").Value, sqlServerOptionsAction: sqlOptions => { sqlOptions.EnableRetryOnFailure( maxRetryCount: sqlOptionsConfig.MaxRetryCount, maxRetryDelay: sqlOptionsConfig.MaxRetryDelay, errorNumbersToAdd: sqlOptionsConfig.ErrorNumbersToAdd); }); options.EnableDetailedErrors(sqlOptionsConfig.EnableDetailedErrors); }); AppCorsConfig appConnections = new AppCorsConfig(); Configuration.GetSection("Connections").Bind(appConnections); var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); var isDevelopment = environment == EnvironmentName.Development || environment == EnvironmentName.Staging; services.AddCors(options => { options.AddPolicy(MyAllowSpecificOrigins, builder => { builder.WithOrigins( appConnections.CORS_AllowedOrigins ).AllowAnyHeader().AllowAnyMethod(); }); }); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); services.AddMvc().AddJsonOptions(options => { options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; }); IQueueConnectionConfig queueConnectionConfig = new QueueConnectionConfig(); Configuration.GetSection("Connections").GetSection("Queue").Bind(queueConnectionConfig); CollateralValueServiceConfig nadaServiceConfig = new CollateralValueServiceConfig(); Configuration.GetSection("NadaService").Bind(nadaServiceConfig); AutoImsServiceConfig autoImsConfig = new AutoImsServiceConfig(); Configuration.GetSection("AutoIms").Bind(autoImsConfig); var repoApiConfig = new RepoApiConfiguration(); Configuration.GetSection("primary").Bind(repoApiConfig); var taskConfigs = Configuration.GetSection("Schedule:Configs") .GetChildren() .ToList() .Select(x => new ScheduledTaskConfig() { Name = x.GetValue("Name"), CronTab = x.GetValue("Crontab"), Subject = x.GetValue("Subject"), User = x.GetValue("User") }); repoApiConfig.TaskConfigs = taskConfigs.ToList().AsReadOnly(); services.AddSingleton(autoImsConfig); services.AddSingleton(nadaServiceConfig); services.AddSingleton(repoApiConfig); services.AddScoped(); services.AddScoped(); services.UseRepoServices(); services.UseRepoRepositories(); // DAO's, Producers, Factories. services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); /* This is not the right way to do feature flags, as this cannot be dynamically changed after startup. Until we add IFeatureManager to the queue lib, we will be unable to disable the HostedTaskScheduler With feature flags. */ if (Configuration.GetSection("FeatureFlags").GetValue(FeatureFlags.RunAutoImsHostedService)) { // Hosted, Queues Configurations services.AddSingleton(queueConnectionConfig); services.AddSingleton(repoApiConfig); // The Hosted Task Scheduler (Should eventually move out of this project) services.AddHostedService(); services.AddHostedService(); } if (Configuration.GetSection("FeatureFlags").GetValue(FeatureFlags.RunRepoHostedService)) { services.AddHostedService(); services.AddHostedService(); } if (isDevelopment) { services.AddScoped(); } else { services.AddScoped(); } // Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new Info { Title = "Repo Management API", Version = "v1" }); c.DescribeAllEnumsAsStrings(); // For this to work, I also had to check the generate xml box in build options. var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); c.IncludeXmlComments(xmlPath); c.AddSecurityDefinition("Bearer", new ApiKeyScheme { Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"", Name = "Authorization", In = "header", Type = "apiKey" }); c.AddSecurityRequirement(new Dictionary> { { "Bearer", Enumerable.Empty() } }); }); services.Configure(options => { options.SuppressModelStateInvalidFilter = true; }); //Set up Authentication services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) // AzureAD config .AddAzureAdBearer(options => Configuration.GetSection("AzureActiveDirectory").Bind( options)); services.AddIdentity() .AddDefaultTokenProviders(); services.AddHttpClient(); //https://docs.microsoft.com/en-us/azure/azure-app-configuration/use-feature-flags-dotnet-core?tabs=core5x services.AddFeatureManagement(Configuration.GetSection("FeatureFlags")); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseSwagger(); app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Repo Management API"); }); 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.UseAuthentication(); app.UseCors(MyAllowSpecificOrigins); app.UseHttpsRedirection(); app.UseMvc(); } } }