Files
2026-04-20 14:47:24 -05:00

241 lines
10 KiB
C#

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<AppDbContext>(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<string>("Name"),
CronTab = x.GetValue<string>("Crontab"),
Subject = x.GetValue<string>("Subject"),
User = x.GetValue<string>("User")
});
repoApiConfig.TaskConfigs = taskConfigs.ToList().AsReadOnly();
services.AddSingleton(autoImsConfig);
services.AddSingleton(nadaServiceConfig);
services.AddSingleton(repoApiConfig);
services.AddScoped<IEnvironmentView, EnvironmentView>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.UseRepoServices();
services.UseRepoRepositories();
// DAO's, Producers, Factories.
services.AddScoped<IEmailer, Emailer>();
services.AddScoped<IFloorPricingStrategyFactory, FloorPricingStrategyFactory>();
services.AddScoped<ICoreDao, CoreDao>();
services.AddScoped<ICollectionsDao, CollectionsDao>();
services.AddScoped<IRepoAccountProcessor, RepoAccountProcessor>();
services.AddScoped<IRedemptionExpiredDateCalculator, RedemptionExpiredDateCalculator>();
services.AddScoped<AutoImsService>();
services.AddScoped<IAuctionProcessorDao, AuctionProcessorDao>();
services.AddScoped<ClientHelpers>();
/* 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<bool>(FeatureFlags.RunAutoImsHostedService))
{
// Hosted, Queues Configurations
services.AddSingleton<IQueueConnectionConfig>(queueConnectionConfig);
services.AddSingleton<IHostedTaskSchedulerConfig>(repoApiConfig);
// The Hosted Task Scheduler (Should eventually move out of this project)
services.AddHostedService<HostedTaskScheduler>();
services.AddHostedService<HostedAutoImsTaskConsumer>();
}
if (Configuration.GetSection("FeatureFlags").GetValue<bool>(FeatureFlags.RunRepoHostedService))
{
services.AddHostedService<HostedRepoTaskConsumer>();
services.AddHostedService<RepoQueueConsumerService>();
}
if (isDevelopment)
{
services.AddScoped<IAutoImsWebService, MockAutoImsWebService>();
}
else
{
services.AddScoped<IAutoImsWebService, AutoImsWebService>();
}
// 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<string, IEnumerable<string>>
{
{ "Bearer", Enumerable.Empty<string>() }
});
});
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressModelStateInvalidFilter = true;
});
//Set up Authentication
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
// AzureAD config
.AddAzureAdBearer(options => Configuration.GetSection("AzureActiveDirectory").Bind( options));
services.AddIdentity<IdentityUser, IdentityRole>()
.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();
}
}
}