Add ChatGPT-style chat interface using MudBlazor components. User messages display on the right (purple), bot echoes "success msg!" on the left. Includes app bar, centered 768px layout, bottom-anchored messages, and documented inline comments on every Blazor concept introduced. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
97 lines
4.6 KiB
Markdown
97 lines
4.6 KiB
Markdown
# Architecture Decisions
|
|
|
|
## Blazor Hosting Model: Server vs WebAssembly
|
|
|
|
### How They Differ
|
|
|
|
| Aspect | Blazor Server | Blazor WASM |
|
|
|--------|--------------|-------------|
|
|
| Code runs | On the server | In the browser |
|
|
| UI updates | Via SignalR WebSocket (server pushes diffs) | Locally in browser (no round-trip) |
|
|
| Calling backend services | Direct — code is already server-side | Needs HTTP calls if accessing server resources |
|
|
| Offline capable | No (requires persistent connection) | Yes |
|
|
| Startup speed | Fast | Slower (downloads .NET runtime to browser) |
|
|
|
|
### Decision: Blazor WASM
|
|
|
|
This project uses **Blazor WebAssembly (standalone)** with a separate ASP.NET Core Web API backend.
|
|
|
|
## When Do You Need a Separate API Project?
|
|
|
|
There are two distinct concerns that are easy to conflate:
|
|
|
|
### 1. Consuming an External API (e.g. OpenAI)
|
|
|
|
Both Blazor Server and WASM can call external APIs directly from C# — no controller needed. The difference is **where that code executes**:
|
|
|
|
- **Blazor Server**: Code runs on the server. A service class calls OpenAI directly. API keys live safely in server memory. No controller, no exposed endpoint required.
|
|
- **Blazor WASM**: Code runs in the browser. You *can* call OpenAI directly, but any **API key would be embedded in the browser download** — anyone could inspect it via browser dev tools. This is the primary reason to add a backend proxy.
|
|
|
|
### 2. Exposing an API Endpoint (e.g. ChatAgent.Api)
|
|
|
|
This is a separate concern. You expose an API endpoint when:
|
|
|
|
- Another application needs to communicate with your chat system
|
|
- You want a REST API for mobile clients, scripts, or integrations
|
|
- You need a server-side proxy to protect secrets from the browser (the WASM case above)
|
|
|
|
**Key insight:** You don't need an API endpoint to *use* an external service. You only need one in WASM to **keep secrets out of the browser**.
|
|
|
|
### 3. Component Updates Do Not Require an API
|
|
|
|
In both hosting models, Blazor components update themselves locally:
|
|
|
|
- Components hold state in fields/properties
|
|
- Calling `StateHasChanged()` triggers a re-render
|
|
- Components can call injected C# services directly
|
|
- No HTTP round-trip is needed for UI updates
|
|
|
|
For example, a chat component that echoes "success msg!" back needs no API at all — a simple injected service handles it entirely within the client project.
|
|
|
|
## API Key Management Scenarios
|
|
|
|
The need for an API project in WASM depends on how secrets are managed:
|
|
|
|
| Scenario | WASM needs API project? | Why |
|
|
|----------|------------------------|-----|
|
|
| Raw API key in config | Yes | To keep the key out of browser-downloadable code |
|
|
| Azure Key Vault | Yes | Browser sandbox cannot access Key Vault or managed identity |
|
|
| API Management gateway (Azure APIM) with token auth | No | WASM calls the gateway directly; gateway handles auth via managed identity |
|
|
| Blazor Server (any scenario) | No | Code is already server-side; secrets never leave the server |
|
|
|
|
### Enterprise Pattern: API Gateway
|
|
|
|
In enterprise environments, a common pattern avoids the need for a custom API proxy entirely:
|
|
|
|
1. An **API Management gateway** (e.g. Azure APIM) sits in front of the external service (e.g. OpenAI)
|
|
2. The gateway authenticates via managed identity and handles secret retrieval
|
|
3. The gateway exposes a public endpoint requiring only a subscription key or OAuth token
|
|
4. WASM calls the gateway directly — no secrets in the browser, no custom API project needed
|
|
|
|
The "proxy" becomes infrastructure rather than application code.
|
|
|
|
## Current Project Structure
|
|
|
|
```
|
|
ChatAgent.sln
|
|
src/
|
|
ChatAgent.Client/ -- Blazor WASM (standalone)
|
|
Pages/ -- Routable page components
|
|
Layout/ -- MainLayout, NavMenu
|
|
Services/ -- Client-side services (e.g. ChatApiClient)
|
|
Program.cs -- Client entry point, DI registration
|
|
ChatAgent.Api/ -- ASP.NET Core Web API (backend proxy)
|
|
Controllers/ -- API controllers (e.g. HealthController)
|
|
Program.cs -- Server entry point, middleware config
|
|
ChatAgent.Shared/ -- Models shared between Client and Api
|
|
Models/ -- DTOs (e.g. HealthResponse)
|
|
```
|
|
|
|
### Why Three Projects?
|
|
|
|
- **ChatAgent.Client**: The Blazor WASM app running in the browser
|
|
- **ChatAgent.Api**: Exists to proxy requests that require server-side secrets (e.g. future OpenAI calls). Not needed for basic component interactions.
|
|
- **ChatAgent.Shared**: Models referenced by both Client and Api, avoiding duplication
|
|
|
|
For the initial "echo success" phase, only ChatAgent.Client is actively used. The Api and Shared projects exist to support future integration with external services that require secret management.
|