HeimdallFramework.Server 2.0.1

dotnet add package HeimdallFramework.Server --version 2.0.1
                    
NuGet\Install-Package HeimdallFramework.Server -Version 2.0.1
                    
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="HeimdallFramework.Server" Version="2.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="HeimdallFramework.Server" Version="2.0.1" />
                    
Directory.Packages.props
<PackageReference Include="HeimdallFramework.Server" />
                    
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 HeimdallFramework.Server --version 2.0.1
                    
#r "nuget: HeimdallFramework.Server, 2.0.1"
                    
#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 HeimdallFramework.Server@2.0.1
                    
#: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=HeimdallFramework.Server&version=2.0.1
                    
Install as a Cake Addin
#tool nuget:?package=HeimdallFramework.Server&version=2.0.1
                    
Install as a Cake Tool

HeimdallFramework.Server

HeimdallFramework.Server provides the ASP.NET Core server runtime for the Heimdall framework.

It exposes middleware, endpoints, and page primitives that enable HTML-first applications, where the server produces documents and UI updates using hypermedia exchange instead of client-side rendering frameworks.

Most applications will use both packages:

  • HeimdallFramework.Server → server runtime
  • HeimdallFramework.Web → client runtime static assets

Install

dotnet add package HeimdallFramework.Server --prerelease

(Optional client runtime)

dotnet add package HeimdallFramework.Web --prerelease

Minimal setup

Heimdall requires ASP.NET Core antiforgery.

using Heimdall.Server;

var builder = WebApplication.CreateBuilder(args);

// Required (Heimdall uses same-origin + antiforgery for actions/SSE)
builder.Services.AddAntiforgery();

// Register Heimdall services
builder.Services.AddHeimdall(options =>
{
    options.EnableDetailedErrors = true; // optional
});

var app = builder.Build();

// Required
app.UseAntiforgery();

// Static assets (needed if using HeimdallFramework.Web)
app.MapStaticAssets();
app.UseStaticFiles();

// Heimdall middleware + endpoints (v1 routes under /__heimdall)
app.UseHeimdall();

app.Run();

Pages (core primitive)

In Heimdall, a page is a function that returns HTML.

Routes map directly to rendering functions — no view engine, no template requirement, no SPA hydration step.

app.MapHeimdallPage("/", ctx =>
{
    return Html.Tag("main",
        Html.Tag("h1", "Hello Heimdall"),
        Html.Tag("p", "The browser requested a document. The server produced it.")
    );
});

Async example:

app.MapHeimdallPage("/dashboard", async (sp, ctx) =>
{
    var repo = sp.GetRequiredService<IDashboardRepository>();
    var data = await repo.Get();

    return DashboardPage.Render(data);
});

Layouts and composition

Heimdall does not impose a layout system.

Layouts are normal functions that wrap page content.

app.MapHeimdallPage("/", ctx =>
{
    var page = HomePage.Render(ctx);
    return MainLayout.Render(page);
});

This keeps composition explicit, strongly-typed, and server-native.


Content actions (server UI updates)

Heimdall supports server actions that return HTML fragments for DOM updates.

Client triggers → server executes → server returns HTML.

  • No JSON DTO layer required
  • No client rendering layer required
  • HTML is the contract

Typical flow:

User interaction → Heimdall client runtime → POST content action → server returns HTML → DOM swap

Responses may include <invocation> directives for out-of-band updates.

Content actions can be static functions or instance methods. Static actions are the smallest primitive:

[ContentInvocation("cart.clear")]
public static IHtmlContent ClearCart(HttpContext ctx)
{
    return CartSummary.Empty();
}

For MVC-style applications, prefer action classes with constructor DI. Heimdall creates the action type from request services using ASP.NET Core DI. If the action type itself is registered, Heimdall uses that registration; otherwise it activates the type with ActivatorUtilities.

