Themia.Storage.AspNetCore 0.29.0

dotnet add package Themia.Storage.AspNetCore --version 0.29.0
                    
NuGet\Install-Package Themia.Storage.AspNetCore -Version 0.29.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Themia.Storage.AspNetCore" Version="0.29.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Themia.Storage.AspNetCore" Version="0.29.0" />
                    
Directory.Packages.props
<PackageReference Include="Themia.Storage.AspNetCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Themia.Storage.AspNetCore --version 0.29.0
                    
#r "nuget: Themia.Storage.AspNetCore, 0.29.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Themia.Storage.AspNetCore@0.29.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Themia.Storage.AspNetCore&version=0.29.0
                    
Install as a Cake Addin
#tool nuget:?package=Themia.Storage.AspNetCore&version=0.29.0
                    
Install as a Cake Tool

Themia.Storage.AspNetCore

Serves Themia.Storage's Local presigned downloads over HTTP — for a host that uses the neutral LocalStorageProvider directly rather than Themia.Modules.Storage.

// The signer must use the same key as the provider.
builder.Services.AddSingleton<IStorageProvider>(new LocalStorageProvider(localOptions));
builder.Services.AddSingleton(new LocalUrlSigner(localOptions.SigningKey));

// Absolute links, including from a background job with no HTTP request (Themia.Storage).
builder.Services.AddThemiaStorageUrls(o => o.PresignedBaseUrl = "https://api.example.com/api/v1/storage");

app.MapThemiaLocalStorage("/api/v1/storage");     // GET /api/v1/storage/_local/get?key=…&token=…

// anywhere:
var url = await storageUrls.GetDownloadUrlAsync(key, TimeSpan.FromMinutes(15), ct);

With an S3-compatible provider, GetDownloadUrlAsync returns the provider's signed URL untouched and the route is never hit.

What the route does

request response
valid token, object exists 200, streamed with its stored content type
valid token, no object 404
missing, tampered or expired token; a token for another key; an upload token bare 403

Every response carries Cache-Control: private, no-store, X-Content-Type-Options: nosniff and Content-Security-Policy: sandbox.

The sandbox is the header that matters. nosniff stops a browser guessing a type; it does nothing for a file whose declared type is already dangerous. An uploaded SVG containing a <script>, stored as image/svg+xml and opened from its presigned link, would otherwise run on your API's origin — the same for text/html. Sandboxed, the document gets a unique origin and no script; images and PDFs render as usual.

Anonymous by construction

The token is the credential, exactly as an S3 presigned URL's signature is, and the link is opened by a browser or mail client that carries no session. So the route is mapped in a group that is never handed back (a host's RequireAuthorization() cannot reach it) and carries AllowAnonymous — because an authorization FallbackPolicy, a common hardening, applies to every endpoint without auth metadata and would otherwise put every link behind a login it cannot satisfy.

Fails at startup, not in production

  • No LocalUrlSigner registered → MapThemiaLocalStorage throws. Otherwise every download fails.
  • PresignedBaseUrl set but not ending with the mount you map → throws. An absolute URL for the wrong mount passes "is it absolute?" and 404s on every link.
  • PresignedBaseUrl not an absolute http(s) URL, or carrying a query → the host fails to start.
  • A Local provider with no PresignedBaseUrlGetDownloadUrlAsync throws naming the option, rather than returning a relative link that goes into an email and breaks there.

The base URL is joined as a string on purpose. new Uri(new Uri("https://host/api/v1/storage"), "_local/get") resolves RFC-3986-style and drops the last segmenthttps://host/api/v1/_local/get — so a missing trailing slash is the whole difference between working links and a 404 on every one. Both forms are tested.

Keep the token out of your logs

The token travels in the query string and is a bearer credential for the life of the URL. This package cannot control your host's request logging; if it writes query strings, exclude this route.

Not included

Presigned uploads (_local/put) — still served by Themia.Modules.Storage only — range requests, and ETags.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Themia.Storage.AspNetCore:

Package Downloads
Themia.Modules.Storage

Tenant-aware object storage — key-prefix isolation, DB-backed metadata + per-tenant quota over EF or Dapper, validation/scan seams, and a Local/S3/R2 backend builder. FluentMigrator schema (PostgreSQL + SQL Server).

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.29.0 0 9/19/2026
0.28.1 6 9/19/2026
0.28.0 34 9/19/2026