esegece.sgcHTML.AspNetCore.Community 2026.10.0

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

esegece.sgcHTML.AspNetCore

sgcHTML for ASP.NET Core: the server-driven HTML / htmx UI components of sgcHTML, hosted on Kestrel. Two calls host an sgcHTML page, its embedded client assets (htmx, the htmx WebSocket extension, the sgcHTMX bridge, Bootstrap and Chart.js), the PWA manifest / service worker, and the htmx WebSocket channel, all on native Kestrel.

Self-contained. The package is one assembly, esegece.sgcHTML.AspNetCore.dll. It compiles the sgcHTML components, the ASP.NET Core adapter and the small part of the sgcWebSockets core they need (JSON, helpers, the WebAuthn relying party and its crypto) into that single file. It has no NuGet dependency at all, only the Microsoft.AspNetCore.App shared framework. Target frameworks: net8.0, net9.0.

Install

Two package ids, the same code:

Package Edition
esegece.sgcHTML.AspNetCore Registered (purchased). No notice, no limits, sources included with the purchase.
esegece.sgcHTML.AspNetCore.Community Community (free). Full feature set, a one-time startup notice and a discreet Community Edition notice on every generated page.
dotnet add package esegece.sgcHTML.AspNetCore

or, for the free edition:

dotnet add package esegece.sgcHTML.AspNetCore.Community

Reference exactly one of the two.

Do not combine with esegece.sgcWebSockets or esegece.sgcHTML

This package defines the same public types as esegece.sgcHTML (and the host types it needs with the same names as esegece.sgcWebSockets), so a project that references both would fail with CS0433. The package therefore ships a build check (error SGCHTML001) that stops the build when esegece.sgcWebSockets.dll or esegece.sgcHTML.dll is also referenced. Use one of these two setups, never both:

  • esegece.sgcHTML.AspNetCore (or .Community) alone, for sgcHTML on ASP.NET Core.
  • esegece.sgcWebSockets plus esegece.sgcHTML, for sgcHTML on the sgcWebSockets servers together with the rest of the sgcWebSockets library.

Namespaces

The types live in the namespaces esegece.sgcWebSockets (components, engine, router, AI assistant, passkeys) and esegece.sgcWebSockets.AspNetCore (AddSgcHtml / UseSgcHtml). That is only a name. This package does not use or ship the sgcWebSockets library, it is one self-contained assembly with no NuGet dependencies. The names match sgcHTML on the sgcWebSockets servers, so the same page and component code compiles unchanged on either host.

Minimal usage

using esegece.sgcWebSockets;              // TsgcHTMX_Engine_Server, TsgcHTMX_Router, TsgcHTMXRequest
using esegece.sgcWebSockets.AspNetCore;   // AddSgcHtml / UseSgcHtml

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSgcHtml(o =>
{
    o.RootPath = "/";
    o.WebSocketPath = "/ws";
    o.ConfigureEngine = engine =>
    {
        // the page shell served at RootPath
        engine.Template.Title = "sgcHTML on ASP.NET Core";
        engine.Template.BodyContent =
            "<div class=\"container py-4\">" +
            "<h1>Hello from sgcHTML</h1>" +
            "<div hx-ext=\"ws\" ws-connect=\"/ws\">" +
            "<button class=\"btn btn-primary\" ws-send " +
            "hx-vals='{\"path\":\"/hello\"}'>Ping</button>" +
            "<div id=\"out\"></div></div></div>";

        // an htmx WebSocket route: reply is pushed out-of-band to #out
        var router = new TsgcHTMX_Router();
        var route = router.Routes.Add();
        route.Path = "/hello";
        route.OnRoute += (object sender, TsgcHTMXRequest request, ref string response) =>
        {
            response = "<div id=\"out\" hx-swap-oob=\"true\">Pong</div>";
        };
        engine.Router = router;
    };
});

var app = builder.Build();

app.UseWebSockets();   // REQUIRED before UseSgcHtml
app.UseSgcHtml();

app.Run();

What the middleware serves

