-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathProgram.cs
More file actions
146 lines (137 loc) · 5.93 KB
/
Program.cs
File metadata and controls
146 lines (137 loc) · 5.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Set up a try block to handle any exceptions during startup
try
{
// Create a WebApplication builder with command-line arguments
var builder = WebApplication.CreateBuilder(args);
// Configure and initialize Serilog for logging
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.Enrich.FromLogContext()
.CreateLogger();
// Use Serilog as the logging provider
builder.Host.UseSerilog(Log.Logger);
// Log information about application startup
Log.Information("Application startup services registration");
// Register application services
builder.Services.AddApplicationLayer();
builder.Services.AddPersistenceInfrastructure(builder.Configuration);
builder.Services.AddSharedInfrastructure(builder.Configuration);
// Register Ollama chat client (IChatClient) — used by OllamaAiService
// AiController is gated by [FeatureGate("AiEnabled")], so no calls are made when AI is disabled
builder.Services.AddEasyCachingInfrastructure(builder.Configuration);
builder.Services.AddHttpContextAccessor();
builder.Services.AddScoped<ICacheDiagnosticsPublisher, HttpCacheDiagnosticsPublisher>();
builder.Services.AddSingleton<ICacheStatsCollector, CacheStatsCollector>();
builder.Services.AddSwaggerExtension();
builder.Services.AddControllersExtension(builder.Configuration);
// Configure CORS policies
builder.Services.AddCorsExtension(builder.Configuration, builder.Environment);
// Add Health Checks service
builder.Services.AddHealthChecks();
builder.Services.AddFeatureManagement();
builder.Services.AddScoped<IAuthorizationHandler, AuthEnabledRequirementHandler>();
var authEnabled = builder.Configuration.GetSection("FeatureManagement").GetValue<bool>("AuthEnabled");
var adminRole = builder.Configuration["ApiRoles:AdminRole"];
var managerRole = builder.Configuration["ApiRoles:ManagerRole"];
var employeeRole = builder.Configuration["ApiRoles:EmployeeRole"];
builder.Services.AddAuthorization(options =>
{
options.DefaultPolicy = authEnabled
? new AuthorizationPolicyBuilder().AddRequirements(new AuthEnabledRequirement()).Build()
: new AuthorizationPolicyBuilder().RequireAssertion(_ => true).Build();
if (authEnabled)
{
options.AddPolicy(AuthorizationConsts.AdminPolicy, policy => policy.RequireRole(adminRole));
options.AddPolicy(AuthorizationConsts.ManagerPolicy, policy => policy.RequireRole(managerRole, adminRole));
options.AddPolicy(AuthorizationConsts.EmployeePolicy, policy => policy.RequireRole(employeeRole, managerRole, adminRole));
}
else
{
options.AddPolicy(AuthorizationConsts.AdminPolicy, policy => policy.RequireAssertion(_ => true));
options.AddPolicy(AuthorizationConsts.ManagerPolicy, policy => policy.RequireAssertion(_ => true));
options.AddPolicy(AuthorizationConsts.EmployeePolicy, policy => policy.RequireAssertion(_ => true));
}
});
// Set up API security with JWT when auth is enabled
if (authEnabled)
{
builder.Services.AddJWTAuthentication(builder.Configuration);
}
// Add API versioning extension
builder.Services.AddApiVersioningExtension();
// Add API explorer for Swagger
builder.Services.AddMvcCore().AddApiExplorer();
// Add versioned API explorer extension
builder.Services.AddVersionedApiExplorerExtension();
// Build the application
var app = builder.Build();
// Log information about middleware registration
Log.Information("Application startup middleware registration");
// Environment-specific configuration
if (app.Environment.IsDevelopment())
{
// Use Developer Exception Page in development
app.UseDeveloperExceptionPage();
// Ensure the database is created and seed initial data during development
using (var scope = app.Services.CreateScope())
{
var dbContext = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
// Ensure the database is created and seed data when enabled and currently empty
dbContext.Database.EnsureCreated();
var skipDbSeed = builder.Configuration.GetValue<bool>("SkipDbSeed");
var needsSeed = !dbContext.Departments.Any() || !dbContext.Employees.Any();
if (!skipDbSeed && needsSeed)
{
DbInitializer.SeedData(dbContext);
}
}
}
else
{
// Use Exception Handler and HSTS in non-development environments
app.UseExceptionHandler("/Error");
app.UseHsts();
}
// Log HTTP requests using Serilog
app.UseSerilogRequestLogging();
// Redirect HTTP requests to HTTPS
app.UseHttpsRedirection();
// Configure request routing
app.UseRouting();
app.UseRequestTimingMiddleware();
// Enable configured CORS policy ("AllowAll" in this case)
app.UseCors("AllowAll");
// Use Authentication middleware
app.UseAuthentication();
app.UseCacheBypassMiddleware();
// Use Authorization middleware
app.UseAuthorization();
// Enable Swagger for API documentation
app.UseSwaggerExtension();
// Use custom error handling middleware
app.UseErrorHandlingMiddleware();
// Configure Health Checks endpoint
app.UseHealthChecks("/health");
// Map controllers for endpoints
app.MapControllers();
// Log information that the application is starting
Log.Information("Application Starting");
// Run the application
app.Run();
}
// Catch any exception that occurs during startup
catch (Exception ex)
{
// Log warning with exception details
Log.Warning(ex, "An error occurred starting the application");
throw;
}
// Ensure the log is flushed properly
finally
{
Log.CloseAndFlush();
}
/// <summary>
/// Partial Program class exposed for functional testing.
/// </summary>
public partial class Program { }