Something went wrong. Try again.
A personal wiki written in .NET
Something went wrong. Try again.
5.1 kB · 141 lines
C#
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141using System;using System.IO;using Dapper;using DotEnv.Core;using Microsoft.AspNetCore.Authentication.Cookies;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.DataProtection;using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.HttpOverrides;using Microsoft.Extensions.Caching.Memory;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Microsoft.Extensions.Logging;using Migrato.Core;using Migrato.Sqlite;using MiniWiki.Data;using MiniWiki.Data.Documents;using MiniWiki.Data.Sessions;using MiniWiki.Data.Settings;using MiniWiki.Data.Tags;using MiniWiki.Data.Users;using MiniWiki.Web.Auth;using MiniWiki.Web.Documents;using MiniWiki.Web.Settings;using MiniWiki.Web.Tags;using MiniWiki.Web.Users;
// make dapper honor snake_case columnsDefaultTypeMap.MatchNamesWithUnderscores = true;
var builder = WebApplication.CreateBuilder(args);new EnvLoader().Load();builder.Configuration.AddEnvironmentVariables();
builder.Services.AddRazorComponents();builder.Services.AddControllers();builder.Services.AddHttpContextAccessor();
builder.Logging.AddConsole();
builder.Logging.SetMinimumLevel(builder.Environment.IsDevelopment() ? LogLevel.Trace : LogLevel.Information);
// Microsoft.AspNetCore logs are chatty AF. Don't allow INFO logs from MS in non-dev situations.builder.Logging.AddFilter("Microsoft.AspNetCore", level => level is LogLevel.Critical or LogLevel.Error or LogLevel.Warning);
builder.WebHost.ConfigureKestrel(options =>{ var port = Environment.GetEnvironmentVariable("MW_PORT") ?? "8080"; options.ListenAnyIP(int.Parse(port));});
var dbPath = Environment.GetEnvironmentVariable("MW_DB_PATH") ?? "/app/mw.db";
builder.Services.AddMemoryCache();
builder.Services.AddSingleton<IDbConnectionFactory>(new SqliteConnectionFactory($"Data Source={dbPath}")) .AddSingleton<ISettingsRepository>(sp => new SettingsCachingRepository(new SettingsDatabaseRepository(sp.GetRequiredService<IDbConnectionFactory>()), sp.GetRequiredService<IMemoryCache>())) .AddSingleton<IUsersRepository>(sp => new UsersCachingRepository(new UsersDatabaseRepository(sp.GetRequiredService<IDbConnectionFactory>()), sp.GetRequiredService<IMemoryCache>())) .AddSingleton<ISessionsRepository>(sp => new SessionsCachingRepository(new SessionsDatabaseRepository(sp.GetRequiredService<IDbConnectionFactory>()), sp.GetRequiredService<IMemoryCache>())) .AddSingleton<IDocumentsRepository, DocumentsDatabaseRepository>() .AddSingleton<ITagsRepository>(sp => new TagsCachingRepository(new TagsDatabaseRepository(sp.GetRequiredService<IDbConnectionFactory>())));
builder.Services.AddSingleton<PasswordService>();
builder.Services.AddSingleton<AuthAction>() .AddSingleton<UsersAction>() .AddSingleton<DocumentsAction>() .AddSingleton<TagsAction>() .AddSingleton<SettingsAction>();
builder.Services.AddSingleton<IMigrationProvider, SqliteMigrationProvider>();
// configure protection to persist keysvar dataProtectionPath = Environment.GetEnvironmentVariable("MW_DATA_PROTECTION_PATH") ?? "/app/keys";builder.Services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(dataProtectionPath)) .SetApplicationName("MiniWiki");
builder.Services.Configure<ForwardedHeadersOptions>(options =>{ options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; options.KnownIPNetworks.Clear(); options.KnownProxies.Clear();});
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/auth/login"; options.LogoutPath = "/auth/logout"; });builder.Services.AddAuthorization();
var app = builder.Build();
using (var scope = app.Services.CreateScope()){ var provider = scope.ServiceProvider.GetRequiredService<IMigrationProvider>(); using var connection = provider.CreateConnection(dbPath); var runner = new MigrationRunner(provider); var migrationsPath = Environment.GetEnvironmentVariable("MW_MIGRATIONS_PATH") ?? "/app/migrations"; var migrations = MigrationLoader.LoadFromDirectory(migrationsPath); var applied = runner.MigrateUp(connection, migrations);
var logger = scope.ServiceProvider.GetRequiredService<ILoggerFactory>().CreateLogger("Migrations"); if (applied.Count == 0) { logger.LogInformation("no pending migrations"); }
foreach (var migration in applied) { logger.LogInformation("applied {version}_{name}", migration.Version, migration.Name); }}
// reverse proxy supportapp.UseForwardedHeaders();
app.UseStaticFiles();app.UseMiddleware<SessionValidationMiddleware>();app.UseAuthentication();app.UseAuthorization();
app.MapControllers();
using (var scope = app.Services.CreateScope()){ var tagRepo = scope.ServiceProvider.GetRequiredService<ITagsRepository>(); if (tagRepo is TagsCachingRepository cachingRepo) await cachingRepo.PrimeCacheAsync();}
await app.RunAsync();