Home / Articles

Building AI Agents on Top of Your Existing .NET Services and APIs

C# teams can expose existing .NET services as governed tools for AI agents via function calling, with the context, security and observability rules needed.

Publisher: REACTAPP.TOP9 min read2060 words

This article is published in English.

Sources: AI Agents Are Changing C# Development: 10 Things Every .NET Developer Should Know

Most .NET teams already own the hard parts of an AI agent: typed services, HTTP APIs, authentication, databases and background jobs. What is new is a language model that can pick which of those capabilities to invoke, in what order, to reach a goal a user describes in plain language. This guide walks through the ideas a C# developer needs to wire an agent into an existing application without giving up control over what the application actually does.

From answering questions to completing tasks

A classic chatbot is a single round trip: a user asks something and the model replies with text. An agent works on a goal instead. It reasons about what the goal requires, calls tools to fetch information or take actions, looks at the results, and only then returns an outcome.

Consider a user who wants to know how many orders came in today. A chatbot can only guess or explain how you might find out. An agent with the right tools can reach the order data, run the query for today, interpret the numbers, write a short summary and deliver it as a report. The practical distinction is simple: chatbots produce answers, agents carry out work.

Tools turn a model into something useful

On its own, a language model has no idea how your application works. It cannot read your customers table or place an order. Tools are the bridge: named operations the model is allowed to request. A typical set for a commerce backend might look like this:

GetCustomer()
CreateOrder()
SearchProducts()
GetWeather()
SendEmail()
QueryDatabase()

The model decides when one of these is needed; your code decides how it runs. In C#, a tool does not have to be anything exotic. It can be an ordinary async method on a service you already have, such as one that loads a customer by id through an injected service:

public async Task<Customer> GetCustomer(int id)
{
    return await customerService.GetByIdAsync(id);
}

Once that method is registered as a tool, the agent can use the capability, while the implementation stays inside your normal service layer, covered by the same dependency injection, tests and logging as the rest of the codebase. This is the point where everyday application development and AI development meet.

How function calling works in practice

Function calling is the mechanism behind tools. The model does not execute anything itself; it emits a structured request to call a function with specific arguments, and your application performs the call.

Suppose a user asks for the status of order 12345. Internally, the model concludes that it lacks information:

I need order information.

So it asks the host application to invoke a function with the order number as its argument:

GetOrderStatus(12345)

Your code executes that request, hands the result back to the model, and the model turns the raw data into a readable reply. For a C# developer this should feel familiar: you are publishing a small surface of your application, much like a public API whose caller is a model. Clear names, precise parameter types and good descriptions make correct calls far more likely.

Reusing the APIs you already have

Adopting agents does not require rewriting the backend. If your application already exposes endpoints, those can become the agent's tools. A service might already publish a customer lookup:

GET /api/customers/{id}

Alongside endpoints for reading an order, creating orders and listing products (the listing below runs the three routes together on one line; read them as separate endpoints):

GET /api/orders/{id}POST /api/ordersGET /api/products

With those in place, a request such as finding the customer who placed the most orders this month becomes a sequence the agent can plan on its own: pull customer data, retrieve order information, compare the figures and report the winner. The agent is simply another client on top of capabilities you have already built and secured.

Context: give the model what it needs, not everything you have

Picture a half-hour working session with an agent that covers your application, its database schema, team coding conventions, business rules, open bugs and decisions made earlier in the conversation. To stay useful, the agent must keep track of the relevant parts of all that. This is why conversation history, context management, memory, retrieval, embeddings and vector databases keep coming up in agent design.

There is a catch that is easy to miss: more context is not automatically better. Every extra token costs money and latency, and irrelevant material dilutes the signal, which makes answers less reliable. Good agent design is about supplying the right context at the moment it is needed, for example by retrieving only the documents that match the current step rather than pasting an entire knowledge base into every request. For a deeper look at how these memory mechanisms differ, see our explainer on AI memory, embeddings and RAG.

Letting agents query data safely

Data access is where agents become especially attractive for .NET shops. A business user might ask which products saw the steepest sales decline last month. Rather than building a dedicated report for every such question, an agent-backed system can interpret the question, work out which data is relevant, query it, analyse the results and explain what it found.

The warning that comes with this is non-negotiable: never hand a model unrestricted access to your database. Letting it generate and run arbitrary SQL invites destructive statements, data leaks across tenants and queries that lock tables. Instead, expose narrow, purpose-built operations with validated parameters and their own permission checks:

GetSalesReport()
GetProductSales()
GetCustomerOrders()

Each can enforce row-level security, cap result sizes and use a read-only connection, trading a little flexibility for a lot of predictability.

Agents do not replace architecture