public sealed class OrderActions(IOrderRepository orders)
{
    [ContentInvocation("orders.filter")]
    public async Task<IHtmlContent> Filter(
        [ContentPayload] OrderFilter filter,
        CancellationToken ct)
    {
        var results = await orders.SearchAsync(filter, ct);
        return OrderList.Render(results);
    }
}

Use [ContentInvocationPrefix] to namespace an action class without repeating the full id on every method:

[ContentInvocationPrefix("orders")]
public sealed class OrderActions(IOrderRepository orders)
{
    [ContentInvocation("filter")]
    public async Task<IHtmlContent> Filter(OrderFilter filter, CancellationToken ct)
    {
        var results = await orders.SearchAsync(filter, ct);
        return OrderList.Render(results);
    }

    [ContentInvocation]
    public IHtmlContent Summary()
    {
        return OrderSummary.Render(orders.GetSummary());
    }
}

The resolved invocation ids are orders.filter and orders.Summary. Invocation ids are still globally unique after prefixing.

Content actions honor ASP.NET Core request timeout metadata:

using Microsoft.AspNetCore.Http.Timeouts;

[ContentInvocation("search")]
[RequestTimeout(milliseconds: 2000)]
public static async Task<IHtmlContent> Search(SearchPayload payload, CancellationToken ct)
{
    var results = await SearchService.QueryAsync(payload.Query, ct);
    return SearchResults.Render(results);
}

Named timeout policies can be reused with [RequestTimeout("PolicyName")] after configuring ASP.NET Core request timeouts with AddRequestTimeouts(...). [DisableRequestTimeout] can be applied to a content action or action class to opt out of a default timeout.

Content actions also honor ASP.NET Core authorization metadata:

using Microsoft.AspNetCore.Authorization;

[Authorize(Roles = "Admin")]
[ContentInvocation("admin.refresh")]
public static IHtmlContent RefreshAdminPanel(HttpContext ctx)
{
    return AdminPanel.Render(ctx.User);
}

[Authorize] can be applied to an action method or containing action class. [AllowAnonymous] can be used to opt out at either level. Heimdall uses the registered ASP.NET Core authorization services, policies, authentication schemes, and challenge/forbid handlers.

Content action parameters are classified without constructing services. Heimdall uses ASP.NET Core's IServiceProviderIsService for implicit service detection and supports explicit markers when a type is ambiguous:

using Microsoft.AspNetCore.Mvc;

[ContentInvocation("orders.filter")]
public static IHtmlContent FilterOrders(
    [ContentPayload] OrderFilter filter,
    [FromServices] IOrderRepository orders)
{
    return OrderList.Render(orders.Search(filter));
}

[ContentPayload] marks the single payload parameter. [FromServices] forces DI binding even if implicit service detection cannot classify the parameter.

MVC partial rendering

MVC apps can keep their existing Razor partials and render them from Heimdall content actions.

builder.Services.AddHeimdall(options =>
{
    options.EnableDetailedErrors = true;
});

builder.Services.AddHeimdallMvc();

AddHeimdallMvc() adds MVC view services, IHttpContextAccessor, and IHeimdallMvcRenderer. It does not map controller routes; call MapControllerRoute(...) or MapControllers() separately if the app also serves normal MVC controllers.

[ContentInvocationPrefix("orders")]
public sealed class OrderActions(
    IOrderRepository orders,
    IHeimdallMvcRenderer views)
{
    [ContentInvocation("filter")]
    public async Task<IHtmlContent> Filter(OrderFilter filter, CancellationToken ct)
    {
        var results = await orders.SearchAsync(filter, ct);
        return await views.PartialAsync("_OrderList", results, ct);
    }
}

Partial names are resolved through the MVC view engine. You can also pass an application-relative path such as ~/Views/Orders/_OrderList.cshtml when you want to avoid controller-based lookup assumptions.

Server helpers cover the same trigger-routing and response directives supported by the Heimdall client runtime:

Html.Button(
    "Close",
    HeimdallHtml.OnClick("dialog.close"),
    HeimdallHtml.Scope(HeimdallHtml.EventScope.Self)
);

