Connecting to Each from .NET
Key Points
Microsoft.Extensions.AI.OpenAI— first-party for OpenAI + Azure OpenAI.- Anthropic, Google, AWS Bedrock: community NuGets or OpenAI-compatible endpoints.
- OpenAI-compatible is the universal wire format — Together, Groq, Fireworks, Ollama, vLLM, Mistral all support.
- Wrap into
IChatClientfor vendor-portable code.
OpenAI / Azure OpenAI
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.*" />
<PackageReference Include="Azure.AI.OpenAI" Version="2.*" />
// OpenAI direct
IChatClient chat = new OpenAIClient(apiKey).AsChatClient("gpt-4o-mini");
// Azure OpenAI with managed identity
IChatClient azureChat = new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.AsChatClient(deploymentName);
Anthropic Claude
No first-party MS SDK. Options:
1. Community Anthropic SDK + adapter
// Anthropic.SDK
public class AnthropicChatClientAdapter(AnthropicClient inner) : IChatClient
{
public async Task<ChatResponse> GetResponseAsync(IEnumerable<ChatMessage> messages, ChatOptions? options = null, CancellationToken ct = default)
{
// Map ChatMessage → Anthropic Message
// Call inner.Messages.GetClaudeMessageAsync
// Map response back
}
}
2. AWS Bedrock (Claude hosted)
// AWSSDK.BedrockRuntime
var bedrock = new AmazonBedrockRuntimeClient(region);
// Adapter to IChatClient
3. Vertex AI (Claude available there too)
Google Gemini
// Mscc.GenerativeAI (community)
var gemini = new GoogleAI(apiKey);
var model = gemini.GenerativeModel(Model.Gemini25Pro);
var resp = await model.GenerateContent("Hello");
Vertex AI:
// Google.Cloud.AIPlatform.V1
var client = new PredictionServiceClientBuilder { Endpoint = "us-central1-aiplatform.googleapis.com" }.Build();
AWS Bedrock
Hosts Anthropic, Meta Llama, Mistral, Amazon Nova, Stability AI.
// AWSSDK.BedrockRuntime
var client = new AmazonBedrockRuntimeClient();
var resp = await client.InvokeModelAsync(new InvokeModelRequest { ModelId = "anthropic.claude-sonnet-4-...", Body = ... });
Adapter to IChatClient worth building once.
OpenAI-compatible endpoints
Many providers expose OpenAI-compatible API: same SDK, different baseUrl + key.
// Together AI
new OpenAIClient(
new ApiKeyCredential(togetherKey),
new OpenAIClientOptions { Endpoint = new Uri("https://api.together.xyz/v1") })
.AsChatClient("meta-llama/Llama-3.3-70B-Instruct-Turbo");
// Groq
new OpenAIClient(
new ApiKeyCredential(groqKey),
new OpenAIClientOptions { Endpoint = new Uri("https://api.groq.com/openai/v1") })
.AsChatClient("llama-3.3-70b-versatile");
// Mistral
new OpenAIClient(
new ApiKeyCredential(mistralKey),
new OpenAIClientOptions { Endpoint = new Uri("https://api.mistral.ai/v1") })
.AsChatClient("mistral-large-latest");
// Fireworks AI
new OpenAIClient(/* same pattern */);
Massive portability via OpenAI-compatible.
Ollama (local)
ONNX Runtime GenAI (Phi)
var model = new Model("/path/to/phi-4-onnx");
// (Custom IChatClient adapter; community packages exist)
Pipeline pattern
Same regardless of provider:
chat = chat.AsBuilder()
.UseFunctionInvocation() // tool calls
.UseLogging(loggerFactory)
.UseOpenTelemetry(/* GenAI conventions */)
.UseDistributedCache(redisCache)
.Build();
Switch provider → keep pipeline.
Multi-provider routing
public class MultiChatClient(IDictionary<string, IChatClient> clients) : IChatClient
{
public Task<ChatResponse> GetResponseAsync(/* ... */, ChatOptions? options, CancellationToken ct)
{
var provider = options?.AdditionalProperties?["provider"]?.ToString() ?? "default";
return clients[provider].GetResponseAsync(/* ... */, options, ct);
}
}
builder.Services.AddSingleton<IChatClient>(new MultiChatClient(new Dictionary<string, IChatClient>
{
["openai"] = openAiClient,
["anthropic"] = anthropicClient,
["default"] = openAiClient
}));
Or fallback:
Authentication patterns
| Provider | Auth |
|---|---|
| OpenAI | API key |
| Azure OpenAI | API key OR managed identity (preferred) |
| Anthropic | API key |
| Google AI Studio | API key |
| Vertex AI | Service Account / Workload Identity |
| AWS Bedrock | IAM role / SDK |
| Together / Groq | API key |
| Ollama (local) | none |
Configuration
"AI": {
"Provider": "azure-openai",
"AzureOpenAI": { "Endpoint": "https://...", "Deployment": "gpt-4o-mini" },
"OpenAI": { "ApiKey": "@KeyVault(...)", "Model": "gpt-4o-mini" },
"Anthropic": { "ApiKey": "@KeyVault(...)", "Model": "claude-4-sonnet" }
}
Senior consideration
Build the provider abstraction once. Use config to swap. Test against multiple providers in CI to catch breakage.