How do you integrate an AI chat model such as OpenAI into an ASP.NET Core application?
How do you integrate an AI chat model such as OpenAI into an ASP.NET Core application?
1 Answer
Yes. The cleanest modern approach is to put OpenAI behind an
ASP.NET Core API endpoint, keep the API key on the server, and use OpenAI's official .NET SDK to call the
Responses API. OpenAI's official .NET repository includes an ASP.NET Core example using
ResponsesClient and dependency injection.
1. Overall architecture
A typical implementation looks like this:
Browser / Mobile App
|
| POST /api/chat
v
ASP.NET Core Web API
|
| User message
v
Chat Service
|
| OpenAI SDK
v
OpenAI Responses API
|
| AI response
v
ASP.NET Core
|
v
Browser / Mobile App
The important point is that the browser should not call OpenAI directly with your secret API key. Your ASP.NET Core backend should make the OpenAI request.
2. Install the OpenAI .NET SDK
The official OpenAI .NET SDK is available as an open-source repository.
For example:
dotnet add package OpenAI
You can then use the SDK's ResponsesClient.
The current official ASP.NET Core example uses configuration-based registration and dependency injection.
3. Store the API key securely
For local development, don't put the API key directly into source code.
For example, use .NET User Secrets:
dotnet user-secrets init
dotnet user-secrets set \
"Clients:ResponsesClient:Credential:Key" \
"YOUR_OPENAI_API_KEY"
Or use an environment variable:
Clients__ResponsesClient__Credential__Key=YOUR_OPENAI_API_KEY
OpenAI's official ASP.NET Core example specifically demonstrates both environment variables and .NET User Secrets.
For production, you can use a proper secret-management solution such as Azure Key Vault rather than committing credentials to
appsettings.json.
4. Configure appsettings.json
For example:
{
"Clients": {
"ResponsesClient": {
"Model": "gpt-5.5"
}
}
}
Keep the actual API key outside the source-controlled configuration file.
The model can then be changed through configuration rather than hard-coded throughout your application.
5. Register the OpenAI client
In Program.cs:
using OpenAI.Responses;
var builder = WebApplication.CreateBuilder(args);
builder.AddResponsesClient("Clients:ResponsesClient");
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
AddResponsesClient is provided by the OpenAI .NET integration and binds the configured
ResponsesClient to ASP.NET Core's dependency-injection system. The official sample registers the client this way and treats it as thread-safe for the application's lifetime.
6. Create a Chat API
Create a request model:
public class ChatRequest
{
public string Message { get; set; } = string.Empty;
}
Then create a controller:
using Microsoft.AspNetCore.Mvc;
using OpenAI.Responses;
[ApiController]
[Route("api/chat")]
public class ChatController : ControllerBase
{
private readonly ResponsesClient _client;
private readonly IConfiguration _configuration;
public ChatController(
ResponsesClient client,
IConfiguration configuration)
{
_client = client;
_configuration = configuration;
}
[HttpPost]
public async Task<IActionResult> Chat(ChatRequest request)
{
if (string.IsNullOrWhiteSpace(request.Message))
{
return BadRequest("Message is required.");
}
var model =
_configuration["Clients:ResponsesClient:Model"]
?? throw new InvalidOperationException(
"OpenAI model is not configured.");
var response =
await _client.CreateResponseAsync(
model,
request.Message);
return Ok(new
{
response = response.GetOutputText()
});
}
}
This is essentially the same pattern demonstrated in OpenAI's official ASP.NET Core example: inject
ResponsesClient, read the configured model, call CreateResponseAsync, and return the generated output.
7. Call the API from your frontend
Your frontend could send:
POST /api/chat
Content-Type: application/json
{
"message": "Explain dependency injection in ASP.NET Core."
}
The ASP.NET Core API sends the message to OpenAI and might return:
{
"response": "Dependency Injection (DI) is a design pattern..."
}
Your React, Angular, Blazor, MVC, or mobile application can then display that response as a chat message.
8. Add conversation history
A real chatbot needs more than one independent question.
For example:
User: What is ASP.NET Core?
AI: ASP.NET Core is Microsoft's web framework...
User: What language does it use?
AI: It primarily uses C#...
The second question requires context from the first interaction.
You therefore need some form of conversation state.
A simple architecture is:
User
|
+-- ConversationId
|
v
ASP.NET Core
|
+-- Load previous messages
|
+-- Add new user message
|
v
OpenAI
|
+-- Generate response
|
v
Save conversation
For a production application, conversation data might be stored in:
- SQL Server
- PostgreSQL
- Redis
- Cosmos DB
another persistent data store
The current OpenAI API also supports mechanisms for continuing responses, so you don't necessarily have to manually reconstruct every conversation in every scenario.
9. Don't expose the OpenAI key
This is one of the most important security rules.
Don't do this
const apiKey = "sk-...";
inside your browser application.
Do this
Browser
|
| /api/chat
v
ASP.NET Core
|
| OpenAI API key
v
OpenAI
The API key remains on your server.
You should also add:
- Authentication
- Authorization
- Rate limiting
- Request validation
- Logging
- Usage limits
Input/output filtering where appropriate
10. Create a dedicated AI service
For a larger application, I wouldn't put OpenAI logic directly in the controller.
Instead:
ChatController
|
v
IChatService
|
v
OpenAIChatService
|
v
ResponsesClient
For example:
public interface IChatService
{
Task<string> GetResponseAsync(string message);
}
Implementation:
using OpenAI.Responses;
public class OpenAIChatService : IChatService
{
private readonly ResponsesClient _client;
private readonly IConfiguration _configuration;
public OpenAIChatService(
ResponsesClient client,
IConfiguration configuration)
{
_client = client;
_configuration = configuration;
}
public async Task<string> GetResponseAsync(string message)
{
var model =
_configuration["Clients:ResponsesClient:Model"]
?? throw new InvalidOperationException(
"AI model is not configured.");
var response =
await _client.CreateResponseAsync(model, message);
return response.GetOutputText();
}
}
Register it:
builder.Services.AddScoped<IChatService, OpenAIChatService>();
Then your controller becomes much simpler:
[ApiController]
[Route("api/chat")]
public class ChatController : ControllerBase
{
private readonly IChatService _chatService;
public ChatController(IChatService chatService)
{
_chatService = chatService;
}
[HttpPost]
public async Task<IActionResult> Chat(ChatRequest request)
{
var answer =
await _chatService.GetResponseAsync(request.Message);
return Ok(new
{
response = answer
});
}
}
This separation becomes particularly valuable when you later add RAG, function calling, conversation storage, moderation, streaming, logging, or multiple AI providers.
Production architecture
For an enterprise .NET application, I'd typically evolve it toward:
┌─────────────────┐
│ React / Blazor │
│ Angular / Mobile│
└────────┬────────┘
│
▼
┌─────────────────┐
│ ASP.NET Core API│
└────────┬────────┘
│
Authentication
Rate Limiting
Validation
│
▼
┌─────────────────┐
│ Chat Service │
└────────┬────────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
Conversation RAG / DB AI Tools
Store Search
│ │ │
└────────────┼────────────┘
▼
┌─────────────────┐
│ OpenAI Responses│
│ API │
└─────────────────┘
In short
The basic implementation is:
ASP.NET Core → OpenAI .NET SDK → Responses API → return AI response to frontend.
The official OpenAI .NET SDK currently provides a dedicated ResponsesClient, and OpenAI's own ASP.NET Core sample demonstrates dependency-injection-based registration.
For a real application, I'd strongly recommend not stopping at the basic API call. The next important pieces are conversation memory, streaming responses, authentication/rate limiting, error handling, logging, and eventually RAG if the chatbot needs to answer questions from your company's own data.