IRONSOFTWAREHOME
MIGRATION GUIDES

Migrating from Dynamsoft Barcode Reader to IronBarcode

Curtis Chau
Curtis Chau
Updated: August 1, 2026

Most developers who migrate from Dynamsoft Barcode Reader to IronBarcode fall into one of two groups: those who chose Dynamsoft for its reputation and then discovered the camera-centric API didn't match a document processing use case, and those running in air-gapped or Docker environments where the license server dependency caused production incidents.

If you are in the first group, the migration removes the external PDF rendering library, the per-page render loop, and the error-code license pattern. If you are in the second group, the migration removes the InitLicense network call, the offline license-content bundle and refresh cycle, and the outbound network policy from your Docker or VPC configuration. Either way, the codebase gets shorter after this migration.

This guide is honest about what you lose: if your application processes real-time camera frames, Dynamsoft's Capture Vision pipeline is tuned for that workload and IronBarcode is not the right replacement. This migration guide is for server-side file processing, document workflows, and environments where license server access is a problem.

Step 1: Swap the NuGet Packages

dotnet remove package Dynamsoft.DotNet.BarcodeReader.Bundle
dotnet add package BarCode
SHELL

If your project also has a PDF rendering library added specifically for Dynamsoft (PdfiumViewer is the most common), that can be removed too:

# Remove if added only for Dynamsoft PDF support
dotnet remove package PdfiumViewer
dotnet remove package PdfiumViewer.Native.x86_64.v8-xfa
SHELL

Step 2: Replace License Initialization

This is where the most immediate simplification happens. The Dynamsoft pattern requires an error code check and exception handling around every startup:

Before - Dynamsoft:

using Dynamsoft.License;
using Dynamsoft.Core;

// Must run before any barcode operations
int errorCode = LicenseManager.InitLicense("YOUR-DYNAMSOFT-KEY", out string errorMsg);
if (errorCode != (int)EnumErrorCode.EC_OK)
    throw new InvalidOperationException($"License validation failed [{errorCode}]: {errorMsg}");

After - IronBarcode:

// NuGet: dotnet add package BarCode
using IronBarCode;

// Local validation — no network call, no error code
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";

In an ASP.NET Core application, add this to Program.cs before builder.Build():

IronBarCode.License.LicenseKey = Environment.GetEnvironmentVariable("IRONBARCODE_KEY")
    ?? "YOUR-LICENSE-KEY";

In a Docker or Kubernetes environment, set the IRONBARCODE_KEY environment variable in your deployment manifest. No outbound network rules required.

Step 3: Replace Namespace Imports

Find and replace across all source files:

grep -r "using Dynamsoft\." --include="*.cs" .
SHELL

Replace each occurrence:

// Before
using Dynamsoft.CVR;
using Dynamsoft.DBR;
using Dynamsoft.License;
using Dynamsoft.Core;

// After
using IronBarCode;

Code Migration Examples

Basic File Reading

The most fundamental operation - reading a barcode from an image file.

Before - Dynamsoft:

using Dynamsoft.CVR;
using Dynamsoft.DBR;

public string ReadBarcodeFromFile(CaptureVisionRouter router, string imagePath)
{
    CapturedResult result = router.Capture(imagePath, PresetTemplate.PT_READ_BARCODES);
    BarcodeResultItem[] items = result.GetDecodedBarcodesResult()?.GetItems();
    if (items == null || items.Length == 0)
        return null;

    return items[0].GetText();
}

After - IronBarcode:

// NuGet: dotnet add package BarCode
using IronBarCode;

public string ReadBarcodeFromFile(string imagePath)
{
    var results = BarcodeReader.Read(imagePath);
    return results?.FirstOrDefault()?.Value;
}

The router instance is gone. BarcodeReader.Read is static. BarcodeResultItem.GetText() becomes .Value. The null check on results is cleaner with LINQ.

Reading Multiple Barcodes

Before - Dynamsoft:

using Dynamsoft.CVR;
using Dynamsoft.DBR;