Request Response
GET RootPath (default /) engine.GetPageHTML() (the page shell)
GET /htmx.min.js, /bootstrap.min.css, ... the embedded asset body
GET ManifestPath (/manifest.json) engine.Template.GetManifestJSON()
GET ServiceWorkerPath (/sw.js) engine.Template.GetServiceWorkerJS()
WS upgrade at WebSocketPath (/ws) accepted; each text frame runs through the engine, the reply is pushed back over the socket
with the SSE transport on: GET engine.SSE.Endpoint (/htmx-sse) with Accept: text/event-stream accepted as an event stream (see "SSE transport")
with the SSE transport on: POST engine.SSE.PostEndpoint (/htmx-sse/send) the upstream message of a stream: 204, 403, 404 or 413
with Auth set: router routes, POST Auth.LoginPath and POST Auth.LogoutPath served through the engine dispatch (see "Sessions and CSRF")
anything else passed to the next middleware

SSE transport

The page can take its realtime updates over server-sent events instead of a WebSocket. Turn it on in ConfigureEngine, either with SSE.Enabled = true or by setting Template.Transport to htSSE (SSE only) or htAuto (WebSocket, with the bridge falling back to SSE when the socket cannot be opened):

builder.Services.AddSgcHtml(o =>
{
    o.ConfigureEngine = e =>
    {
        e.Template.Transport = TsgcHTMXTransport.htSSE;
        e.SSE.Enabled = true;
    };
});

UseSgcHtml then accepts the event stream on engine.SSE.Endpoint and the upstream POST on engine.SSE.PostEndpoint, the two paths the rendered page carries. A stream gets retry: 3000 and its connection guid as the first plain message, : keepalive comments every SSE.KeepAlive seconds, and one event per pushed fragment (event: <SSE.EventName>, id: <guid>:<n>, one data: line per line). A stream is bound to the session of its cookies under the same same-origin rule as a WebSocket handshake, and the last SSE.ReplaySize events are kept for SSE.ReplayTTL seconds so a reconnect carrying Last-Event-ID (or ?lastEventId=) gets what it missed, renumbered, from a stream of the same session.

ISgcHtmlHub.PushFragmentAsync and BroadcastAsync reach both transports, so the pushing code does not change with the transport. The upstream POST must name its stream in the X-SGC-Connection header (or the sgc_connection field), carry the CSRF token when the page is signed in, and stays under 1 MB; it answers 204 (run), 403 (no token), 404 (unknown or foreign stream) or 413.

With the SSE transport off, nothing above is served and the middleware behaves exactly as before.

Assets + WebSocket only (multi-page apps)

By default UseSgcHtml serves the engine-generated page at RootPath. For a multi-page app that renders its own pages but still wants the sgcHTML client assets (htmx, Bootstrap, Chart.js), the PWA manifest / service worker and the WebSocket push channel, set ServeRootPage = false. The middleware then serves everything except the page: page requests fall through to next(), so your own MapGet / MapPost routes own all page routing.

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddSgcHtml(o =>
{
    o.ServeRootPage = false;   // the app owns "/" and every other page route
});

var app = builder.Build();

app.UseWebSockets();   // REQUIRED before UseSgcHtml
app.UseSgcHtml();      // serves assets + manifest + sw + the /ws channel only

// the app renders its own pages
app.MapGet("/", (HttpContext ctx) =>
{
    string html = /* build the page HTML yourself */ "<html>...</html>";
    return Results.Content(html, "text/html");
});

app.Run();

Server-driven updates

The adapter runs the WebSockets itself (the engine has no TsgcWSHTTPServer bound), so push updates through the DI-registered ISgcHtmlHub instead of the engine's Server-bound PushFragment / BroadcastFragment:

public sealed class Ticker(ISgcHtmlHub hub) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            await hub.BroadcastAsync(
                $"<div id=\"clock\" hx-swap-oob=\"true\">{DateTime.UtcNow:T}</div>",
                cancellationToken: stoppingToken);
            await Task.Delay(1000, stoppingToken);
        }
    }
}