return Html.Fragment(
    HeimdallHtml.Abort("validation-failed"),
    HeimdallHtml.Invocation("#errors", HeimdallHtml.Swap.Inner, ErrorList.Render(errors))
);

Use HeimdallHtml.Ignore(...) / .IgnoreAll() for heimdall-ignore, HeimdallHtml.Scope(...) for heimdall-scope, HeimdallHtml.Abort(...) to suppress the main swap, and HeimdallHtml.Redirect(...) for client navigation.


Endpoints (v1)

Heimdall.Server exposes the following same-origin endpoints:

Content actions

POST /__heimdall/v1/content/actions
Executes a server action and returns HTML (optionally containing <invocation> directives).

CSRF token

GET /__heimdall/v1/csrf
Returns an antiforgery token used by the Heimdall client runtime (cached client-side).

Bifrost (SSE)

GET /__heimdall/v1/bifrost?topic=...
Server-Sent Events stream for pushing HTML and/or <invocation> directives.

Bifrost publishes on the default Heimdall SSE event unless an event name is supplied:

await bifrost.PublishAsync("orders", Html.Span("Updated"), TimeSpan.FromSeconds(5));
await bifrost.PublishAsync("orders", "order.updated", Html.Span("Updated"), TimeSpan.FromSeconds(5));

Use topics for subscription and authorization boundaries. Use named events to route different message types inside the same topic stream.

Bifrost subscribe token

GET /__heimdall/v1/bifrost/token?topic=...
Issues a short-lived subscribe token gated by antiforgery.

Topic subscription can be authorized before a subscribe token is issued:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("BifrostTopic", policy =>
        policy.RequireAuthenticatedUser());
});

builder.Services.AddHeimdall(options =>
{
    options.BifrostTopicPolicy = "BifrostTopic";
    options.AuthorizeBifrostTopic = (ctx, topic) =>
        ValueTask.FromResult(topic.StartsWith($"user:{ctx.User.Identity?.Name}:", StringComparison.Ordinal));
});

Policy handlers receive a BifrostTopicResource containing the topic and HttpContext. If both BifrostTopicPolicy and AuthorizeBifrostTopic are configured, both must allow the topic. Subscribe tokens are short-lived and bound to the current authenticated principal.


What this package provides

  • Heimdall middleware
  • Content action execution pipeline
  • HTML response helpers
  • Page mapping primitives (MapHeimdallPage)
  • Antiforgery integration
  • Bifrost (SSE) server runtime
  • Hypermedia-driven UI execution model

Design philosophy

Heimdall intentionally moves UI back toward the browser’s original model:

  • The browser requests documents
  • The server produces documents
  • Interactions request HTML, not data
  • HTML is the contract
  • Composition happens on the server
  • Real-time updates stream HTML

This allows rich applications without SPA complexity.


Status

This package is currently alpha.
Public APIs, naming, and patterns may change.


License

MIT

Product Compatible and additional computed target framework versions.
.NET 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.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.1 76 5/29/2026
2.0.0 70 5/29/2026
1.0.7 96 5/26/2026
1.0.6 103 5/7/2026
1.0.5 88 5/6/2026
1.0.4 112 4/25/2026
1.0.3 93 4/25/2026
1.0.2 99 4/24/2026
1.0.1 98 4/16/2026
1.0.0 96 4/16/2026
0.2.3-alpha.1 58 4/13/2026
0.2.2-alpha.1 59 4/13/2026
0.2.1-alpha.1 57 4/13/2026
0.2.0-alpha.1 57 4/10/2026
0.1.9-alpha.1 59 4/10/2026
0.1.8-alpha.1 56 4/9/2026
0.1.7-alpha.1 61 4/9/2026
0.1.6-alpha.1 60 4/8/2026
0.1.5-alpha.1 56 4/7/2026
0.1.4-alpha.1 63 4/4/2026
Loading failed