181 lines
12 KiB
Markdown
181 lines
12 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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) or `application/x-ndjson`
|
|
- Client uses `SetBrowserResponseStreamingEnabled(true)` on `HttpRequestMessage`
|
|
- Client reads with `HttpCompletionOption.ResponseHeadersRead` and 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 `ConversationRepository` service on the API that reads/writes from a configurable base path
|
|
- Register as `Singleton` (not `Scoped`) 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)` where `pipeline` is built with `MarkdownPipelineBuilder` enabling 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-body` for 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*
|