• Oct 27, 2025

Smart Business Card Reader with Azure AI ,Azure Document Intelligence ,OpenAI and .NET Core

Smart Business Card Reader with Azure AI ,Azure Document Intelligence ,OpenAI and .NET Core

In today’s fast-paced world, automating data extraction from documents like business cards can save hours of manual entry and improve data accuracy. In this article, we’ll walk through how to build a .NET Core API that:
• Accepts a business card image upload
• Extracts structured data using Azure Document Intelligence
• Maps the extracted fields to a C# model using Azure OpenAI
• Stores the result in a database
We’ll also cover how to test the API using Swagger or Postman.

Step 1: Azure Setup

Before diving into code, let’s configure the necessary Azure resources.

  1. Azure AI Document Intelligence (formerly Form Recognizer)

  2. This service extracts structured data from documents using prebuilt models.

Steps:

  • Go to Azure Portal

  • Click Create a resource

  • Search for Azure AI services

  • Select Azure AI services (Microsoft)

  • Click Create

  • Fill in:

  • Resource name: e.g., BusinessCardAI

  • Region: Choose a supported region (e.g., East US, West Europe)

  • Pricing tier: Standard S0

  • Click Review + Create, then Create

  • After deployment, go to the resource and copy:

  • Endpoint

  • Key 1

2. Azure OpenAI

This service enables access to GPT models for natural language processing.
Steps:
• Go to Azure Portal
• Click Create a resource
• Search for Azure OpenAI
• Select Azure OpenAI (Microsoft)
• Click Create
• Fill in:
• Resource name: e.g., 
• Region: Choose a region that supports GPT-4 (e.g., East US)
• After deployment:
• Go to Model Deployments
• Deploy the gpt-4.1 model
• Copy the Endpoint and Key

Step 2: .NET Core API Breakdown(find the complete code snippet at the end of the article)

Let’s walk through the key components of the BusinessCardController

Upload Endpoint

[HttpPost("upload")]
public async Task<IActionResult> UploadCard([FromForm] IFormFile image)
  • Accepts a business card image (JPEG, PNG, or PDF)
    • Saves it to a local folder
    • Calls ExtractBusinessCardData to analyze the image
    • Sends the extracted JSON to MapFieldsUsingAzureOpenAI for intelligent field mapping
    • Deserializes the mapped result into BusinessCard model
    • Saves it to the database

Document Intelligence Integration

var operation = await client.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-businessCard", stream);
  • Uses the prebuilt-businessCard model to extract fields like name, company, email, phone, and address
    • Converts the result into a flat dictionary using ConvertFieldsToJson

OpenAI Field Mapping

ChatCompletion result = await MapFieldsUsingAzureOpenAI(cardJsonString);
  • Sends the extracted JSON and a C# model definition to GPT-4.1
    • Prompts the model to:
    • Map fields confidently
    • Return a clean JSON object under finalMapping
    • Include the original input under incomingJson
    • Deserializes the mapped result into a BusinessCard object

Step 3: Testing the API with Swagger or Postman

Postman:

Below is the json response:

{
    "incomingJson": {
        "Addresses": [
            "123 Anywhere St., Any City"
        ],
        "ContactNames": [
            "Daniel Gallego"
        ],
        "Emails": [
            "hello@reallygreatsite.com"
        ],
        "JobTitles": [
            "Fashion Designer"
        ],
        "WorkPhones": [
            "+123-456-7890"
        ]
    },
    "finalMapping": {
        "Id": 0,
        "Name": "Daniel Gallego",
        "Company": "Fashion Designer",
        "Email": "hello@reallygreatsite.com",
        "Phone": "+123-456-7890",
        "Address": "123 Anywhere St., Any City"
    }
}

Below is the screenshot from db:

Complete code snippet:

BusinessCardController

using Azure;
using Azure.Core;
using BusinessCardApi.Constants;
using BusinessCardApi.DataFactory;
using BusinessCardApi.Model;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Azure.AI.DocumentIntelligence;
using Azure.AI.FormRecognizer.DocumentAnalysis;
using System.Text;
using Azure.AI.Vision.ImageAnalysis;
using Microsoft.Extensions.Options;
using System.Text.Json;
using System.Reflection;
using Azure.AI.OpenAI;
using OpenAI.Chat;
using System.Collections.Generic;
using System.Text.Json.Nodes;


