The scenario is anything but theoretical: your product runs on Azure, a large customer imposes their AWS infrastructure, and the data team wants Claude for the quality of its long-form answers. Without an abstraction, that’s three codebases. With Microsoft.Extensions.AI, it’s three lines of configuration — because all three providers now ship their own IChatClient adapter.
After tools and middleware, here is the multi-cloud episode: Azure AI Foundry, Anthropic and AWS Bedrock, plugged into the same socket. Not rocket science.
The contract: one business core, several adapters
The whole value of this episode fits in this signature:
// Your application knows ONLY this:
async Task<string> AnalyzeOrder(IChatClient client, Order order)
{
var result = await client.GetResponseAsync<OrderAnalysis>(
$"Analyze this order and flag anomalies: {order.ToJson()}");
return result.Result.Summary;
}
The rest of the article merely builds different IChatClient instances for that same function.
Azure AI Foundry: the mothership
The standard path goes through Azure.AI.OpenAI and — non-negotiable best practice — keyless Entra ID authentication:
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Extensions.AI;
IChatClient foundry = new AzureOpenAIClient(
new Uri("https://my-project.openai.azure.com"),
new DefaultAzureCredential())
.GetChatClient("gpt-5-mini") // the name of YOUR deployment
.AsIChatClient();
A detail that changes the game in 2026: the same Foundry resource also serves the Foundry Models catalog — DeepSeek, Llama, Mistral and even Claude can be deployed behind the same OpenAI-compatible endpoint. One Azure entry point, several model families.
Anthropic: the official SDK
Since 2026, Anthropic maintains an official C# SDK — the Anthropic NuGet package (careful: versions ≤ 3.x of that name were a community package, since relocated to tryAGI.Anthropic). MEAI integration is built in:
using Anthropic;
using Microsoft.Extensions.AI;
// Reads ANTHROPIC_API_KEY from the environment
IChatClient claude = new AnthropicClient()
.AsIChatClient("claude-opus-4-8")
.AsBuilder()
.UseFunctionInvocation()
.Build();
Cross-cloud cherry on top: the SDK ships Anthropic.Foundry, Anthropic.Bedrock and Anthropic.Vertex flavors — the same Claude, consumed through whichever cloud your IT department already signed off on.
AWS Bedrock: the official AWS adapter
AWS publishes AWSSDK.Extensions.Bedrock.MEAI, which lays the MEAI interface directly on the Bedrock Runtime client (Converse API underneath, IAM for authentication):
using Amazon;
using Amazon.BedrockRuntime;
using Microsoft.Extensions.AI;
IChatClient bedrock = new AmazonBedrockRuntimeClient(RegionEndpoint.EUCentral1)
.AsIChatClient(); // model picked via ChatOptions.ModelId,
// e.g. "anthropic.claude-sonnet-4-5-v1:0" or "amazon.nova-pro-v1:0"
The switch: configuration, not code
Assembled in DI, the provider choice becomes one line of appsettings.json:
builder.Services.AddChatClient(services =>
{
IChatClient inner = config["AI:Provider"] switch
{
"foundry" => BuildFoundryClient(config),
"anthropic" => BuildAnthropicClient(config),
"bedrock" => BuildBedrockClient(config),
_ => throw new InvalidOperationException("Unknown AI:Provider")
};
return inner.AsBuilder()
.UseDistributedCache()
.UseFunctionInvocation()
.UseOpenTelemetry()
.Build(services);
});
Note what the switch preserves: the entire pipeline from episode 2 — tools, caching, telemetry — applies to all three clouds without one extra line. Need several providers simultaneously (one for cheap triage, another for deep analysis)? .NET keyed services do the job: AddKeyedChatClient("triage", …).
What leaks anyway
The interface unifies the call, not the operating context:
| What changes | Consequence |
|---|---|
| Model identifiers | gpt-5-mini (deployment) vs claude-opus-4-8 vs anthropic.claude-…-v1:0 — externalize them into config |
| Model behavior | a prompt tuned for GPT isn’t tuned for Claude or Nova — re-run your evals on every switch |
| Price and quotas | the price is per token and varies tenfold |
| Proprietary options | exotic settings go through RawRepresentationFactory — you still need an eye on the provider’s docs |
| Data residency | region, compliance, DPAs: legal doesn’t abstract away |
A word of honesty
- “Same code” doesn’t mean “same behavior”: MEAI portability is syntactic. Semantic portability — equivalent quality from one model to the next — is earned with an eval suite, not an interface.
- The Anthropic C# SDK is official but still labeled beta (versions 10+): pin the version and read the release notes before upgrading.
In short
- Three clouds, three official adapters:
Azure.AI.OpenAI(+ Entra ID),Anthropic(official SDK,AsIChatClient),AWSSDK.Extensions.Bedrock.MEAI. - Switching providers = one configuration entry; the middleware pipeline stays identical.
- One Azure AI Foundry resource also serves DeepSeek, Llama, Mistral, Claude through the same endpoint; Claude also comes in Foundry/Bedrock/Vertex flavors.
- What leaks: model names, behaviors, prices, options, compliance — manage them with config and evals.
Tomorrow we cut the cord: Ollama and Foundry Local, or how to run everything we’ve seen on your own machine — zero cloud, zero API key, and the awkward question: how much VRAM? And that, honestly… is not rocket science.