Skip to content

Commit 0e89141

Browse files
Fix 6.1 blog: correct OllamaSharp vs Microsoft.Extensions.AI narrative
1 parent 38f7f2b commit 0e89141

1 file changed

Lines changed: 15 additions & 11 deletions

File tree

blogs/series-6-ai-app-features/6.1-dotnet-ai-foundation.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
# Run a Local LLM in Your .NET 10 API with Ollama
22

3-
## How Microsoft.Extensions.AI Makes Your API AI-Ready Without Locking You Into One Provider
3+
## How OllamaSharp and a Custom Service Interface Make Your .NET 10 API AI-Ready
44

55
Every developer wants AI in their app. The problem is getting started: API keys, cloud costs, rate limits, and the fear of betting your architecture on one vendor. What if you could add a working AI endpoint to your .NET 10 API in under an hour — for free, running entirely on your laptop?
66

7-
This article shows you exactly how, using [Ollama](https://ollama.com) for a local LLM and `Microsoft.Extensions.AI` as a provider-agnostic abstraction.
7+
This article shows you exactly how, using [Ollama](https://ollama.com) for a local LLM and [OllamaSharp](https://github.com/awaescher/OllamaSharp) as the .NET client library.
88

99
📖 **Tutorial Repository:** [AngularNetTutorial on GitHub](https://github.com/workcontrolgit/AngularNetTutorial)
1010

@@ -16,11 +16,11 @@ This article is part of the **AngularNetTutorial** series. The full-stack tutori
1616

1717
## 🎓 What You'll Learn
1818

19-
* **Microsoft.Extensions.AI abstraction** — How `IChatClient` lets you swap LLM providers by changing one line
19+
* **OllamaSharp streaming** — How `IOllamaApiClient` streams tokens from Ollama using `IAsyncEnumerable<>` so responses appear progressively, not all at once
2020
* **Ollama integration** — Pull a free local model and connect it to your .NET API in minutes
2121
* **Feature flag gating** — Why `[FeatureGate("AiEnabled")]` is the safest way to ship AI without breaking existing users
2222
* **Clean Architecture placement** — Where AI interfaces, implementations, and controllers belong in the layer structure
23-
* **Provider-agnostic DI** — How to register `AddOllamaChatClient()` so the rest of the app never knows which provider you're using
23+
* **Custom `IAiChatService` interface** — How defining your own service interface in the Application layer hides OllamaSharp from callers and makes the implementation swappable
2424

2525
---
2626

@@ -54,16 +54,18 @@ Beyond getting started, there's an architectural risk: if your AI code reaches d
5454

5555
## 💡 The Solution
5656

57-
[Microsoft.Extensions.AI](https://learn.microsoft.com/en-us/dotnet/ai/microsoft-extensions-ai) provides a single `IChatClient` interface that works identically across providers. Register `AddOllamaChatClient()` in development, `AddAzureOpenAIChatClient()` in productionyour `IAiChatService` implementation doesn't change.
57+
[OllamaSharp](https://github.com/awaescher/OllamaSharp) is a .NET client for Ollama that exposes `IOllamaApiClient` and native token streaming via `IAsyncEnumerable<>`. We use it directly in `Infrastructure.Shared`one package, no additional provider abstraction library needed.
5858

5959
[Ollama](https://ollama.com) runs open-weight models like `llama3.2` locally. No API key. No cloud. Works offline. Perfect for tutorials and development.
6060

61+
Provider independence comes from our own `IAiChatService` interface defined in the Application layer. `OllamaAiService` implements it using OllamaSharp. To swap providers (e.g., Azure OpenAI in production), you write a new implementation of `IAiChatService` in Infrastructure.Shared and change the DI registration — the Application layer, handlers, and controller are untouched.
62+
6163
We gate the entire `AiController` behind a `[FeatureGate("AiEnabled")]` attribute. When `"AiEnabled": false` (the default), the controller doesn't even respond to requests — no Ollama connection is attempted, the rest of the API is unaffected.
6264

6365
**Key benefits:**
6466

6567
***Zero cost** — Ollama is free; no API key, no credit card, no rate limits
66-
***Provider-agnostic**Swap Ollama → Azure OpenAI → Anthropic by changing one DI registration line
68+
***Provider-independent Application layer**`IAiChatService` hides OllamaSharp from all callers; swap the implementation without touching handlers or controllers
6769
***Safe coexistence** — Feature flag default `false` means original tutorial (Series 0–5) works unchanged
6870
***Clean Architecture** — Interface in Application, implementation in Infrastructure.Shared, controller in WebApi
6971

@@ -340,7 +342,7 @@ Click **POST /api/v1/ai/chat**, then **Try it out**, and send:
340342

341343
![Swagger UI POST /api/v1/ai/chat endpoint — request body schema with message and systemPrompt fields](../../Tests/AngularNetTutorial-Playwright/screenshots-output/series-2-dotnet-api/swagger-ai-chat-endpoint.png)
342344

343-
Click **POST /api/v1/ai/chat**, then **Try it out**, and send:
345+
Expand **POST /api/v1/ai/chat**, click **Try it out**, and send:
344346

345347
```json
346348
{
@@ -374,25 +376,27 @@ curl -X POST https://localhost:44378/api/v1/ai/chat \
374376

375377
**After this approach:**
376378

377-
* ✅ Swap Ollama for Azure OpenAI in production by changing one DI lineapplication code unchanged
379+
* ✅ Swap Ollama for Azure OpenAI in production by writing a new `IAiChatService` implementation and updating one DI registrationApplication layer and controller unchanged
378380
* ✅ Zero-cost, zero-signup AI during development — every tutorial reader can follow along
379381
* ✅ Feature flag default `false` means the full Series 0–5 stack runs unchanged — AI is opt-in
380382

381383
---
382384

383385
## 🌟 Why This Matters
384386

385-
The `IChatClient` abstraction from Microsoft is the `.NET HTTP Client` of AI — a standard interface the ecosystem is aligning around. By building on it now, your code is forward-compatible with whatever provider becomes the best choice in 12 months.
387+
OllamaSharp's native `IAsyncEnumerable<>` streaming means tokens appear progressively as Ollama generates them — critical when a local model takes several seconds per response. Buffering the entire reply before returning it would feel broken to users.
388+
389+
The custom `IAiChatService` interface pattern is the key architectural decision. It places the Ollama dependency entirely inside `Infrastructure.Shared`. Application-layer code (handlers, queries) and the controller depend only on the interface — they are completely unaware of OllamaSharp. When you are ready to move to a cloud provider (Azure OpenAI, Anthropic), you add a new infrastructure implementation and update one DI registration. Nothing else changes.
386390

387391
For tutorial purposes, Ollama removes the biggest barrier to learning: access. Every developer on every OS can pull `llama3.2`, type `ollama serve`, and have a working LLM in their local environment. No billing, no configuration, no waiting for API access.
388392

389393
The feature flag pattern ensures this is safe to ship: the codebase always builds, always runs, and the original Series 0–5 experience is completely unchanged. AI features activate on demand.
390394

391395
**Transferable skills:**
392396

393-
* **Provider-agnostic AI abstractions** — The `IChatClient` pattern applies equally to Azure OpenAI, Anthropic, Google, and Hugging Face endpoints
397+
* **Custom service interface for AI** — The `IAiChatService` pattern applies to any AI provider; define the contract in Application, implement in Infrastructure
394398
* **Feature flag architecture** — The `[FeatureGate]` pattern applies to any experimental or optional feature
395-
* **Clean Architecture for external services** — Interface in Application, implementation in Infrastructure, provider registration in WebApi
399+
* **Clean Architecture for external services** — Interface in Application, implementation in Infrastructure, DI registration in WebApi
396400

397401
---
398402

0 commit comments

Comments
 (0)