You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: blogs/series-6-ai-app-features/6.1-dotnet-ai-foundation.md
+15-11Lines changed: 15 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,10 +1,10 @@
1
1
# Run a Local LLM in Your .NET 10 API with Ollama
2
2
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
4
4
5
5
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?
6
6
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.
8
8
9
9
📖 **Tutorial Repository:**[AngularNetTutorial on GitHub](https://github.com/workcontrolgit/AngularNetTutorial)
10
10
@@ -16,11 +16,11 @@ This article is part of the **AngularNetTutorial** series. The full-stack tutori
16
16
17
17
## 🎓 What You'll Learn
18
18
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
20
20
***Ollama integration** — Pull a free local model and connect it to your .NET API in minutes
21
21
***Feature flag gating** — Why `[FeatureGate("AiEnabled")]` is the safest way to ship AI without breaking existing users
22
22
***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
24
24
25
25
---
26
26
@@ -54,16 +54,18 @@ Beyond getting started, there's an architectural risk: if your AI code reaches d
54
54
55
55
## 💡 The Solution
56
56
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 production — your `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.
58
58
59
59
[Ollama](https://ollama.com) runs open-weight models like `llama3.2` locally. No API key. No cloud. Works offline. Perfect for tutorials and development.
60
60
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
+
61
63
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.
62
64
63
65
**Key benefits:**
64
66
65
67
* ✅ **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
67
69
* ✅ **Safe coexistence** — Feature flag default `false` means original tutorial (Series 0–5) works unchanged
68
70
* ✅ **Clean Architecture** — Interface in Application, implementation in Infrastructure.Shared, controller in WebApi
69
71
@@ -340,7 +342,7 @@ Click **POST /api/v1/ai/chat**, then **Try it out**, and send:
340
342
341
343

342
344
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:
344
346
345
347
```json
346
348
{
@@ -374,25 +376,27 @@ curl -X POST https://localhost:44378/api/v1/ai/chat \
374
376
375
377
**After this approach:**
376
378
377
-
* ✅ Swap Ollama for Azure OpenAI in production by changing one DI line — application code unchanged
379
+
* ✅ Swap Ollama for Azure OpenAI in production by writing a new `IAiChatService` implementation and updating one DI registration — Application layer and controller unchanged
378
380
* ✅ Zero-cost, zero-signup AI during development — every tutorial reader can follow along
379
381
* ✅ Feature flag default `false` means the full Series 0–5 stack runs unchanged — AI is opt-in
380
382
381
383
---
382
384
383
385
## 🌟 Why This Matters
384
386
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.
386
390
387
391
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.
388
392
389
393
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.
390
394
391
395
**Transferable skills:**
392
396
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
394
398
***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
0 commit comments