Sessions and CSRF

Set Auth to a configured TsgcHTMLAuth (or AuthFactory to build one from the application services) and the adapter serves sgcHTML requests through the engine's own dispatch, exactly as the self-hosted servers do:

  • The page at RootPath, the engine router routes and the built-in POST login and logout endpoints (Auth.LoginPath, Auth.LogoutPath) run with the session of the request. The login form posts username, password, remember and next. The login page itself (a GET on LoginPath) is yours, as a router route or an app endpoint.
  • Routes with RequireLogin or RequireRoles send anonymous visitors to Auth.LoginPath?next=... (302, or 401 with HX-Redirect for htmx requests) and answer 403 when the session has none of the listed roles.
  • With Auth.CSRFProtection on (the default), a signed in request with any method other than GET, HEAD or OPTIONS must carry the session token in the X-CSRF-Token header or the csrf_token form field, or it gets 403. The page renders the csrf-token and csrf-header meta tags for that.
  • Every cookie is written as its own Set-Cookie line, so a remember-me login and a logout reach the browser complete.
  • WebSocket messages on WebSocketPath use the session of the cookies sent with the upgrade request, but only when the upgrade has no Origin header or its host matches the Host header. A remember-me cookie is never redeemed there.

With Auth set, engine routes answer HTTP requests as well, so do not map the same path in the app. Without Auth the adapter behaves exactly as described above. The instance passed in Auth stays yours to dispose. One built by AuthFactory is disposed with the service container.

var store = new TsgcHTMLSessionStore_Memory();
var auth = new TsgcHTMLAuth { SessionStore = store, LoginPath = "/login", AfterLoginPath = "/" };
auth.OnAuthenticate += (object sender, string user, string password, ref bool accept,
    ref string userId, ref string displayName, List<string> roles) =>
{
    // check the credentials against your user store here
    accept = user == "admin" && password == "secret";
    userId = user;
    displayName = "Administrator";
    roles.Add("admin");
};

builder.Services.AddSgcHtml(o =>
{
    o.Auth = auth;
    o.MapSessionToUser = true;
    o.ConfigureEngine = engine => { /* template and router */ };
});

// only for [Authorize] and RequireAuthorization(): a challenge that sends
// anonymous users to the sgcHTML login page
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(o => { o.LoginPath = "/login"; o.ReturnUrlParameter = "next"; });
builder.Services.AddAuthorization();

var app = builder.Build();
app.UseWebSockets();
app.UseAuthentication();
app.UseSgcHtml();        // after UseAuthentication, before UseAuthorization
app.UseAuthorization();

app.MapGet("/api/me", (ClaimsPrincipal user) => user.Identity!.Name).RequireAuthorization();

Signed in users on your own endpoints

With MapSessionToUser = true, every request that the middleware passes on to your own endpoints and that carries a valid sgcHTML session gets HttpContext.User set to a principal with the authentication type sgcHTML, a ClaimTypes.NameIdentifier claim (the user id), a ClaimTypes.Name claim (the display name) and one ClaimTypes.Role claim per role. [Authorize] and RequireAuthorization() then work with the same login. A remember-me cookie is redeemed there too, and its new cookies are added to your response.

The order of the middleware matters. Call UseSgcHtml() after UseAuthentication() and before UseAuthorization(), and call UseAuthorization() yourself. When WebApplication adds the authorization middleware on its own, it places it at the start of the pipeline, ahead of UseSgcHtml(), so the policy would still see an anonymous user. An anonymous request to a protected endpoint needs a challenge scheme. The cookie scheme in the sample only redirects to the sgcHTML login page. It never signs anyone in.

Bring your own LLM

The AI features (the AI assistant behind the Grid, DataTable, PivotTable, Form and InlineAIPrompt components) do not ship a built-in LLM provider in this package. Handle TsgcHTMLAIAssistant.OnAIRequest and call whatever model you use. The handler receives the system prompt, the user prompt and the JSON schema the answer has to follow, and returns the raw answer, which must be a single JSON object with no prose and no code fences:

using esegece.sgcWebSockets;   // TsgcHTMLAIAssistant

var ai = new TsgcHTMLAIAssistant();
ai.OnAIRequest += (object sender, string aSystemPrompt, string aPrompt,
    string aJSONSchema, ref string aResponse) =>
{
    // call your own LLM client here (OpenAI, Anthropic, Azure, a local model...)
    aResponse = MyLlmClient.Complete(aSystemPrompt, aPrompt, aJSONSchema);
};

grid.AIAssistant = ai;   // any component with an AIAssistant property

With no handler assigned the assistant uses its rule based parser.

Passkeys

Passkey sign-in (WebAuthn) is included: TsgcHTMLComponent_WebAuthnLogin and the WebAuthn relying party it uses (registration, authentication, attestation with X.509 chain verification and the FIDO metadata service) are compiled into the package. The 02.AdminCRUD demo shows it end to end.

Not included

These parts of sgcHTML depend on the sgcWebSockets servers or on other sgcWebSockets APIs, so they are available only with esegece.sgcWebSockets plus esegece.sgcHTML:

  • Web Push (sgcHTML_WebPush).
  • MCP Apps (showing an sgcHTML page inside Claude, ChatGPT or VS Code).
  • The admin console.
  • The HTTP.sys hosts (TsgcWSServer_HTTPAPI engines). This package hosts on Kestrel only.
  • The built-in LLM providers (TsgcAIChat and friends). Use OnAIRequest instead, see above.

Demos

The demos\61.HTML.AspNetCore suite hosts fifteen sgcHTML apps on Kestrel through this adapter, mirroring the self-hosted demos\60.HTML set. Each is a Microsoft.NET.Sdk.Web (net8.0) app that reuses the matching 60.HTML demo's rendering / DB / auth code and rewrites only the host layer. The multi-route apps register with AddSgcHtml(o => o.ServeRootPage = false) (see "Assets + WebSocket only" above) so the app owns its routes, while the adapter still serves the htmx / Bootstrap / Chart.js assets, the PWA manifest / service worker and the /ws push hub.

Folder App Port What it shows
07.Site sgcSiteWeb 8092 query-driven site layouts / themes
06.Grid sgcGridWeb 8093 data-grid routes (sort / filter / group / paging / virtual-scroll / export)
05.HTMX sgcHTMXWeb 8094 htmx patterns (OOB, search, wizard, inline edit, live validation, DELETE-row, infinite scroll, cascade)
08.Components sgcComponentsWeb 8095 component showcase + WebSocket live push (ISgcHtmlHub) + XLSX / PDF export
10.ShopAssistant sgcShopWeb 8096 storefront + in-memory session + AI chat (keyless fallback)
02.AdminCRUD sgcAdminWeb 8097 admin CRUD: bcrypt auth + passkeys + cookie sessions + SQLite + i18n
01.ERP sgcERPWeb 8098 ERP CRUD on the same auth stack
04.Portal sgcPortalWeb 8099 role-gated dual area (customer + back-office)
09.Helpdesk sgcHelpdeskWeb 8100 ticketing with multipart upload / download (IFormFile) + CSV export
03.LiveMonitor sgcLiveMonitorWeb 8101 live dashboard: BackgroundService pushing KPI fragments over the hub
13.Warehouse sgcWMSWeb 8102 warehouse management
14.POS sgcPOSWeb 8103 point of sale
15.Reports sgcReportsWeb 8104 reports
16.SaaS sgcSaaSWeb 8105 multi-tenant SaaS app
17.FieldService sgcFieldWeb 8106 field service

Run any demo (it listens on its appsettings.json port), or open the solution demos\61.HTML.AspNetCore\61.HTML.AspNetCore.sln:

dotnet run --project demos\61.HTML.AspNetCore\08.Components
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 is compatible.  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 was computed.  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.
  • net8.0

    • No dependencies.
  • net9.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
2026.10.0 77 9/25/2026