Sentiment analysis is the process of automatically detecting the emotional tone of text. Businesses use it to monitor customer feedback, social media posts, product reviews, and support tickets. Integrating sentiment analysis into a modern web application can provide actionable insights and improve user experience.
In this article, we will walk through a production-ready approach to integrating sentiment analysis in a full-stack application using ASP.NET Core as backend and Angular as frontend. We will cover:
Architecture overview
Choosing a sentiment analysis approach
Backend implementation in ASP.NET Core
Exposing REST APIs for Angular consumption
Angular frontend integration
Performance and scalability considerations
Real-world best practices
This guide assumes you have a good understanding of both Angular and ASP.NET Core, as well as general knowledge of Natural Language Processing (NLP) concepts.
1. Architecture Overview
A sentiment analysis system in a web application typically follows this architecture:
Angular Frontend <---- REST API ----> ASP.NET Core Backend <---- Sentiment Engine / ML Model
Responsibilities
Angular Frontend
Capture user input (feedback, comments, or text)
Display sentiment results
Visualise analytics if needed
ASP.NET Core Backend
Expose REST API endpoints
Receive text data from frontend
Call sentiment analysis logic or external services
Store results in database if required
Sentiment Analysis Engine
Could be a built-in .NET ML.NET model,
Or an external API (like Azure Cognitive Services or OpenAI)
Returns sentiment score (positive, negative, neutral) and confidence
2. Choosing a Sentiment Analysis Approach
There are three common approaches:
2.1 Using Pre-trained NLP APIs
2.2 Using ML.NET in ASP.NET Core
2.3 Hybrid Approach
For enterprise applications, ML.NET or Azure Cognitive Services are most commonly used.
3. Setting Up ASP.NET Core Backend
We will use ML.NET for sentiment analysis. ML.NET is a production-ready, cross-platform machine learning framework for .NET.
3.1 Create a New ASP.NET Core Web API
dotnet new webapi -n SentimentApi
cd SentimentApi
Add ML.NET NuGet package:
dotnet add package Microsoft.ML
3.2 Define Data Models
Create Models/SentimentData.cs:
using Microsoft.ML.Data;
public class SentimentData
{
[LoadColumn(0)]
public string Text { get; set; }
}
public class SentimentPrediction
{
[ColumnName("PredictedLabel")]
public bool IsPositive { get; set; }
public float Score { get; set; }
}
3.3 Load Pre-trained Model or Train New Model
You can train a simple model using a CSV dataset (data/sentiment.csv) with two columns: Text and Label (0 = negative, 1 = positive).
Create Services/SentimentService.cs:
using Microsoft.ML;
using Microsoft.ML.Data;
public class SentimentService
{
private readonly MLContext _mlContext;
private ITransformer _mlModel;
private PredictionEngine<SentimentData, SentimentPrediction> _predEngine;
public SentimentService()
{
_mlContext = new MLContext();
LoadModel();
}
private void LoadModel()
{
// Option 1: Load pre-trained model from file
if (File.Exists("Models/SentimentModel.zip"))
{
_mlModel = _mlContext.Model.Load("Models/SentimentModel.zip", out _);
}
else
{
// Option 2: Train a new model
var data = _mlContext.Data.LoadFromTextFile<SentimentData>("data/sentiment.csv", hasHeader: true, separatorChar: ',');
var pipeline = _mlContext.Transforms.Text.FeaturizeText("Features", nameof(SentimentData.Text))
.Append(_mlContext.BinaryClassification.Trainers.SdcaLogisticRegression(labelColumnName: "Label", featureColumnName: "Features"));
_mlModel = pipeline.Fit(data);
// Save model for later use
_mlContext.Model.Save(_mlModel, data.Schema, "Models/SentimentModel.zip");
}
_predEngine = _mlContext.Model.CreatePredictionEngine<SentimentData, SentimentPrediction>(_mlModel);
}
public SentimentPrediction Predict(string text)
{
return _predEngine.Predict(new SentimentData { Text = text });
}
}
3.4 Create Controller
Controllers/SentimentController.cs:
using Microsoft.AspNetCore.Mvc;
[Route("api/[controller]")]
[ApiController]
public class SentimentController : ControllerBase
{
private readonly SentimentService _sentimentService;
public SentimentController(SentimentService sentimentService)
{
_sentimentService = sentimentService;
}
[HttpPost("analyze")]
public IActionResult Analyze([FromBody] SentimentRequest request)
{
if (string.IsNullOrWhiteSpace(request.Text))
return BadRequest("Text cannot be empty");
var result = _sentimentService.Predict(request.Text);
return Ok(new
{
sentiment = result.IsPositive ? "Positive" : "Negative",
score = result.Score
});
}
}
public class SentimentRequest
{
public string Text { get; set; }
}
3.5 Register Service in Program.cs
builder.Services.AddSingleton<SentimentService>();
4. Angular Frontend Integration
4.1 Create Angular Service
// sentiment.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
export interface SentimentResponse {
sentiment: string;
score: number;
}
@Injectable({
providedIn: 'root'
})
export class SentimentService {
private apiUrl = 'https://localhost:5001/api/sentiment/analyze';
constructor(private http: HttpClient) {}
analyzeText(text: string) {
return this.http.post<SentimentResponse>(this.apiUrl, { text });
}
}
4.2 Angular Component for Sentiment Input
// sentiment.component.ts
import { Component } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { SentimentService } from './sentiment.service';
@Component({
selector: 'app-sentiment',
templateUrl: './sentiment.component.html'
})
export class SentimentComponent {
form: FormGroup;
sentimentResult: string | null = null;
score: number | null = null;
constructor(private fb: FormBuilder, private sentimentService: SentimentService) {
this.form = this.fb.group({
text: ['']
});
}
analyze() {
const text = this.form.value.text;
if (!text) return;
this.sentimentService.analyzeText(text).subscribe(res => {
this.sentimentResult = res.sentiment;
this.score = res.score;
});
}
}
4.3 Component Template
<div>
<textarea formControlName="text" placeholder="Enter your text"></textarea>
<button (click)="analyze()">Analyze Sentiment</button>
</div>
<div *ngIf="sentimentResult">
<p>Sentiment: {{ sentimentResult }}</p>
<p>Score: {{ score | number:'1.2-2' }}</p>
</div>
5. Real-World Best Practices
5.1 Asynchronous Processing
For large text or batch analysis, offload sentiment analysis to a background queue (e.g., Azure Functions, RabbitMQ, or Hangfire).
5.2 Model Versioning
Keep versions of your trained models. When updating a model, do not overwrite production model until fully tested.
5.3 Caching Results
For repeated analyses of the same text (e.g., product reviews), cache results to reduce compute.
5.4 Logging and Monitoring
Log API calls, text length, sentiment score distribution for monitoring accuracy and potential misuse.
5.5 Security
5.6 Frontend UX
Show a loading spinner for analysis
Limit text length for performance
Highlight positive/negative words for user feedback
6. Scaling Sentiment Analysis
6.1 Using Cloud NLP APIs
For enterprise workloads, consider cloud APIs:
Advantages:
Auto-scaling
High accuracy
Multilingual support
6.2 Batch Processing
7. Performance Considerations
ML.NET PredictionEngine is not thread-safe. Use singleton pattern carefully. For high throughput, create PredictionEnginePool:
builder.Services.AddPredictionEnginePool<SentimentData, SentimentPrediction>()
.FromFile("Models/SentimentModel.zip");
For Angular, debounce input to avoid excessive API calls:
this.form.get('text')?.valueChanges
.pipe(debounceTime(500))
.subscribe(value => this.analyze());
Compress API responses for large data sets using GZIP.
8. Handling Multilingual Text
ML.NET supports only the language your model was trained on. For multi-language support:
Translate text to English using Azure Translator API
Apply sentiment analysis
Store original and translated text
Alternatively, cloud NLP APIs often support multilingual sentiment detection natively.
9. Advanced Features
9.1 Entity Sentiment
Detect sentiment towards specific entities in a text:
9.2 Word-Level Highlighting
Frontend can highlight positive and negative words for UX:
9.3 Analytics Dashboard
Aggregate sentiment over time:
Daily/weekly sentiment trends
Average score per product/service
Visualize via charts (Angular + Chart.js or ngx-charts)
10. Testing
10.1 Unit Tests
[Fact]
public void Predict_PositiveText_ReturnsPositive()
{
var service = new SentimentService();
var result = service.Predict("I love this product!");
Assert.True(result.IsPositive);
}
10.2 Angular Tests
11. Security Considerations
Sanitize user input before analysis
Limit input size to prevent denial-of-service
Use HTTPS for API
Implement API rate limiting
Summary
We have covered end-to-end implementation of sentiment analysis in an ASP.NET Core + Angular application:
Architecture design
Choosing ML.NET or cloud-based sentiment analysis
Backend service creation and API exposure
Angular service and component integration
Real-world best practices for performance, security, and scalability
Advanced features like multilingual support, entity-level sentiment, and dashboards
This approach is production-ready, modular, and maintainable. It allows developers to extend features like batch processing, background jobs, or multi-language sentiment detection without rewriting the system.
By combining ML.NET with Angular reactive forms, you get a robust, full-stack solution that provides actionable sentiment insights in real time.