The middleware that serves it
Nothing maps an endpoint for these URLs: you add a middleware. It is about thirty lines around
TryParseUrlForContent and FileHandler.HandleFileAsync:
public class RelatudeDBMiddleware(RequestDelegate next) {
public async Task Invoke(HttpContext http, RelatudeDBContext ctx) {
if (RelatudeDBRuntime.IsReady) {
// scheme and host included, so domain routing can see them
var url = http.Request.Scheme + "://" + http.Request.Host
+ http.Request.Path.Value + http.Request.QueryString;
// firstInQueue: a browser waits, so this goes ahead of background conversions
if (ctx.Database.TryParseUrlForContent(url, out var content, firstInQueue: true)) {
var result = content.Id.Target switch {
UrlTarget.Property or UrlTarget.PropertyAdjusted
=> await FileHandler.HandleFileAsync(http, content.Stream, content.FileName,
content.Attachment, content.ContentType, content.Cacheable),
UrlTarget.Node or UrlTarget.EmbeddedNode => RenderPage(http, content),
_ => null,
};
if (result != null) { await result.ExecuteAsync(http); return; }
}
}
await next.Invoke(http);
}
}Register it after the static files. A URL manager can own /, so the middleware sees every request
that gets that far:
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMiddleware<RelatudeDBMiddleware>();
app.UseRelatudeDB();Four things in the middleware matter:
- Keep the
IsReadycheck. The store opens in the background, and requests that arrive before it is open would throw instead of passing on. - Pass scheme and host, not just the path. Domain routing needs the host, and an asset token can be in the query string.
- Other requests go on to
next.TryParseUrlForContentreturnsfalsefor URLs that are not the store's, so a tampered asset URL ends as a plain 404. - Rendering pages is up to you. For
UrlTarget.NodeandEmbeddedNodeyou getcontent.NodeData, andcontent.Id.CultureCodenames the culture the URL matched. Returnnullto pass the request on to MVC or Razor Pages.
FileHandler answers a Range request with 206 Partial Content when the stream can seek, as a file
on local disk can; video and audio players need that. A file in blob storage or in a single-file
store is served whole. If your web layer parses URLs before it decides what serves them, call
TryParseUrl once and then GetUrlContentAsync(keys), rather than parsing twice.