I'm always excited to take on new projects and collaborate with innovative minds.

Social Links

Building AI That Can Use Your APIs: Function Calling in ASP.NET Core

Most AI applications can answer questions, but useful AI applications perform actions. Learn how to build Function Calling in ASP.NET Core using OpenAI GPT-4o, tool registries, validation, authorization, structured logging, and business service integration to safely connect AI with real-world operations.

Function Calling in ASP.NET Core: Letting AI Safely Execute Business Operations

Most AI applications can answer questions.

Useful AI applications perform actions.

Examples include:

  • Creating invoices
  • Fetching customer details
  • Searching products
  • Booking meetings
  • Sending emails
  • Generating reports

This is where many developers misunderstand the role of an LLM.

The model should not execute business logic.

The model should decide when business logic should be executed.

Your existing services, APIs, validation rules, authorization checks, and business workflows should remain the source of truth.

Function Calling bridges these two worlds.

In this article, we'll build a production-ready Function Calling architecture in ASP.NET Core that allows GPT-4o to safely invoke business capabilities without giving the model direct access to databases, services, or internal systems.


What We'll Build

The architecture looks like this:

               User

                 │

        "Create an invoice"

                 │

              GPT-4o

                 │

     Decides Which Tool To Call

                 │

        InvoiceService.Create()

                 │

        Business Logic Executes

                 │

        Result Returned to LLM

                 │

      Final Natural Response

The key idea is simple.

The model decides.

The backend validates.

The backend executes.

The model responds.

This separation keeps AI useful without making it dangerous.


Why Function Calling?

Without Function Calling, an AI model can only generate text.

That often leads to hallucinations.

Example:

User:
What is my current account balance?

AI:
Your balance is $12,500.

The model has no way of knowing whether that answer is true.

It guessed.

Now consider Function Calling.

User:
What is my current account balance?

AI

↓

Calls Customer API

↓

Receives Real Data

↓

Responds

Now the answer comes from an actual system.

This dramatically improves reliability.


Real Enterprise Use Cases

Function Calling enables AI to interact with existing systems.

Examples include:

Finance

  • Create invoices
  • Generate statements
  • Retrieve payment history

Customer Support

  • Fetch customer records
  • Open support tickets
  • Update account information

E-Commerce

  • Search products
  • Check inventory
  • Create orders

Internal Operations

  • Generate reports
  • Query business systems
  • Trigger workflows

The AI becomes an orchestration layer instead of a guessing machine.


What Makes a Good Tool?

One of the biggest mistakes developers make is creating tools that do too much.

Avoid this:

DoEverythingTool

A good tool should:

  • Have one responsibility
  • Return structured data
  • Be deterministic
  • Execute quickly
  • Be independently testable

Think of tools as APIs.

Small and focused beats large and complicated.


Designing the Tool Interface

Every tool should implement a common contract.

public interface IAITool
{
    string Name { get; }

    string Description { get; }

    Task<string> ExecuteAsync(string arguments);
}

This abstraction provides several benefits.

First, the AI system doesn't care how a tool works internally.

Second, new capabilities can be added without changing existing code.

Third, tools become easy to test and maintain.

A weather tool, invoice tool, or customer lookup tool all behave the same way from the perspective of the orchestration layer.


Example Tools

Let's look at a few practical examples.


Invoice Tool

Responsible for:

CreateInvoice()

Example request:

{
  "customerId": 123,
  "amount": 500
}

The tool delegates to an InvoiceService.

It does not contain business rules itself.


Customer Tool

Responsible for:

GetCustomer()

Example response:

{
  "id":123,
  "name":"John Smith",
  "email":"john@example.com"
}

Weather Tool

Responsible for:

GetWeather()

Useful for demonstrating external API integration.


Product Search Tool

Responsible for:

SearchProducts()

Returns structured product information.

Again, one responsibility per tool.


Tool Registration

Hardcoding tool execution quickly becomes messy.

Instead, introduce a Tool Registry.

AI

↓

Tool Registry

↓

Invoice

Weather

Customer

Products

The registry discovers and resolves tools dynamically.

Benefits include:

  • Easier maintenance
  • Extensibility
  • Cleaner architecture

Adding a new tool should require registration, not modification.


Dependency Injection

ASP.NET Core already provides a powerful mechanism for managing dependencies.

Register every tool using Dependency Injection.

builder.Services.AddScoped<IAITool, InvoiceTool>();

builder.Services.AddScoped<IAITool, CustomerTool>();

builder.Services.AddScoped<IAITool, WeatherTool>();

builder.Services.AddScoped<IAITool, ProductSearchTool>();

Now the registry can automatically discover all available tools.

This follows the Open/Closed Principle.

Open for extension.

Closed for modification.


Understanding the Execution Flow

This orchestration layer is the most important part of the system.

The flow looks like this:

User Question

↓

LLM

↓

Function Request

↓

Tool Validation

↓

Tool Execution

↓

Result

↓

LLM Final Response

Let's break it down.


Step 1: User Sends a Request

Example:

Create an invoice for customer 123
for $500.

Step 2: GPT-4o Chooses a Tool

The model determines:

Tool:
CreateInvoice

and generates arguments.