namespace BusinessCardApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class BusinessCardController : ControllerBase
    {
        private readonly BusinessCardDbContext _context;
        private readonly IWebHostEnvironment _env;

        public BusinessCardController(BusinessCardDbContext context, IWebHostEnvironment env)
        {
            _context = context;
            _env = env;
        }

        /// <summary>
        /// Upload a business card image and extract structured data using Azure Document Intelligence.
        /// </summary>
        /// <param name="image">Business card image (JPEG, PNG, or PDF)</param>
        /// <returns>Extracted business card data</returns>
        [HttpPost("upload")]
        [ProducesResponseType(typeof(BusinessCard), StatusCodes.Status200OK)]
        [ProducesResponseType(StatusCodes.Status400BadRequest)]
        public async Task<IActionResult> UploadCard([FromForm] IFormFile image)
        {
            try
            {
                if (image == null || image.Length == 0)
                    return BadRequest("No image uploaded.");

                var uploadsDir = Path.Combine(_env.ContentRootPath, "uploads");
                Directory.CreateDirectory(uploadsDir);

                var filePath = Path.Combine(uploadsDir, Guid.NewGuid() + Path.GetExtension(image.FileName));
                using (var stream = new FileStream(filePath, FileMode.Create))
                {
                    await image.CopyToAsync(stream);
                }

                var card = await ExtractBusinessCardData(filePath);
                if (card == null)
                    return BadRequest("Could not extract business card data.");
                string cardJsonString = JsonSerializer.Serialize(card);
                ChatCompletion result = await MapFieldsUsingAzureOpenAI(cardJsonString);


                var jsonObject = JsonSerializer.Deserialize<Dictionary<string, object>>(result.Content[0].Text);

                var businessCard = JsonSerializer.Deserialize<BusinessCard>(jsonObject["finalMapping"].ToString());
                _context.BusinessCards.Add(businessCard);

                await _context.SaveChangesAsync();
                return Ok(jsonObject);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message.ToString());
            }
        }

        public async Task<Dictionary<string, object>> ExtractBusinessCardData(string imagePath)
        {
            var client = new DocumentAnalysisClient(
                new Uri(AzureAIConstants.DocumentAnalysisEndpoint),
                new AzureKeyCredential(AzureAIConstants.DocumentAnalysisApiKey)
            );

            using var stream = System.IO.File.OpenRead(imagePath);
            var operation = await client.AnalyzeDocumentAsync(WaitUntil.Completed, "prebuilt-businessCard", stream);
            var result = operation.Value;

            var card = new BusinessCard();
            var values = ConvertFieldsToJson(result);

            return values;

        }

        public Dictionary<string, object> ConvertFieldsToJson(Azure.AI.FormRecognizer.DocumentAnalysis.AnalyzeResult result)
        {
            var doc = result.Documents.FirstOrDefault();
            if (doc == null) return new Dictionary<string, object>();

            var jsonDict = new Dictionary<string, object>();

            foreach (var field in doc.Fields)
            {
                var key = field.Key;
                var value = field.Value;

                if (value.FieldType == Azure.AI.FormRecognizer.DocumentAnalysis.DocumentFieldType.List)
                {
                    var listItems = value.Value.AsList().Select(item => item.Content).ToList();
                    jsonDict[key] = listItems;
                }
                else if (value.FieldType == Azure.AI.FormRecognizer.DocumentAnalysis.DocumentFieldType.Dictionary)
                {
                    var dictItems = new Dictionary<string, string>();
                    foreach (var kvp in value.Value.AsDictionary())
                    {
                        dictItems[kvp.Key] = kvp.Value.Content;
                    }
                    jsonDict[key] = dictItems;
                }
                else
                {
                    jsonDict[key] = value.Content;
                }
            }

            return jsonDict;// JsonSerializer.Serialize(jsonDict, new JsonSerializerOptions { WriteIndented = true });
        }



        public async Task<ChatCompletion> MapFieldsUsingAzureOpenAI(string extractedJson)
        {
            var prompt = $@"
                          Here is the fixed C# model:
                          public class BusinessCard {{
                            public int Id {{ get; set; }}
                            public string Name {{ get; set; }}
                            public string Company {{ get; set; }}
                            public string Email {{ get; set; }}
                            public string Phone {{ get; set; }}
                            public string Address {{ get; set; }}
                          }}

                          Here is the incoming JSON:
                          {extractedJson}

                          ";
            // Retrieve the OpenAI endpoint from environment variables
            var endpoint = AzureAIConstants.AzureOpenAIEndpoint;


            var key = AzureAIConstants.AzureOpenAIApiKey;


            AzureKeyCredential credential = new AzureKeyCredential(key);

            // Initialize the AzureOpenAIClient
            AzureOpenAIClient azureClient = new(new Uri(endpoint), credential);

            // Initialize the ChatClient with the specified deployment name
            ChatClient chatClient = azureClient.GetChatClient("gpt-4.1");

            // Create a list of chat messages
            var messages = new List<ChatMessage>
            {
             new SystemChatMessage(@"You are a smart field-mapping engine."),
              new UserChatMessage(@"Map the incoming Json and its value with given C# model and provide the output as 
                                   json of C# model with values, please give plain json response without any slashes 
                                   and in seperate property say finalMapping, also add incoming json in the response as seperate 
                                   property as incomingJson, also for properties from incoming json which cannot be mapped or 
                                   not very confident in mapping with C# model in such case match those properties to others prop
                                   in c# model:"+prompt),
            };


            // Create chat completion options

            var options = new ChatCompletionOptions
            {
                Temperature = (float)1,
                MaxOutputTokenCount = 800,

                TopP = (float)1,
                FrequencyPenalty = (float)0,
                PresencePenalty = (float)0
            };


            // Create the chat completion request
            ChatCompletion completion = await chatClient.CompleteChatAsync(messages, options);

            return completion;

        }
    }
    public class OpenAIResponse
    {
        public List<Choice> Choices { get; set; }

        public class Choice
        {
            public Message Message { get; set; }
        }

        public class Message
        {
            public string Role { get; set; }
            public string Content { get; set; }
        }
    }

}

BusinessCardDbContext

using BusinessCardApi.Model;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

namespace BusinessCardApi.DataFactory
{
    public class BusinessCardDbContext : DbContext
    {
        public BusinessCardDbContext(DbContextOptions<BusinessCardDbContext> options) : base(options) { }

        public DbSet<BusinessCard> BusinessCards { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<BusinessCard>().ToTable("BusinessCard");
        }

    }
}

BusinessCard Model:

using System.ComponentModel.DataAnnotations.Schema;

namespace BusinessCardApi.Model
{
   
    public class BusinessCard
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Company { get; set; }
        public string Email { get; set; }
        public string Phone { get; set; }
        public string Address { get; set; }
        public string? Others { get; set; }

    }
}