Restructures application startup and configuration

Migrates from standalone Program.cs to Startup-based configuration
Adds application configuration JSON for environment-specific settings
Integrates Autofac dependency injection and modular service registration

Configures application services, modules, and middleware for enhanced flexibility
This commit is contained in:
Janus C. H. Knudsen 2026-01-10 20:56:29 +01:00
parent 7fc1ae0650
commit cd092f8290
4 changed files with 129 additions and 45 deletions

View file

@ -1,47 +1,14 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.RazorPages;
using PlanTempus.Application.Features.Localization.Services;
using PlanTempus.Application.Features.Menu.Services;
using Autofac.Extensions.DependencyInjection;
using PlanTempus.Application;
var builder = WebApplication.CreateBuilder(args);
// Add Razor Pages with feature-based structure
builder.Services.AddRazorPages(options =>
var host = Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webHostBuilder =>
{
options.RootDirectory = "/Features";
webHostBuilder
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>();
})
.AddRazorOptions(options =>
{
// View locations for partials and ViewComponents
options.ViewLocationFormats.Add("/Features/_Shared/Pages/{0}.cshtml");
options.ViewLocationFormats.Add("/Features/_Shared/Components/{1}/{0}.cshtml");
.Build();
});
// Register application services
builder.Services.AddScoped<IMenuService, MockMenuService>();
builder.Services.AddScoped<ILocalizationService, JsonLocalizationService>();
var app = builder.Build();
// Developer exception page for debugging
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Serve static files from wwwroot
app.UseStaticFiles();
// Configure routing
app.UseRouting();
// Map Razor Pages
app.MapRazorPages();
app.Run("http://localhost:8000");
// Note: Set ASPNETCORE_ENVIRONMENT=Development for detailed error pages
host.Run();

View file

@ -0,0 +1,93 @@
using Autofac;
using PlanTempus.Application.Features.Localization.Services;
using PlanTempus.Application.Features.Menu.Services;
using PlanTempus.Components.ModuleRegistry;
using PlanTempus.Components.Outbox;
using PlanTempus.Core.Configurations.JsonConfigProvider;
using PlanTempus.Core.Configurations;
using PlanTempus.Core.Email;
using PlanTempus.Core.ModuleRegistry;
using PlanTempus.Core.Outbox;
namespace PlanTempus.Application;
public class Startup
{
public Startup(IWebHostEnvironment env)
{
var builder = new Core.Configurations.ConfigurationBuilder()
.AddJsonFile("appconfiguration.json", optional: true, reloadOnChange: true);
ConfigurationRoot = builder.Build();
}
public Core.Configurations.IConfigurationRoot ConfigurationRoot { get; private set; }
public ILifetimeScope? AutofacContainer { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddOptions();
// Add Razor Pages with feature-based structure
services.AddRazorPages(options =>
{
options.RootDirectory = "/Features";
})
.AddRazorOptions(options =>
{
options.ViewLocationFormats.Add("/Features/_Shared/Pages/{0}.cshtml");
options.ViewLocationFormats.Add("/Features/_Shared/Components/{1}/{0}.cshtml");
});
services.AddAntiforgery(x => x.HeaderName = "X-ANTI-FORGERY-TOKEN");
}
public void ConfigureContainer(ContainerBuilder builder)
{
// Application services
builder.RegisterType<MockMenuService>().As<IMenuService>().InstancePerLifetimeScope();
builder.RegisterType<JsonLocalizationService>().As<ILocalizationService>().InstancePerLifetimeScope();
// Infrastructure modules
builder.RegisterModule(new Database.ModuleRegistry.DbPostgreSqlModule
{
ConnectionString = ConfigurationRoot.GetConnectionString("DefaultConnection")
});
builder.RegisterModule(new TelemetryModule
{
TelemetryConfig = ConfigurationRoot.GetSection("ApplicationInsights").ToObject<TelemetryConfig>()
});
builder.RegisterModule<CommandModule>();
builder.RegisterModule<OutboxModule>();
builder.RegisterModule<OutboxListenerModule>();
builder.RegisterModule(new EmailModule
{
PostmarkConfiguration = ConfigurationRoot.GetSection("Postmark").ToObject<PostmarkConfiguration>()
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseStaticFiles();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
});
}
}

View file

@ -0,0 +1,19 @@
{
"ConnectionStrings": {
"DefaultConnection": "Host=192.168.1.63;Port=5432;Database=ptmain;User Id={usr};Password={pwd};"
},
"ApplicationInsights": {
"ConnectionString": "InstrumentationKey=07d2a2b9-5e8e-4924-836e-264f8438f6c5;IngestionEndpoint=https://northeurope-2.in.applicationinsights.azure.com/;LiveEndpoint=https://northeurope.livediagnostics.monitor.azure.com/;ApplicationId=56748c39-2fa3-4880-a1e2-24068e791548",
"UseSeqLoggingTelemetryChannel": true
},
"SeqConfiguration": {
"IngestionEndpoint": "http://localhost:5341",
"ApiKey": null,
"Environment": "Development"
},
"Postmark": {
"ServerToken": "3f285ee7-1d30-48fb-ab6f-a6ae92a843e7",
"FromEmail": "janus@sevenweirdpeople.io",
"TestToEmail": "janus@sevenweirdpeople.io"
}
}

View file

@ -1,5 +1,6 @@
using Autofac;
using Microsoft.Extensions.Hosting;
using PlanTempus.Core.Telemetry;
namespace PlanTempus.Components.Outbox;
@ -7,6 +8,10 @@ public class OutboxListenerModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<NotificationChannel>()
.As<IMessageChannel<string>>()
.SingleInstance();
builder.RegisterType<OutboxListener>()
.As<IHostedService>()
.SingleInstance();