Update SDK; htmx serving now works (#59)

This commit is contained in:
2026-07-04 20:27:39 -04:00
parent 84444e4789
commit 7c588662d2
2 changed files with 55 additions and 54 deletions
+1 -2
View File
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
@@ -7,7 +7,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Content Include="appsettings*.json" CopyToOutputDirectory="Always" />
<Compile Include="Caches.fs" /> <Compile Include="Caches.fs" />
<Compile Include="ViewContext.fs" /> <Compile Include="ViewContext.fs" />
<Compile Include="Template.fs" /> <Compile Include="Template.fs" />
+42 -40
View File
@@ -1,7 +1,4 @@
open Microsoft.AspNetCore.Hosting open Microsoft.AspNetCore.Http
open Microsoft.AspNetCore.Http
open Microsoft.Data.Sqlite
open Microsoft.Extensions.Configuration
open Microsoft.Extensions.Logging open Microsoft.Extensions.Logging
open MyWebLog open MyWebLog
@@ -30,6 +27,7 @@ type WebLogMiddleware(next: RequestDelegate, log: ILogger<WebLogMiddleware>) =
} }
open System
open Giraffe.Htmx open Giraffe.Htmx
/// Middleware to check redirects for the current web log /// Middleware to check redirects for the current web log
@@ -37,7 +35,7 @@ type RedirectRuleMiddleware(next: RequestDelegate, _log: ILogger<RedirectRuleMid
/// Shorthand for case-insensitive string equality /// Shorthand for case-insensitive string equality
let ciEquals str1 str2 = let ciEquals str1 str2 =
System.String.Equals(str1, str2, System.StringComparison.InvariantCultureIgnoreCase) String.Equals(str1, str2, StringComparison.InvariantCultureIgnoreCase)
member _.InvokeAsync(ctx: HttpContext) = task { member _.InvokeAsync(ctx: HttpContext) = task {
let path = ctx.Request.Path.Value.ToLower() let path = ctx.Request.Path.Value.ToLower()
@@ -57,9 +55,9 @@ type RedirectRuleMiddleware(next: RequestDelegate, _log: ILogger<RedirectRuleMid
} }
open System
open System.IO open System.IO
open BitBadger.Documents open BitBadger.Documents
open Microsoft.Extensions.Configuration
open Microsoft.Extensions.DependencyInjection open Microsoft.Extensions.DependencyInjection
open MyWebLog.Data open MyWebLog.Data
open Newtonsoft.Json open Newtonsoft.Json
@@ -137,8 +135,10 @@ open Giraffe
open Giraffe.EndpointRouting open Giraffe.EndpointRouting
open Microsoft.AspNetCore.Authentication.Cookies open Microsoft.AspNetCore.Authentication.Cookies
open Microsoft.AspNetCore.Builder open Microsoft.AspNetCore.Builder
open Microsoft.AspNetCore.HttpOverrides
open Microsoft.Extensions.Caching.Distributed open Microsoft.Extensions.Caching.Distributed
open Microsoft.AspNetCore.HttpOverrides
open Microsoft.AspNetCore.Hosting
open Microsoft.Data.Sqlite
open NeoSmart.Caching.Sqlite open NeoSmart.Caching.Sqlite
open RethinkDB.DistributedCache open RethinkDB.DistributedCache
@@ -150,19 +150,20 @@ let main args =
ContentRootPath = Directory.GetCurrentDirectory(), ContentRootPath = Directory.GetCurrentDirectory(),
WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"), WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot"),
Args = args)) Args = args))
let _ = builder.Services.Configure<ForwardedHeadersOptions>( let _ = builder.WebHost.UseStaticWebAssets()
builder.Services
.Configure<ForwardedHeadersOptions>(
fun (opts: ForwardedHeadersOptions) -> fun (opts: ForwardedHeadersOptions) ->
opts.ForwardedHeaders <- ForwardedHeaders.XForwardedFor ||| ForwardedHeaders.XForwardedProto) opts.ForwardedHeaders <- ForwardedHeaders.XForwardedFor ||| ForwardedHeaders.XForwardedProto)
let _ = .AddLogging()
builder.Services .AddAuthorization()
.AddAntiforgery()
.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(fun opts -> .AddCookie(fun opts ->
opts.ExpireTimeSpan <- TimeSpan.FromMinutes 60. opts.ExpireTimeSpan <- TimeSpan.FromMinutes 60.
opts.SlidingExpiration <- true opts.SlidingExpiration <- true
opts.AccessDeniedPath <- "/forbidden") opts.AccessDeniedPath <- "/forbidden")
let _ = builder.Services.AddLogging() |> ignore
let _ = builder.Services.AddAuthorization()
let _ = builder.Services.AddAntiforgery()
let sp = builder.Services.BuildServiceProvider() let sp = builder.Services.BuildServiceProvider()
let data = DataImplementation.get sp let data = DataImplementation.get sp
@@ -178,37 +179,37 @@ let main args =
match data with match data with
| :? RethinkDbData as rethink -> | :? RethinkDbData as rethink ->
// A RethinkDB connection is designed to work as a singleton // A RethinkDB connection is designed to work as a singleton
let _ = builder.Services.AddSingleton<IData> data builder.Services
let _ = .AddSingleton<IData>(data)
builder.Services.AddDistributedRethinkDBCache(fun opts -> .AddDistributedRethinkDBCache(fun opts ->
opts.TableName <- "Session" opts.TableName <- "Session"
opts.Connection <- rethink.Conn) opts.Connection <- rethink.Conn)
() |> ignore
| :? SQLiteData -> | :? SQLiteData ->
// ADO.NET connections are designed to work as per-request instantiation // ADO.NET connections are designed to work as per-request instantiation; use SQLite for caching as well
let cfg = sp.GetRequiredService<IConfiguration>() let cfg = sp.GetRequiredService<IConfiguration>()
let _ = builder.Services.AddScoped<SqliteConnection>(fun sp -> Sqlite.Configuration.dbConn ())
let _ = builder.Services.AddScoped<IData, SQLiteData>()
// Use SQLite for caching as well
let cachePath = defaultArg (Option.ofObj (cfg.GetConnectionString "SQLiteCachePath")) "./data/session.db" let cachePath = defaultArg (Option.ofObj (cfg.GetConnectionString "SQLiteCachePath")) "./data/session.db"
let _ = builder.Services.AddSqliteCache(fun o -> o.CachePath <- cachePath) builder.Services
() .AddScoped<SqliteConnection>(fun sp -> Sqlite.Configuration.dbConn ())
.AddScoped<IData, SQLiteData>()
.AddSqliteCache(fun o -> o.CachePath <- cachePath)
|> ignore
| :? PostgresData as postgres -> | :? PostgresData as postgres ->
// ADO.NET Data Sources are designed to work as singletons // ADO.NET Data Sources are designed to work as singletons
let _ = builder.Services.AddSingleton<NpgsqlDataSource>(Postgres.Configuration.dataSource ()) builder.Services
let _ = builder.Services.AddSingleton<IData> postgres .AddSingleton<NpgsqlDataSource>(Postgres.Configuration.dataSource ())
let _ = .AddSingleton<IData>(postgres)
builder.Services.AddSingleton<IDistributedCache>(fun _ -> .AddSingleton<IDistributedCache>(fun _ -> Postgres.DistributedCache() :> IDistributedCache)
Postgres.DistributedCache() :> IDistributedCache) |> ignore
()
| _ -> () | _ -> ()
let _ = builder.Services.AddSession(fun opts -> builder.Services
.AddSession(fun opts ->
opts.IdleTimeout <- TimeSpan.FromMinutes 60. opts.IdleTimeout <- TimeSpan.FromMinutes 60.
opts.Cookie.HttpOnly <- true opts.Cookie.HttpOnly <- true
opts.Cookie.IsEssential <- true) opts.Cookie.IsEssential <- true)
let _ = builder.Services.AddGiraffe() .AddGiraffe()
let _ = builder.WebHost.UseStaticWebAssets() |> ignore
// Set up DotLiquid // Set up DotLiquid
DotLiquidBespoke.register () DotLiquidBespoke.register ()
@@ -243,14 +244,15 @@ let main args =
|> isNotNull |> isNotNull
|> function true -> app.UseCanonicalDomains() |> ignore | false -> () |> function true -> app.UseCanonicalDomains() |> ignore | false -> ()
let _ = app.UseCookiePolicy(CookiePolicyOptions(MinimumSameSitePolicy = SameSiteMode.Strict)) app .UseCookiePolicy(CookiePolicyOptions(MinimumSameSitePolicy = SameSiteMode.Strict))
let _ = app.UseMiddleware<WebLogMiddleware>() .UseMiddleware<WebLogMiddleware>()
let _ = app.UseMiddleware<RedirectRuleMiddleware>() .UseMiddleware<RedirectRuleMiddleware>()
let _ = app.UseAuthentication() .UseAuthentication()
let _ = app.UseRouting() .UseStaticFiles()
let _ = app.UseSession() .UseRouting()
let _ = app.UseGiraffe Handlers.Routes.endpoints .UseSession()
let _ = app.UseStaticFiles() .UseGiraffe Handlers.Routes.endpoints
|> ignore
do! app.RunAsync() do! app.RunAsync()
} }