Deciding per request: selectors
A selector looks at the request before anything else, for every page. The first selector that
returns a target wins. Return null to pass the page on:
.AddRendering(o => o
.Select((http, m) => http.Request.Query["view"] == "print" && m.Content is IArticle ? new RazorViewTarget("ArticlePrint") : null)
.Select((http, m) => http.Request.Query["format"] == "json" ? new ResultTarget((_, c) => Results.Json(new { c.Content.Name })) : null))Print views, A/B tests and a theme per site all start here. A selector that needs a service takes it
from http.RequestServices.
A selector is also how code overrides a template, and the only way a plain ITemplate renders. It
tells templates apart by name or id:
.AddRendering(o => o
// every page with the template "Campaign": a Blazor component
.Select((http, m) => m.Template?.Name == "Campaign"
? new ResultTarget((_, c) => new RazorComponentResult<CampaignPage>(new { Content = c.Content }))
: null)
// per page: a long article gets another view; null leaves the page to its template
.Select((http, m) => m.Template?.Name == "Article" && m.Content is IArticle { Body.Length: > 20_000 } ? new RazorViewTarget("ArticleLong") : null))Editors see a template's name and may change it. For a template that always renders the same way, a kind of its own is sturdier, because editors then see what renders it.