In today’s digital age, the ability to extract text from images is becoming increasingly important. Whether you’re dealing with scanned documents, business cards, or any other form of image-based data, being able to search and manipulate this information efficiently can save a lot of time and effort. This tutorial will guide you through building an interactive web application using Aspose.OCR and ASP.NET Core that allows users to upload images, search for specific keywords within the extracted text, and view real-time results with highlighted matches.
Source of truth: The code and flow below are aligned with the gist at the end of this article (controller endpoints,
AsposeOcr
usage, and JSON response shape).
Complete Example
Prerequisites
- .NET 8 (or .NET 6+) SDK
- Visual Studio / VS Code
- NuGet access for
Aspose.OCR
- (Optional) An Aspose license file if you plan to exceed evaluation limits
Step 1: Create the ASP.NET Core MVC Project
dotnet new mvc -n ImageTextSearchApp -f net8.0
cd ImageTextSearchApp
# Add Aspose.OCR
dotnet add package Aspose.OCR
Why MVC? The gist uses controllers (HomeController
), views, and a classic Startup
—an easy, well-known pattern for file uploads + server-side OCR.
Step 2: Prepare Static Assets and Uploads Folder
The controller writes uploads under wwwroot/uploads
. Create that folder and ensure the app can write to it.
mkdir -p wwwroot/uploads
We also enable static files middleware in
Startup
(shown later) so thewwwroot
tree is served correctly.
Step 3: Add the Controller (Upload + OCR + Search)
Create Controllers/HomeController.cs and implement Index
+ SearchText
as per the gist. This action saves the uploaded image, performs OCR, searches a keyword (case-insensitive), and returns JSON.
using System;
using System.IO;
using System.Threading.Tasks;
using Aspose.Ocr;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace ImageTextSearchApp
{
public class HomeController : Controller
{
private readonly IWebHostEnvironment _environment;
public HomeController(IWebHostEnvironment environment)
{
_environment = environment;
}
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
[RequestSizeLimit(20_000_000)] // ~20MB max, adjust as needed
public async Task<IActionResult> SearchText(IFormFile imageFile, string searchKeyword)
{
if (imageFile == null || imageFile.Length == 0)
return BadRequest("Image file is required.");
if (string.IsNullOrWhiteSpace(searchKeyword))
return BadRequest("Search keyword is required.");
// Ensure uploads directory exists
var uploadsDir = Path.Combine(_environment.WebRootPath, "uploads");
Directory.CreateDirectory(uploadsDir);
// Sanitize filename and save
var safeName = Path.GetFileName(imageFile.FileName);
var filePath = Path.Combine(uploadsDir, safeName);
using (var stream = new FileStream(filePath, FileMode.Create))
{
await imageFile.CopyToAsync(stream);
}
// Perform OCR on the uploaded image
using (var ocrEngine = new AsposeOcr())
{
var extractedText = await ocrEngine.RecognizeImageAsync(filePath);
// Case-insensitive keyword check
var found = extractedText?.IndexOf(searchKeyword, StringComparison.OrdinalIgnoreCase) >= 0;
var searchResult = found ? "Keyword found!" : "Keyword not found.";
// Return minimal JSON (exact shape matches the gist)
return Json(new { extractedText, searchResult });
}
}
}
}
Notes
- We added a small file size limit and directory creation for robustness.
- For production, validate file types (
.png/.jpg/.jpeg/.tif
) and consider virus scanning.
Step 4: Wire Up Startup and Program
Create Startup.cs and Program.cs as in the gist to enable MVC, static files, routing, and HTTPS redirection.
Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ImageTextSearchApp
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(); // serves wwwroot (including /uploads)
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Program.cs
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
namespace ImageTextSearchApp
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
Step 5: Build the Upload + Search UI (Razor View)
Create Views/Home/Index.cshtml with a simple upload form and a search box. The JavaScript posts the file + keyword to /Home/SearchText
, prints OCR text, and highlights matches in the browser (no server changes needed).
@{
ViewData["Title"] = "Image Text Search";
}
<h1 class="mb-3">Image Text Search (Aspose.OCR + ASP.NET Core)</h1>
<form id="ocrForm" enctype="multipart/form-data" class="mb-4">
<div class="form-group mb-2">
<label for="imageFile">Select image</label>
<input type="file" id="imageFile" name="imageFile" accept=".png,.jpg,.jpeg,.tif,.tiff,.bmp" class="form-control" required />
</div>
<div class="form-group mb-2">
<label for="searchKeyword">Keyword</label>
<input type="text" id="searchKeyword" name="searchKeyword" class="form-control" placeholder="Enter a word to find..." required />
</div>
<button type="submit" class="btn btn-primary">Upload & Search</button>
</form>
<div id="result" class="mt-3">
<h3>Result</h3>
<p id="searchStatus" class="fw-bold"></p>
<pre id="extractedText" style="white-space: pre-wrap"></pre>
</div>
@section Scripts {
<script>
(function () {
const form = document.getElementById('ocrForm');
const statusEl = document.getElementById('searchStatus');
const textEl = document.getElementById('extractedText');
function escapeHtml(s) {
return s.replace(/[&<>"']/g, c => ({
'&': '&', '<': '<', '>': '>', '"': '"', "'": '''
}[c]));
}
function highlight(text, keyword) {
if (!keyword) return escapeHtml(text);
const pattern = new RegExp(`(${keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
return escapeHtml(text).replace(pattern, '<mark>$1</mark>');
}
form.addEventListener('submit', async (e) => {
e.preventDefault();
statusEl.textContent = 'Processing...';
textEl.textContent = '';
const formData = new FormData(form);
try {
const res = await fetch('/Home/SearchText', {
method: 'POST',
body: formData
});
if (!res.ok) {
const msg = await res.text();
statusEl.textContent = `Error: ${msg}`;
return;
}
const data = await res.json();
statusEl.textContent = data.searchResult || '';
const kw = document.getElementById('searchKeyword').value;
textEl.innerHTML = highlight(data.extractedText || '', kw);
} catch (err) {
statusEl.textContent = 'Unexpected error. See console.';
console.error(err);
}
});
})();
</script>
}
This implements real-time highlighting in the extracted text block. Rendering highlights on the image itself would require OCR bounding boxes and drawing overlays (not covered by the gist).
Step 6: Run the App
dotnet run
Open the URL shown in console (e.g., https://localhost:5001
).
Upload an image, enter a keyword, and click Upload & Search. You’ll see:
Keyword found!
orKeyword not found.
(server-generated)- The extracted text with client-side
<mark>
highlights
Step 7: Production-Ready Considerations (Optional)
- File validation: Check MIME types/extensions and consider antivirus scanning.
- Size limits: Use
RequestSizeLimit
(shown) and reverse proxy/web.config limits as needed. - Cleanup: Periodically delete old files from
wwwroot/uploads
. - Localization: If you need multiple languages, configure OCR language options server-side.
- Error UX: Replace alerts with toasts; add loading spinners and progress bars.
Troubleshooting
- Empty OCR result: Try higher-quality input, correct orientation, or different format (PNG/TIFF).
- CORS: If front-end is separate, enable CORS and use the full API URL.
- HTTPS: Ensure dev cert trust (
dotnet dev-certs https --trust
) if browser blocks mixed content.