{
  "customerId":123,
  "amount":500
}

Step 3: Backend Validates

Before execution:

  • Tool exists
  • User is authorized
  • Arguments are valid
  • Business rules pass

The model's suggestion is not automatically trusted.


Step 4: Tool Executes

The selected tool invokes the business service.

InvoiceTool

↓

InvoiceService

↓

Database

Step 5: Result Returns

Example:

{
  "invoiceId":4567,
  "status":"Created"
}

Step 6: AI Generates Final Response

The model converts the structured result into natural language.

Example:

Invoice #4567 was successfully
created for customer 123
with an amount of $500.

This is where Function Calling feels magical.

But the magic comes from orchestration, not AI.


Validation Is Mandatory

One of the most dangerous assumptions is:

The model already validated the request.

No.

Always validate.


Tool Exists

Reject unknown tools.

DeleteEntireDatabase()

should never execute.


Argument Validation

Validate:

  • Required fields
  • Types
  • Formats

Example:

Amount > 0

Business Rules

Example:

Customer Exists

before creating an invoice.


Authorization

Example:

Guest User

↓

CreateInvoice

↓

Denied

AI suggestions should never bypass business security.


Security Considerations

Function Calling introduces a powerful capability.

That means security becomes even more important.


Prevent Arbitrary Function Calls

Only registered tools should be executable.

The AI must never invoke arbitrary methods.


Authorization Before Execution

Every tool should enforce authorization policies.

Example:

Admin

↓

CreateInvoice

↓

Allowed
Guest

↓

CreateInvoice

↓

Denied

Input Validation

Treat AI-generated arguments exactly like user input.

Validate everything.


Audit Logging

Track:

  • User
  • Tool
  • Arguments
  • Timestamp
  • Result

This is critical for compliance and troubleshooting.


Rate Limiting

Some tools may trigger expensive operations.

Protect them appropriately.


Error Handling

Tools fail.

Systems fail.

Networks fail.

Design for failure.

Examples:

Tool Not Found

{
  "success":false,
  "error":"Tool not found"
}

Validation Failure

{
  "success":false,
  "error":"Invalid amount"
}

Database Failure

{
  "success":false,
  "error":"Unable to create invoice"
}

External API Failure

Weather APIs and third-party services can fail.

Handle failures gracefully.

The AI should receive structured error information so it can explain the problem appropriately.


Logging and Observability

Function Calling adds a new execution layer.

Without observability, debugging becomes difficult.

Track:

Tool Selected
Execution Time
Success
Failure
Correlation ID
User ID

Example log:

Tool=CreateInvoice

Duration=132ms

Status=Success

CorrelationId=abc123

Avoid logging:

  • API keys
  • Customer secrets
  • Sensitive financial data

Logs should be useful, not dangerous.


Business Logic Belongs in Services

A common anti-pattern looks like this:

Tool

↓

Business Logic

↓

Database

Instead:

Tool

↓

Business Service

↓

Database

Example:

InvoiceTool

↓

InvoiceService

↓

Repository

Tools orchestrate.

Services execute business logic.

This separation keeps the system maintainable.


Common Mistakes

These mistakes appear frequently in production systems.


Giving AI Direct Database Access

Extremely risky.


Letting the Model Execute Arbitrary Methods

Creates a massive attack surface.


Skipping Authorization

AI should never bypass security controls.


Huge Tool Descriptions

Large tool catalogs increase token usage and confusion.


Ignoring Validation

The model is not a security boundary.


Mixing AI Logic with Business Logic

Creates tightly coupled systems.


Logging Sensitive Data

Creates compliance and privacy risks.


Repository Features

The reference implementation includes:

  • ASP.NET Core Web API
  • OpenAI Function Calling
  • Tool Registry
  • Dependency Injection
  • Invoice Tool
  • Customer Tool
  • Weather Tool
  • Product Search Tool
  • Structured Logging
  • Swagger
  • Docker Support
  • Unit Tests

The goal is not simply to call functions.

The goal is to create a safe, maintainable orchestration layer between AI and business systems.


Suggested Screenshots

Include the following visuals.

Architecture Diagram

Show the complete Function Calling workflow.


Tool Execution Flow

Visualize:

AI

↓

Tool

↓

Service

↓

Database

Swagger Endpoint

Display:

POST /api/chat

Function Call JSON

Show generated tool arguments.


Structured Logs

Display:

Tool
Duration
Status
CorrelationId

These visuals help readers understand how orchestration works behind the scenes.


Conclusion

Function Calling transforms AI from a system that only generates text into a system that can safely interact with business operations.

The key is maintaining clear boundaries.

The model decides which capability it needs.

The backend validates the request.

Business services execute the operation.

The model then communicates the result in natural language.

By introducing tool abstractions, validation, authorization, observability, and structured execution, you can integrate AI into existing systems without compromising security or maintainability.

Function Calling gives AI the ability to interact with your existing systems, but every request still starts from scratch.

In the next article, we'll explore how to build persistent AI memory so applications can maintain context across conversations without sending the entire chat history every time.

7 min read
Mar 01, 2025
By Dheer Gupta
Share

Leave a comment

Your email address will not be published. Required fields are marked *