A common misconception is that adding a model lets you relax the fundamentals. The opposite is true. Dependency injection, SOLID design, logging, testing, authentication, authorization, error handling, observability and clean layering all matter more once a non-deterministic component is choosing what to call.

The useful mental model is a separation of roles: the agent may propose an action, but your application decides whether that action is permitted. In short, AI decides, your application governs. Authorization checks belong in the tool implementations and the services behind them, never in the prompt, because a prompt is a suggestion to the model rather than an enforced rule.

Security risks multiply with every tool

Every tool you grant expands what can go wrong. An agent might be able to perform actions like these:

Read customer data
Send emails
Create orders
Delete records
Call external APIs

Three questions follow. What happens when the model simply makes a mistake, such as deleting the wrong record? What happens when a malicious user tries to talk the agent into misusing a tool? And what happens when external content the agent reads, such as an email or a web page, contains hidden instructions? That last scenario, usually called indirect prompt injection, is a real and well-documented attack class, not a thought experiment.

The defences are mostly ones you already know, applied deliberately:

  • Authentication and authorization on every tool call, scoped to the end user rather than to the agent.
  • Input validation on all arguments the model supplies.
  • Explicit per-tool permissions, so a support agent cannot reach billing operations.
  • Rate limits to contain runaway loops and abuse.
  • Logging of every call and its arguments.
  • Human approval before sensitive or irreversible actions.

For anything high-impact, such as refunds, deletions or outbound messages to customers, a confirmation step where a person approves the action is often the cheapest insurance available.

Observability for non-linear request flows

Conventional request handling is easy to trace because it follows a straight line:

Request → Service → Database → Response

An agent run can bounce back and forth between the model, several tools and multiple backends before it settles on a response:

User
 ↓
AI Model
 ↓
Tool
 ↓
API
 ↓
Database
 ↓
AI Model
 ↓
Another Tool
 ↓
Final Response

That shape is far harder to debug. When something goes wrong, you need to answer which tools were called, why the model chose them, how long each call took, what failed, how many model invocations the run needed and what the whole operation cost. Treat each run as a trace with spans for model and tool calls, recording arguments and token counts next to timings; otherwise a wrong answer is nearly impossible to reproduce.

Why C# developers start ahead

Developers comfortable with C# and .NET are not starting from scratch. Interfaces and classes, HTTP APIs, DI containers, async code, databases, auth, hosted background services and cloud deployment are exactly what agent systems are built from. What remains is a short list of new concepts, which build on each other roughly in this order:

LLMs
 ↓
Prompting
 ↓
Function Calling
 ↓
Tools
 ↓
RAG
 ↓
Agents
 ↓
Multi-Agent Systems

There is no need to absorb it all at once; start small.

A reference architecture

A minimal design places the agent in the middle, with a handful of tools fanning out to your own services, the database and an external search API, and the results flowing back through the agent to the user:

User
               ↓
          AI Agent
               ↓
       ┌───────┼────────┐
       ↓       ↓        ↓
    API Tool DB Tool  Search Tool
       ↓       ↓        ↓
     .NET    Database  External API
       └───────┼────────┘
               ↓
          Agent Result
               ↓
             User

The key property of this layout is that the agent never touches your systems directly. Every path goes through a tool that your .NET application owns, so access control, validation and logging live in one place you already know how to maintain.

A practical learning path

For a C# developer moving into AI work, a sensible progression looks like this:

  • Understand LLMs. Learn how large language models behave, what they are good at and where they fail, such as confident but wrong answers.
  • Integrate a model API. Call a model from a .NET application and handle responses, errors and timeouts.
  • Learn function calling. Let the model request calls into your application's functions and feed the results back.
  • Learn RAG. Retrieve content from your own documents and data so answers are grounded in facts the model was never trained on.
  • Build a small agent. Give it two or three tools and watch how it plans across them.
  • Harden and instrument it. Add permissions, validation and tracing before anyone depends on the agent.
  • Ship something real. Move past tutorials to a tool people actually use.

A customer support agent is a good first real project because it exercises every layer. It can look up the customer, inspect the order, check delivery status, open a ticket and reply:

Search customer
 ↓
Check order
 ↓
Check delivery status
 ↓
Create support ticket
 ↓
Respond to customer

Each step maps to a narrow tool, and the steps with side effects are obvious candidates for approval rules.

Key takeaways

  • An agent is a software system: a model combined with tools, data, application logic, security and monitoring, not a replacement for any of them.
  • Expose capabilities as narrow, validated tools; never grant raw database or unrestricted API access.
  • Keep authorization in code, where the application governs what the agent proposes.
  • Curate context per step instead of maximising it.
  • Trace every run end to end so failures and costs are explainable.
  • Existing .NET skills transfer directly; the realistic outcome is not developers being replaced but developers who build with AI becoming considerably more productive.