AI-powered chatbots have become an essential part of modern web applications. They can automate customer support, guide users, and provide personalized recommendations. In this article, we will build a full-stack AI-based chatbot with an Angular frontend and ASP.NET Core backend, integrating with an AI model via API (for example, OpenAI GPT or any other AI service).
We will focus on technical accuracy, clean architecture, scalability, and best practices for production-ready applications.
1. Understanding the Architecture
A chatbot system has three main layers:
Frontend (Angular)
Backend (ASP.NET Core Web API)
Receives messages from the frontend
Sends requests to AI services
Stores chat history (optional)
AI Service
Handles natural language understanding and generates responses
Could be OpenAI GPT API, Microsoft Azure OpenAI, or a custom NLP model
High-Level Flow
User -> Angular Frontend -> ASP.NET Core API -> AI Service
<- Response <- <- AI Response
2. Setting Up the ASP.NET Core Backend
Step 1: Create a New ASP.NET Core Web API Project
dotnet new webapi -n ChatbotAPI
cd ChatbotAPI
Step 2: Install Required Packages
For HTTP requests to AI services, install System.Net.Http.Json:
dotnet add package System.Net.Http.Json
Optionally, if you want logging:
dotnet add package Serilog.AspNetCore
Step 3: Define Chat Message Model
Create Models/ChatMessage.cs:
public class ChatMessage
{
public string User { get; set; } = "user"; // "user" or "bot"
public string Message { get; set; } = string.Empty;
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
}
Step 4: AI Service Integration
Create a service to handle AI requests:
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;
public class AIService
{
private readonly HttpClient _httpClient;
public AIService(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<string> GetResponseAsync(string prompt)
{
// Example: calling OpenAI GPT API
var request = new
{
model = "gpt-3.5-turbo",
messages = new[] { new { role = "user", content = prompt } }
};
var response = await _httpClient.PostAsJsonAsync("https://api.openai.com/v1/chat/completions", request);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadFromJsonAsync<dynamic>();
return result?.choices[0].message.content ?? "Sorry, I did not understand.";
}
}
In production, keep your API keys in appsettings.json or Azure Key Vault, and never commit secrets.
Step 5: Create Chat Controller
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("api/[controller]")]
public class ChatController : ControllerBase
{
private readonly AIService _aiService;
public ChatController(AIService aiService)
{
_aiService = aiService;
}
[HttpPost]
public async Task<IActionResult> Post([FromBody] ChatMessage message)
{
if (string.IsNullOrWhiteSpace(message.Message))
return BadRequest("Message cannot be empty");
var botResponse = await _aiService.GetResponseAsync(message.Message);
var responseMessage = new ChatMessage
{
User = "bot",
Message = botResponse
};
return Ok(responseMessage);
}
}
Step 6: Register AIService in Program.cs
builder.Services.AddHttpClient<AIService>(client =>
{
client.DefaultRequestHeaders.Add("Authorization", "Bearer YOUR_API_KEY");
});
This sets up a minimal but production-ready backend API for chatbot messages.
3. Setting Up Angular Frontend
Step 1: Create Angular Project
ng new chatbot-app --routing --style=scss
cd chatbot-app
ng serve
Step 2: Create Chat Models
src/app/models/chat-message.model.ts:
export interface ChatMessage {
user: 'user' | 'bot';
message: string;
timestamp?: string;
}
Step 3: Chat Service
src/app/services/chat.service.ts:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ChatMessage } from '../models/chat-message.model';
@Injectable({
providedIn: 'root'
})
export class ChatService {
private apiUrl = 'https://localhost:5001/api/chat'; // ASP.NET Core URL
constructor(private http: HttpClient) { }
sendMessage(message: string): Observable<ChatMessage> {
return this.http.post<ChatMessage>(this.apiUrl, { user: 'user', message });
}
}
Step 4: Chat Component
src/app/components/chat/chat.component.ts:
import { Component } from '@angular/core';
import { ChatService } from '../../services/chat.service';
import { ChatMessage } from '../../models/chat-message.model';
@Component({
selector: 'app-chat',
templateUrl: './chat.component.html',
styleUrls: ['./chat.component.scss']
})
export class ChatComponent {
messages: ChatMessage[] = [];
userInput: string = '';
loading: boolean = false;
constructor(private chatService: ChatService) { }
sendMessage() {
if (!this.userInput.trim()) return;
const userMessage: ChatMessage = {
user: 'user',
message: this.userInput,
timestamp: new Date().toISOString()
};
this.messages.push(userMessage);
this.loading = true;
this.chatService.sendMessage(this.userInput).subscribe({
next: (botMessage) => {
this.messages.push(botMessage);
this.loading = false;
},
error: () => {
this.messages.push({ user: 'bot', message: 'Sorry, something went wrong.' });
this.loading = false;
}
});
this.userInput = '';
}
}
Step 5: Chat Component Template
chat.component.html:
<div class="chat-container">
<div class="messages">
<div *ngFor="let msg of messages" [ngClass]="msg.user">
<strong>{{ msg.user }}:</strong> {{ msg.message }}
</div>
<div *ngIf="loading" class="bot-loading">Bot is typing...</div>
</div>
<div class="input-container">
<input [(ngModel)]="userInput" placeholder="Type a message" (keyup.enter)="sendMessage()"/>
<button (click)="sendMessage()">Send</button>
</div>
</div>
Step 6: Add Styling
chat.component.scss:
.chat-container {
display: flex;
flex-direction: column;
height: 500px;
border: 1px solid #ccc;
padding: 10px;
}
.messages {
flex: 1;
overflow-y: auto;
margin-bottom: 10px;
.user { text-align: right; color: blue; }
.bot { text-align: left; color: green; }
.bot-loading { font-style: italic; color: gray; }
}
.input-container {
display: flex;
input {
flex: 1;
padding: 5px;
}
button {
margin-left: 5px;
}
}
4. Handling Best Practices
Security: Never expose API keys in Angular. Keep them in ASP.NET Core backend.
Async Handling: Use Observables and BehaviorSubject for state management if chatbot UI becomes complex.
Error Handling: Always handle API errors gracefully.
Persistence: Store chat history in a database for returning users.
Scalability: Backend can use queue-based systems if AI API requests increase.
Typing Indicators: Use loading flags for better UX.
Rate Limiting: Protect backend to avoid hitting AI API limits.
Deployment: Use HTTPS in production for secure communication.
5. Optional Enhancements
WebSocket Integration: For real-time chat updates instead of polling.
AI Fine-Tuning: Provide context for better responses.
Widget-Based Chat: Embed chatbot as a draggable widget on dashboards.
Multi-Language Support: Localize frontend and provide multi-language AI prompts.
Bot Analytics: Track common questions, failed responses, and usage stats.
6. Folder Structure
chatbot-app/
src/app/
components/
chat/
chat.component.ts
chat.component.html
chat.component.scss
models/
chat-message.model.ts
services/
chat.service.ts
ChatbotAPI/
Controllers/
ChatController.cs
Models/
ChatMessage.cs
Services/
AIService.cs
Program.cs
appsettings.json
7. Conclusion
By combining Angular frontend and ASP.NET Core backend, we can build a full-featured AI chatbot that is scalable, production-ready, and easy to extend.
Key takeaways
Use dynamic state management for chat messages.
Keep AI API calls backend-only for security.
Implement error handling, persistence, and UX improvements for production readiness.
Optional enhancements like WebSocket, analytics, and multi-language support make the chatbot more professional.
With this architecture, you can now integrate AI chatbots in enterprise dashboards, SaaS products, customer support portals, or learning platforms efficiently.