public List<string> ReadAllBarcodes(CaptureVisionRouter router, string imagePath)
{
    SimplifiedCaptureVisionSettings settings = router.GetSimplifiedSettings(
        PresetTemplate.PT_READ_BARCODES);
    settings.BarcodeSettings.ExpectedBarcodesCount = 0; // 0 = find all
    router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings);

    CapturedResult result = router.Capture(imagePath, PresetTemplate.PT_READ_BARCODES);
    BarcodeResultItem[] items = result.GetDecodedBarcodesResult()?.GetItems();
    var values = new List<string>();

    if (items != null)
    {
        foreach (var item in items)
            values.Add(item.GetText());
    }

    return values;
}

After - IronBarcode:

using IronBarCode;

public List<string> ReadAllBarcodes(string imagePath)
{
    var options = new BarcodeReaderOptions
    {
        ExpectMultipleBarcodes = true,
        MaxParallelThreads = 4
    };

    return BarcodeReader.Read(imagePath, options)
        .Select(r => r.Value)
        .ToList();
}

Reading from Bytes (In-Memory Images)

Before - Dynamsoft:

using Dynamsoft.CVR;
using Dynamsoft.Core;
using Dynamsoft.DBR;

// Requires width, height, stride, and pixel format — low-level buffer API
public string ReadFromBuffer(CaptureVisionRouter router, byte[] rawPixels, int width, int height)
{
    var imageData = new ImageData
    {
        Bytes = rawPixels,
        Width = width,
        Height = height,
        Stride = width * 3, // assuming 24bpp RGB
        Format = EnumImagePixelFormat.IPF_RGB_888
    };

    CapturedResult result = router.Capture(imageData, PresetTemplate.PT_READ_BARCODES);
    return result.GetDecodedBarcodesResult()?.GetItems()?.FirstOrDefault()?.GetText();
}

After - IronBarcode:

using IronBarCode;

// Pass PNG/JPEG/BMP bytes directly — no pixel format or stride calculation
public string ReadFromImageBytes(byte[] imageBytes)
{
    return BarcodeReader.Read(imageBytes)?.FirstOrDefault()?.Value;
}

If your application previously converted image bytes into a raw pixel buffer for Dynamsoft, you can pass the original encoded image bytes (PNG, JPEG, BMP) directly to IronBarcode without decoding to raw pixels first.

PDF Barcode Reading - Remove the Render Loop

This is typically the largest code reduction in the migration. Remove the entire PdfiumViewer render loop and replace it with a single call.

Before - Dynamsoft with PdfiumViewer:

// Requires: Dynamsoft.DotNet.BarcodeReader.Bundle + PdfiumViewer + PdfiumViewer.Native.*
using Dynamsoft.CVR;
using Dynamsoft.DBR;
using PdfiumViewer;
using System.Drawing.Imaging;

public List<string> ReadBarcodesFromPdf(CaptureVisionRouter router, string pdfPath)
{
    var allBarcodes = new List<string>();

    using (var pdfDoc = PdfDocument.Load(pdfPath))
    {
        for (int page = 0; page < pdfDoc.PageCount; page++)
        {
            using var image = pdfDoc.Render(page, 300, 300, true);
            using var ms = new MemoryStream();
            image.Save(ms, ImageFormat.Png);

            CapturedResult result = router.Capture(ms.ToArray(),
                PresetTemplate.PT_READ_BARCODES);
            var items = result.GetDecodedBarcodesResult()?.GetItems();
            if (items != null)
            {
                foreach (var item in items)
                    allBarcodes.Add(item.GetText());
            }
        }
    }

    return allBarcodes;
}

After - IronBarcode:

using IronBarCode;

public List<string> ReadBarcodesFromPdf(string pdfPath)
{
    return BarcodeReader.Read(pdfPath)
        .Select(r => r.Value)
        .ToList();
}

The page loop, the PdfDocument, the 300 DPI render step, the MemoryStream, and the per-page Capture call all disappear. IronBarcode handles PDF pages internally.

If you need to read from a PDF with options (for dense or difficult barcodes):

using IronBarCode;

public List<string> ReadBarcodesFromPdfAccurate(string pdfPath)
{
    var options = new BarcodeReaderOptions
    {
        Speed = ReadingSpeed.Balanced,
        ExpectMultipleBarcodes = true
    };

    return BarcodeReader.Read(pdfPath, options)
        .Select(r => r.Value)
        .ToList();
}

Offline / Air-Gapped Deployment

If your current code includes the offline licensing pattern, remove it entirely:

Before - Dynamsoft offline license:

using Dynamsoft.License;
using Dynamsoft.Core;

// Dynamsoft offline: fetch license bundle on a connected machine, persist it,
// then replay it on the offline machine via InitLicenseFromLicenseContent.
int errorCode = LicenseManager.InitLicenseFromLicenseContent(
    licenseContent,
    out string errorMsg);

if (errorCode != (int)EnumErrorCode.EC_OK)
    throw new InvalidOperationException($"Offline license failed: {errorMsg}");

After - IronBarcode:

// Remove all of the above. Replace with:
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";

No license-content bundle to fetch and refresh. No connected-machine bootstrap step. The key validates locally.

Docker Configuration

If you previously had network egress rules or proxy configuration to allow outbound HTTPS to Dynamsoft's licence endpoints:

# Before: Docker or Kubernetes egress policy
# Required: Allow outbound HTTPS to Dynamsoft licence endpoints

# After: Remove that egress rule.
# IronBarcode does not require outbound network access for license validation.

# Set license via environment variable
env:
  - name: IRONBARCODE_KEY
    valueFrom:
      secretKeyRef:
        name: ironbarcode-license
        key: key
Text

Instance Management Cleanup

Dynamsoft uses an instance-based API built around CaptureVisionRouter. If your code creates router instances in service classes, field initializers, or DI registrations, all of that disappears:

Before - Dynamsoft instance management:

using Dynamsoft.CVR;
using Dynamsoft.DBR;
using Dynamsoft.License;
using Dynamsoft.Core;

public class BarcodeService : IDisposable
{
    private readonly CaptureVisionRouter _router;

    public BarcodeService()
    {
        int errorCode = LicenseManager.InitLicense("KEY", out string errorMsg);
        if (errorCode != (int)EnumErrorCode.EC_OK)
            throw new InvalidOperationException(errorMsg);

        _router = new CaptureVisionRouter();

        var settings = _router.GetSimplifiedSettings(PresetTemplate.PT_READ_BARCODES);
        settings.BarcodeSettings.ExpectedBarcodesCount = 0;
        _router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings);
    }

    public string[] ReadFile(string path)
    {
        CapturedResult result = _router.Capture(path, PresetTemplate.PT_READ_BARCODES);
        var items = result.GetDecodedBarcodesResult()?.GetItems();
        return items?.Select(i => i.GetText()).ToArray() ?? Array.Empty<string>();
    }

    public void Dispose()
    {
        _router?.Dispose();
    }
}

After - IronBarcode static API:

// NuGet: dotnet add package BarCode
using IronBarCode;

public class BarcodeService
{
    // No constructor initialization — license set once at app startup
    // No Dispose — no instance to clean up

    public string[] ReadFile(string path)
    {
        var options = new BarcodeReaderOptions { ExpectMultipleBarcodes = true };
        return BarcodeReader.Read(path, options)
            .Select(r => r.Value)
            .ToArray();
    }
}

The class loses its constructor, its IDisposable implementation, and its _router field. If this service was registered in DI as a singleton or scoped service to manage the router lifecycle, that registration can be simplified or the service can become a set of static methods.

Reading Speed vs Timeout Mapping

Dynamsoft uses a Timeout in milliseconds optimized for camera frame rates. IronBarcode uses a ReadingSpeed enum:

Dynamsoft settingIronBarcode equivalent
settings.Timeout = 100 (camera pipeline)Speed = ReadingSpeed.Faster
Low timeout (prioritize speed)Speed = ReadingSpeed.Balanced
Higher timeout (prioritize accuracy)Speed = ReadingSpeed.Detailed
Maximum accuracy, no time pressureSpeed = ReadingSpeed.ExtremeDetail

For most document processing workflows where throughput matters more than sub-100ms response time, ReadingSpeed.Balanced is the right default:

var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,
    ExpectMultipleBarcodes = true,
    MaxParallelThreads = 4
};

Common Migration Issues

BarcodeResultItem.GetText() vs result.Value

The accessor changes from a method to a property:

// Before
string value = item.GetText();

// After
string value = result.Value;

BarcodeResultItem.GetFormatString() vs result.Format

Dynamsoft returns the format as a string via GetFormatString(). IronBarcode exposes it as a BarcodeEncoding enum on result.Format:

// Before
if (item.GetFormatString() == "QR_CODE")
    Console.WriteLine("Found QR code");

// After
if (result.Format == BarcodeEncoding.QRCode)
    Console.WriteLine("Found QR code");

// For logging without enum comparison — .ToString() works on both
Console.WriteLine($"Format: {result.Format}");

Null Results vs Empty Collection

Dynamsoft's GetDecodedBarcodesResult() can return null when no barcodes are found. IronBarcode returns an empty collection. Update null checks:

// Before: null check required
CapturedResult result = router.Capture(path, PresetTemplate.PT_READ_BARCODES);
var items = result.GetDecodedBarcodesResult()?.GetItems();
if (items != null && items.Length > 0)
    Process(items[0].GetText());

// After: null-safe but also correct to check Count
var results = BarcodeReader.Read(path);
if (results.Any())
    Process(results.First().Value);

SimplifiedCaptureVisionSettings to BarcodeReaderOptions

The GetSimplifiedSettings / UpdateSettings pattern becomes BarcodeReaderOptions passed to Read:

// Before
var settings = router.GetSimplifiedSettings(PresetTemplate.PT_READ_BARCODES);
settings.BarcodeSettings.ExpectedBarcodesCount = 0;
settings.Timeout = 500;
router.UpdateSettings(PresetTemplate.PT_READ_BARCODES, settings);
var result = router.Capture(path, PresetTemplate.PT_READ_BARCODES);

// After
var options = new BarcodeReaderOptions
{
    Speed = ReadingSpeed.Balanced,
    ExpectMultipleBarcodes = true
};
var results = BarcodeReader.Read(path, options);

Migration Checklist

Run these searches to find every Dynamsoft reference that needs updating:

grep -r "using Dynamsoft\." --include="*.cs" .
grep -r "LicenseManager.InitLicense\|EnumErrorCode\|EC_OK" --include="*.cs" .
grep -r "new CaptureVisionRouter\|router\.Capture\|PresetTemplate" --include="*.cs" .
grep -r "BarcodeResultItem\|GetDecodedBarcodesResult\|GetFormatString" --include="*.cs" .
grep -r "GetSimplifiedSettings\|UpdateSettings\|SimplifiedCaptureVisionSettings" --include="*.cs" .
grep -r "router\.Dispose\|InitLicenseFromLicenseContent" --include="*.cs" .
SHELL

Work through each match:

  • using Dynamsoft.*using IronBarCode
  • LicenseManager.InitLicense(key, out errorMsg) + error check → IronBarCode.License.LicenseKey = "key"
  • new CaptureVisionRouter() → remove (static API, no instance)
  • router.Capture(path, PresetTemplate.PT_READ_BARCODES)BarcodeReader.Read(path)
  • router.Capture(imageData, ...) (raw pixel buffer) → BarcodeReader.Read(imageBytes)
  • Per-page PDF render loop + router.Capture(pageBytes, ...)BarcodeReader.Read(pdfPath)
  • BarcodeResultItem.GetText()result.Value
  • BarcodeResultItem.GetFormatString()result.Format
  • GetSimplifiedSettings(...) + UpdateSettings(...)new BarcodeReaderOptions { ... }
  • router.Dispose() → remove
  • LicenseManager.InitLicenseFromLicenseContent(...) → remove entirely
  • Remove PdfiumViewer NuGet packages if they were added only to support Dynamsoft PDF processing
  • Remove Docker/Kubernetes network egress rules for Dynamsoft licence endpoints
  • Set IRONBARCODE_KEY environment variable in deployment configuration
Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...
Read More

Related Articles

Key in blue circle

Get your free 30-day Trial Key instantly.

Your trial license will be sent to your email address

No limitations. 100% unlocked. No credit card.

bullet_checkedNo credit card or account creation requiredNo limitations. 100% unlocked. No credit card.
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
Book your free Live Demo
Booking Badge

Trusted by Millions of Engineers Worldwide

Iron Software's customer logos
Get Your No-Obligation Consult
Complete the form below or email sales@ironsoftware.com
Your details will always be kept confidential.
Trusted by Millions of Engineers Worldwide
Iron Software's customer logos
Get your free 30-day Trial Key instantly.
No credit card or account creation required