Skip to content

Guided tour

FabrCore 2.0 · Release and package availability

These guides track the current 2.0 source. Stable 2.0.0 publication is pending; package commands show the release target. Until it is published, follow the source quick start or use a matching available prerelease set. Release migration · Runtime modes

MODULE 05 · LESSON 5.6

Host FabrCore inside a Blazor Server application

Run FabrCore and Blazor Interactive Server in one web application.

Lesson 26 of 86 · FabrCore 2.0

Overview

This is the server-integrated path: the browser uses a Blazor circuit, and server-side Surface services connect that principal's workspace to FabrCore. It does not require browser Orleans access or a custom browser WebSocket receive loop. Use the same Operations Desk agents as the mobile path.

The browser talks to the Blazor server

In this variant FabrCore runs inside the server-side web application. The browser's circuit talks to Blazor components; server-side Surface services connect the user's workspace to the runtime. You reuse the Operations Desk agent classes, but you do not implement the MAUI socket receive loop in the Razor page.

Register services and assets together

The example Program.cs wires the Host and Surface services. App.razor supplies the matching assets and interactive component setup, while Routes.razor selects pages. Missing one layer can produce an application that starts successfully but displays a noninteractive chat panel. The development principal is a sample convenience; a deployed circuit must use the actual signed-in user's scope.

Run the integrated Blazor host

Download the Operations Desk source. The README lists project setup, package prerequisites and local ports.

  1. Create a Blazor Web App with Interactive Server and reference FabrCore.Host, the agents library and FabrCore.Surface. Register Razor components, FabrCore and Surface services in Program.cs.
  2. Add Surface styles/assets and the documented route extension if using /surface. Ensure the page/layout hosting SurfaceChatLink has an interactive render mode; registering services alone does not make a static Razor component interactive.
  3. Map the authenticated user to ISurfacePrincipalContextProvider and a scoped SurfaceWorkspaceService. Keep development fallback identity restricted to the development environment.
integration.md · reference snippet
builder.AddFabrCoreSurfaceFromConfig("fabrcore-surface.json", "crm-demo");
builder.Services.AddFabrCoreSurfaceComponents();
integration.md · reference snippet
app.MapRazorComponents<App>()
    .AddInteractiveServerRenderMode()
    .AddFabrCoreSurfaceRoutes();
OperationsDesk.Web/Program.cs · downloadable checkpoint
using FabrCore.Host;
using FabrCore.Surface;
using FabrCore.Surface.Services;
using OperationsDesk.Web.Components;
var builder = WebApplication.CreateBuilder(args);
if (!builder.Environment.IsDevelopment())
    throw new InvalidOperationException("Configure authenticated Surface principal identity before deploying this development sample.");
builder.WebHost.UseUrls("http://localhost:5099");
builder.Services.AddRazorComponents().AddInteractiveServerComponents();
builder.AddFabrCoreServer();
builder.AddFabrCoreSurface(options => {
    options.DevelopmentFallbackPrincipalId = "dev";
    options.CommandCenterChatDeliveryMode = SurfaceChatDeliveryMode.RequestResponse;
});
builder.Services.AddFabrCoreSurfaceComponents();
var app = builder.Build();
app.UseStaticFiles();
app.UseAntiforgery();
app.UseFabrCoreServer();
app.MapRazorComponents<App>().AddInteractiveServerRenderMode().AddFabrCoreSurfaceRoutes();
app.Run();
OperationsDesk.Web/Components/App.razor · downloadable checkpoint
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><base href="/" />
<link href="_content/FabrCore.Surface/surface.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css" rel="stylesheet" />
<HeadOutlet @rendermode="InteractiveServer" /></head><body>
<Routes @rendermode="InteractiveServer" />
<script src="_framework/blazor.web.js"></script>
</body></html>
OperationsDesk.Web/Components/Routes.razor · downloadable checkpoint
<Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="[typeof(SurfaceCommandCenter).Assembly]">
  <Found Context="routeData"><RouteView RouteData="routeData" /><FocusOnNavigate RouteData="routeData" Selector="h1" /></Found>
  <NotFound><h1>Page not found</h1></NotFound>
</Router>

Open the page and send the first message

  1. Stop the standalone sample before starting OperationsDesk.Web, because their default Localhost Orleans ports overlap. Run the Web sample's guide launch profile and browse http://localhost:5099.
  2. Open the request page, launch chat and create the example agent if prompted. Send “Blazor check SR-1042” and expect the echo reply in the panel.
  3. Reload the page and compare the workspace's agent/history state. Inspect server logs if the panel opens but cannot create or message an instance.

This verifies the integrated server path. It does not require exposing Orleans to the browser or adding a custom browser WebSocket client.

If the result is different

Check the Blazor web script, render mode and Surface registration if controls render but do nothing. Do not register a singleton transcript shared across users.

Go deeper

Explore the related documentation.