Section 1 — Official Anthropic C# SDK Fundamentals
Summary — what this page covers The foundation for everything on Day 2: install and wire up the official Anthropic NuGet package, make single- and multi-turn calls, build a
ClaudeServiceabstraction, manage conversation history, and apply prompt caching and Polly retries. Get to a working API call within the first 20 minutes. Pair with Lab 1.
9:00 – 10:30 AM · 90 min — 45 min lecture/demo + 45 min lab
Learning objectives
- Install/configure the official Anthropic NuGet package in ASP.NET Core
- Register
AnthropicClientvia DI with the options pattern - Make async single-turn and multi-turn calls
- Design a
ClaudeServiceabstraction following .NET best practices - Manage conversation history across HTTP requests (
IDistributedCache) - Apply prompt caching to cut cost on repeated system prompts
- Handle errors, rate limits, transient failures with Polly
- Understand
IChatClientfromMicrosoft.Extensions.AI
Content
Block 1A — SDK landscape & setup (≈20 min)
The .NET SDK landscape. Use the official Anthropic package (v12.x) — it's the one
Anthropic maintains and the one this workshop targets. Community options exist (Anthropic.SDK,
Claudia) and are fine, but the official package is the reference. ⚠️ Watch the name: the old
tryAGI.Anthropic v3.x is a different lineage — don't pull it by mistake.
Install & setup. Add the package, store the key in user-secrets (never commit it), bind it with the options pattern, and register the client in DI:
dotnet add package Anthropic
using Anthropic;
// Bind Anthropic:ApiKey from configuration/user-secrets via the options pattern,
// then register the client. AnthropicClient reads ANTHROPIC_API_KEY by default,
// or set it explicitly from your bound options.
builder.Services.AddSingleton(new AnthropicClient {
ApiKey = builder.Configuration["Anthropic:ApiKey"]
});
Register
AnthropicClientas a Singleton. It holds anHttpClientinternally — registering it Scoped or Transient creates a new socket per request and leads to socket exhaustion under load. This is the same reason you useIHttpClientFactoryelsewhere. YourIClaudeServicewrapper can be Scoped; the client underneath is Singleton.
Block 1B — First API calls (≈35 min)
Single-turn message call. Everything goes through client.Messages.Create: pick a model, set a
max-tokens ceiling, pass the messages. Read response.Usage for the token counts (and cost):
using Anthropic.Models.Messages;
var response = await client.Messages.Create(new MessageCreateParams {
Model = Model.ClaudeSonnet4_6, // default for app features; Haiku for cheap, Opus for hard
MaxTokens = 1024,
Messages = [new() { Role = Role.User, Content = "Recommend a book like Dune." }],
});
// ContentBlock is a union — filter to the text blocks
foreach (var text in response.Content.Select(b => b.Value).OfType<TextBlock>())
Console.WriteLine(text.Text);
Console.WriteLine($"in: {response.Usage.InputTokens}, out: {response.Usage.OutputTokens}");
System prompts & multi-turn. The system prompt is your assistant's constructor — it scopes
the assistant to BookTracker once, up front. The API is stateless, so multi-turn means you
keep the history: IClaudeService maps your stored history → a message list and appends the new
user turn on every call.
Prompt caching. Mark stable, reused content (the system prompt, RAG context, few-shot examples)
with CacheControlEphemeral and pay up to ~90% less for the cached input on repeat calls:
System = new List<TextBlockParam> {
new() { Text = longSystemPrompt, CacheControl = new CacheControlEphemeral() },
},
Cache when the prefix is stable and ≥ ~1,000 tokens and shared across requests. Verify it's
working by reading response.Usage.CacheCreationInputTokens (first call) then
CacheReadInputTokens (subsequent calls).
Block 1C — Error handling & chat endpoint (≈25 min)
Polly retry. Wrap calls in a retry policy for 429 (rate limit) and 529 (overloaded) — both are transient and safe to retry with exponential backoff. (The SDK also retries 429/5xx automatically with a default of 2 retries; add Polly when you want custom backoff or jitter.)
Wire /api/chat. A Minimal API endpoint that takes a user message + session id, loads history
from IDistributedCache, calls IClaudeService, persists the new turn, and returns the reply.
IChatClientfromMicrosoft.Extensions.AI. The official SDK also plugs into the provider-agnosticIChatClientabstraction — useful if you want to swap providers or use the broader Microsoft.Extensions.AI tooling. We use the nativeAnthropicClientdirectly today for full access to caching, tools, and streaming.
Demos referenced here
- First working call · Multi-turn with persisted history · Prompt-cache token counts
(show
CacheCreationInputTokensthenCacheReadInputTokens). [Scripts in_instructor/demo-plan.md.]
→ Continue to Lab 1.