12 KiB
Stack Research
Domain: Blazor WebAssembly AI Chat Application (.NET / C#) Researched: 2026-03-27 Confidence: HIGH (core stack verified via NuGet and official Microsoft docs; version numbers confirmed via nuget.org)
Recommended Stack
Core Technologies
| Technology | Version | Purpose | Why Recommended |
|---|---|---|---|
| .NET 9 SDK | 9.x (latest patch) | Runtime, tooling, SDK | LTS-adjacent, stable, .NET 10 is in preview — stay on 9 for a tutorial project targeting a stable foundation |
| Blazor WebAssembly Standalone | .NET 9 | Client SPA running in-browser | Non-negotiable per project constraints; client-side execution with no server round-trip for UI |
| ASP.NET Core Web API | .NET 9 | Backend proxy for OpenAI calls | Required to keep the OpenAI API key server-side; WASM cannot access secrets directly |
| C# 13 | Included with .NET 9 | Application language | Included in .NET 9 SDK; no separate install needed |
Critical architecture note: The "hosted Blazor WebAssembly" template (single .sln with Client + Server + Shared projects) was removed in .NET 8. In .NET 9, you create two separate projects manually: a dotnet new blazorwasm standalone client and a dotnet new webapi backend, then add them to a solution. This is the correct approach for this project.
OpenAI Integration
| Library | Version | Purpose | Why Recommended |
|---|---|---|---|
OpenAI (official) |
2.9.1 | OpenAI API client with streaming | The official OpenAI-published .NET library; supports CompleteChatStreamingAsync() returning AsyncCollectionResult<StreamingChatCompletionUpdate> via await foreach; stable release as of 2026-03-02 |
Do not use OpenAI-DotNet (version 8.8.8) — this is an unofficial community package with a different API surface. The official OpenAI package is published directly by OpenAI and is the correct choice.
Streaming mechanism: The backend Web API endpoint calls CompleteChatStreamingAsync() and proxies chunks to the client. The WASM client uses HttpCompletionOption.ResponseHeadersRead with SetBrowserResponseStreamingEnabled(true) on the HttpRequestMessage to consume the streamed response. In .NET 10 streaming is enabled by default; in .NET 9 it must be explicitly opted in per-request.
Markdown Rendering
| Library | Version | Purpose | Why Recommended |
|---|---|---|---|
Markdig |
1.1.1 | Parse markdown text to HTML | The de facto standard markdown processor for .NET; CommonMark-compliant, fast, extensible, targets .NET Standard 2.0 so works in WASM; used by Microsoft and Syncfusion as the underlying engine |
How it integrates in Blazor: Call Markdig.Markdown.ToHtml(content) on the client, render the result with @((MarkupString)htmlContent) in a Razor component. No JS interop needed.
UI Component Library
| Library | Version | Purpose | Why Recommended |
|---|---|---|---|
MudBlazor |
9.2.0 | Material Design component library | Full .NET 9 support confirmed; pure C# with minimal JavaScript; comprehensive chat-friendly components (MudTextField, MudPaper, MudScrollToBottom, MudList); large community; no per-seat licensing |
Alternative considered: Radzen Blazor (free, good) and Telerik UI for Blazor (licensed). MudBlazor wins for a tutorial/personal project because it is free, has zero JS dependencies, and has excellent documentation for learners.
JSON Storage (Server-side)
| Technology | Version | Purpose | Why Recommended |
|---|---|---|---|
System.Text.Json |
Built into .NET 9 | Serialize/deserialize conversation history | Built-in, no extra dependency; JsonSerializerOptions with WriteIndented = true for human-readable files; async file I/O via File.ReadAllTextAsync / File.WriteAllTextAsync |
Storage lives entirely on the backend (Web API project). The WASM client cannot access the local filesystem — only the server can. API endpoints expose CRUD operations over conversations, with JSON files persisted in a configurable directory on the server host.
Supporting Libraries
| Library | Version | Purpose | When to Use |
|---|---|---|---|
Microsoft.Extensions.AI (abstractions) |
9.x preview | Optional AI abstraction layer | Skip for v1 — adds indirection before the core chat pattern is understood. Relevant for v2 when adding multi-provider support |
Blazored.LocalStorage |
latest | Browser local storage | Not needed for this project — persistence is on the server via JSON files, not the browser |
System.Net.ServerSentEvents |
Built into .NET 9 | SSE parser for streaming | Used automatically by the OpenAI library on the server; no direct usage needed |
Development Tools
| Tool | Purpose | Notes |
|---|---|---|
| Visual Studio 2022 (v17.12+) | IDE with Blazor hot reload | Recommended for tutorial builder; full Blazor debugging, component preview, and hot reload support |
| VS Code + C# Dev Kit | Lighter-weight alternative | Works well; use dotnet watch for hot reload |
dotnet watch run |
Hot reload during development | Run in both Client and Server project directories simultaneously |
dotnet-dev-certs |
HTTPS dev certificate | Required for local HTTPS; run dotnet dev-certs https --trust once |
Installation
# Create solution
mkdir ChatAgentApp && cd ChatAgentApp
dotnet new sln -n ChatAgentApp
# Create Blazor WASM client (standalone)
dotnet new blazorwasm -n ChatAgentApp.Client --framework net9.0
dotnet sln add ChatAgentApp.Client/ChatAgentApp.Client.csproj
# Create ASP.NET Core Web API backend
dotnet new webapi -n ChatAgentApp.Api --framework net9.0
dotnet sln add ChatAgentApp.Api/ChatAgentApp.Api.csproj
# Install OpenAI SDK in the API project
cd ChatAgentApp.Api
dotnet add package OpenAI --version 2.9.1
# Install Markdig in the Client project
cd ../ChatAgentApp.Client
dotnet add package Markdig --version 1.1.1
dotnet add package MudBlazor --version 9.2.0
Alternatives Considered
| Recommended | Alternative | When to Use Alternative |
|---|---|---|
OpenAI 2.9.1 (official) |
OpenAI-DotNet 8.8.8 (unofficial) |
Never — the official package is now stable and maintained by OpenAI directly |
OpenAI 2.9.1 (official) |
Azure.AI.OpenAI 2.1.0 |
When targeting Azure OpenAI Service specifically (e.g., enterprise, EU data residency, private endpoints) — overkill for this project |
Markdig |
CommonMark.NET |
Only if strict CommonMark compliance matters more than extensions; Markdig is a superset and the ecosystem standard |
MudBlazor |
Radzen Blazor | Radzen is fine; choose it if you already know it; MudBlazor has more learning resources |
MudBlazor |
Telerik UI for Blazor | Telerik requires a paid license; not appropriate for a personal tool |
| Standalone WASM + separate Web API | Blazor Web App template (unified) | Use the unified Blazor Web App template when you want mixed Server+WASM render modes on a single project; overkill for this project and obscures the WASM-specific patterns the tutorial aims to teach |
| JSON flat files (server-side) | SQLite via EF Core | SQLite is a better choice at scale; JSON is simpler for single-user personal tools and avoids introducing a migration workflow |
What NOT to Use
| Avoid | Why | Use Instead |
|---|---|---|
OpenAI-DotNet (unofficial) |
Different API surface, not maintained by OpenAI, version numbers create confusion | Official OpenAI NuGet package |
Microsoft.SemanticKernel |
Adds significant abstraction and dependency weight for a tutorial; streaming works but is complex to explain | Direct OpenAI SDK calls; add SK in v2 when orchestration is needed |
JavaScript EventSource API via JSInterop for streaming |
Blazor WASM has SetBrowserResponseStreamingEnabled which avoids JS interop; adding JSInterop for streaming increases complexity significantly |
HttpCompletionOption.ResponseHeadersRead + SetBrowserResponseStreamingEnabled(true) in the HTTP handler |
Newtonsoft.Json |
Unnecessary dependency; System.Text.Json is built into .NET 9 and is faster; Newtonsoft was the pre-.NET Core standard |
System.Text.Json (built-in) |
Blazored.LocalStorage for persistence |
Browser storage is limited (~5MB), cleared by users, and not suitable for chat history of any meaningful length; also exposes all data client-side | Server-side JSON file storage via the Web API |
| AOT compilation during learning phase | Dramatically increases build times; not needed until production optimization is a concern; confusing to introduce in a tutorial | Default IL interpretation; add AOT opt-in note in the final phase |
Stack Patterns by Variant
For streaming responses from the API backend to the WASM client:
- Backend streams OpenAI tokens as
text/event-stream(SSE) orapplication/x-ndjson - Client uses
SetBrowserResponseStreamingEnabled(true)onHttpRequestMessage - Client reads with
HttpCompletionOption.ResponseHeadersReadand iterates the stream - Trigger
StateHasChanged()in the component after each token to update the UI
For local JSON file storage on the server:
- Define a
ConversationRepositoryservice on the API that reads/writes from a configurable base path - Register as
Singleton(notScoped) since there is only one user and file access must be serialized - Use
SemaphoreSlim(1,1)to prevent concurrent write conflicts even in single-user mode
For markdown rendering in the client:
- Use
Markdig.Markdown.ToHtml(text, pipeline)wherepipelineis built withMarkdownPipelineBuilderenabling extensions (e.g.,UseAutoLinks(),UseEmojiAndSmiley()) - Render the HTML string using
@((MarkupString)html)inside a<div class="markdown-body">element - Apply CSS (GitHub Markdown CSS or custom) scoped to
.markdown-bodyfor code blocks and tables
Version Compatibility
| Package | Compatible With | Notes |
|---|---|---|
OpenAI 2.9.1 |
.NET Standard 2.0+ (.NET 9 confirmed) | Published 2026-03-02; requires System.Net.ServerSentEvents (built into .NET 9) |
Markdig 1.1.1 |
.NET 8.0, .NET Standard 2.0, .NET Framework 4.6.2 | .NET 9 compatible via .NET 8 TFM; published 2026-03-04 |
MudBlazor 9.2.0 |
.NET 8.0, .NET 9.0, .NET 10.0 | Published 2026-03-18; version 9.x = full support for .NET 9 |
| .NET 9 SDK | Blazor WASM + Web API in same solution | Both project types target net9.0; no cross-framework issues |
Sources
- https://www.nuget.org/packages/OpenAI — Official OpenAI NuGet package; version 2.9.1 confirmed (2026-03-02)
- https://github.com/openai/openai-dotnet — Official OpenAI .NET SDK; streaming API verified (
CompleteChatStreamingAsync,await foreach) - https://www.nuget.org/packages/Markdig — Markdig version 1.1.1 confirmed (2026-03-04)
- https://www.nuget.org/packages/MudBlazor — MudBlazor 9.2.0 confirmed; .NET 8/9/10 full support (2026-03-18)
- https://learn.microsoft.com/en-us/aspnet/core/blazor/hosting-models?view=aspnetcore-9.0 — Official Blazor hosting model docs; standalone WASM vs Blazor Web App distinction verified
- https://learn.microsoft.com/en-us/dotnet/core/compatibility/networking/10.0/default-http-streaming — Breaking change: WASM streaming opt-in (.NET 9) vs default (.NET 10)
- https://www.strathweb.com/2024/07/built-in-support-for-server-sent-events-in-net-9/ — SSE native support in .NET 9 via
System.Net.ServerSentEvents; used internally by OpenAI SDK (MEDIUM confidence, single source) - https://github.com/openai/openai-dotnet/issues/65 — Confirmed streaming issue in Blazor WASM requires
SetBrowserResponseStreamingEnabled(true)(MEDIUM confidence, GitHub issue thread) - https://devblogs.microsoft.com/dotnet/openai-dotnet-library/ — Official .NET Blog announcement of the OpenAI library
- https://dev.to/kazinix/blazor-web-app-webassembly-hosted-in-net8-and-net9-1k6g — Hosted template removal in .NET 8+, manual solution structure (MEDIUM confidence)
Stack research for: Blazor WebAssembly AI Chat Application Researched: 2026-03-27