If you're a .NET developer looking to break into AI engineering, agents are the single best place to start. They're the point where "calling an LLM API" turns into "building a system that reasons, uses tools, and takes action" β and Azure AI Foundry Agent Service, paired with .NET, makes this surprisingly approachable.
In this post, I'll walk through exactly how to stand up your first agent end-to-end β from the Azure side setup to the actual C# code β and share the full walkthrough in video form as well.
π₯ Watch the full hands-on video here: https://youtu.be/mrsEsculrNg
Why Agents, and Why Now
Most of us started our AI journey with a simple chat completion call β send a prompt, get text back. That's fine for Q&A, but it falls apart the moment you need the model to do something: run code, search documents, call an API, or hold a multi-turn conversation with real state.
That's exactly the gap Foundry Agent Service closes. An agent in Foundry is:
- Durable β it lives as a resource in your Foundry project, not in your app's memory
- Tool-aware β it can invoke built-in tools (like a code interpreter) or your own custom functions
- Stateful β conversations persist and carry context across turns
And the best part for us .NET folks: the entire thing is callable from clean, typed C# β no wrestling with raw REST payloads.
What You'll Need
Before writing any code, set up the Azure side:
-
An Azure AI Foundry project with a chat model deployed (e.g.,
gpt-4o-mini) - The Foundry User RBAC role assigned to your account at the resource/resource-group scope β this is the single most common blocker people hit (a silent 403 when calling the SDK), so don't skip it
-
az loginrun locally, so your code can authenticate without hardcoding any keys
If you've worked with Cognitive Services roles before, note that agent management needs this separate Foundry-specific role β that trips up a lot of people coming from plain Azure OpenAI usage.
Setting Up the .NET Project
dotnet new console -n FoundryAgentLab -f net10.0
cd FoundryAgentLab
dotnet add package Azure.AI.Projects
dotnet add package Azure.Identity
Set your environment variables:
export PROJECT_ENDPOINT="https://<your-resource>.services.ai.azure.com/api/projects/<your-project>"
export MODEL_DEPLOYMENT_NAME="gpt-4o-mini"
export AGENT_NAME="my-dotnet-agent"
Creating the Agent
using Azure.AI.Projects;
using Azure.AI.Projects.OpenAI;
using Azure.Identity;
string projectEndpoint = Environment.GetEnvironmentVariable("PROJECT_ENDPOINT")
?? throw new InvalidOperationException("Missing environment variable 'PROJECT_ENDPOINT'");
string modelDeploymentName = Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME")
?? throw new InvalidOperationException("Missing environment variable 'MODEL_DEPLOYMENT_NAME'");
string agentName = Environment.GetEnvironmentVariable("AGENT_NAME")
?? throw new InvalidOperationException("Missing environment variable 'AGENT_NAME'");
AIProjectClient projectClient = new(new Uri(projectEndpoint), new AzureCliCredential());
AgentDefinition agentDefinition = new PromptAgentDefinition(modelDeploymentName)
{
Instructions = "You are a helpful .NET/Azure tutor that answers general questions",
};
AgentVersion newAgentVersion = projectClient.Agents.CreateAgentVersion(
agentName,
options: new(agentDefinition));
Console.WriteLine($"Agent created β Id: {newAgentVersion.Id}, Version: {newAgentVersion.Version}");
A few things worth calling out here:
-
AIProjectClientis your single entry point into the project β agents, conversations, and responses all hang off it. -
PromptAgentDefinitionis a declarative agent β you describe its model and instructions, and Foundry handles the execution plumbing. - Notice the agent has a version. Every time you update it, Foundry keeps a version history β helpful when you're iterating on prompts and want to roll back.
Talking to the Agent
Creating the agent is half the story β now let's have an actual conversation with it, with context retained across turns:
using OpenAI.Responses;
// Create a conversation to maintain context across turns
ProjectConversation conversation = projectClient.OpenAI.Conversations.CreateProjectConversation();
// A responses client pre-bound to this agent and this conversation
ProjectResponsesClient responsesClient = projectClient.OpenAI.GetProjectResponsesClientForAgent(
defaultAgent: agentName,
defaultConversationId: conversation.Id);
ResponseResult response = responsesClient.CreateResponse("What is the size of France in square miles?");
Console.WriteLine(response.GetOutputText());
// Follow-up β same conversation, so context carries over
response = responsesClient.CreateResponse("And what is the capital city?");
Console.WriteLine(response.GetOutputText());
Run it, and you'll see the second answer correctly reference "it" back to France β no manual history management, no prompt-stuffing. That's the conversation object doing its job.
What Makes This "Agentic" Rather Than Just "A Chat Call"
It's a fair question β at this scale, it looks a lot like calling any chat API. The distinction shows up once you scale this pattern up:
- Attach built-in tools (code interpreter, file search, Bing grounding) and the model decides on its own when to invoke them
- Attach your own function tools, and the agent calls into your application code mid-conversation
- The agent persists as a named, versioned resource your whole team can reference β not a prompt buried in someone's script
This lab is deliberately the smallest possible slice of that β enough to get something real running today, with room to grow into tool-calling and multi-agent patterns next.
Wrapping Up
If you're a .NET developer eyeing a move toward AI engineering, this is a genuinely good on-ramp β the SDK is clean, the concepts map well onto things you already know (clients, DI-friendly patterns, typed models), and Foundry handles the infrastructure you'd otherwise have to hand-roll.
I go through this entire setup β including the Azure Portal steps, the RBAC gotcha, and debugging a couple of real errors β in the video below. If you're following along in Hindi/Hinglish, this one's for you:
π₯ https://youtu.be/mrsEsculrNg
If you found this useful, a like/subscribe on the channel genuinely helps β and drop a comment if you get stuck anywhere, I read all of them.
Happy coding! π
Top comments (1)
This is a good entry point for .NET developers because it moves past βsend prompt, get answerβ into tools and action boundaries. The next useful layer is usually observability: what the agent tried, what tool returned, and where a human can inspect the trace.