IRONSOFTWAREHOME
MIGRATION GUIDES

Migrating from Accusoft BarcodeXpress to IronBarcode

Curtis Chau
Curtis Chau
Updated: August 1, 2026

Most of the work in this migration is deletion. The two-key licensing system - SetSolutionName, SetSolutionKey, and SetOEMLicenseKey for runtime - disappears entirely. The actual barcode operations (read an image, write a barcode to a file) translate to shorter IronBarcode equivalents. If your codebase has a BarcodeService class that wraps BarcodeXpress, the licensing code is often a large fraction of it. After migration, that class shrinks.

Why Migrate from Accusoft BarcodeXpress

Teams migrating from BarcodeXpress report these triggers:

Evaluation Mode Blocks Accurate Benchmarking: Without a valid OEM/runtime key, BarcodeXpress stamps decoded results with the literal string " UNLICENSED accusoft.com " and applies the same stamp to generated 2D barcodes. Pre-purchase accuracy testing on real documents produces this watermarked output, so you cannot verify that the library reads your actual scan types correctly before committing to a purchase.

Two-Key Licensing Increases Operational Overhead: BarcodeXpress separates the SDK license (SetSolutionName + SetSolutionKey) from the OEM/runtime license (SetOEMLicenseKey). CI/CD pipelines, Docker containers, and container orchestrators each need both key systems managed as separate secrets. A missing or invalid runtime key falls back to watermarked output rather than raising an error, creating a failure mode that can pass automated tests if assertions check only for non-null results.

Minimum Five Runtime Licenses for Any Production Deployment: Even a single-server deployment requires purchasing at least five runtime licenses. Teams running one production server and one staging server pay for ten runtime licenses minimum, regardless of actual usage.

40 PPM Standard Edition Ceiling: The Standard Edition throttles processing to 40 pages per minute. A batch of 100,000 documents takes roughly 41 hours at that rate. Removing the ceiling requires upgrading to the Professional Edition, which carries a higher per-developer seat cost on top of the runtime licenses already purchased.

No Native PDF Support: PDF files must be rendered to images using a separate library before BarcodeXpress can read them. That external dependency adds a second licensing cost, a conversion step, and additional memory pressure from holding rendered page images.

Thread Safety Requires Instance Isolation: BarcodeXpress's reader object is stateful and not safe for concurrent access. Parallel batch processing requires one fully initialized BarcodeXpress instance per thread, with the full two-layer license initialization repeated in each thread context.

The Fundamental Problem

BarcodeXpress requires a multi-step initialization, a Bitmap load, and a BarcodeType[] configuration before any barcode can be read:

using var bitmap = new Bitmap(imagePath);
var barcodeXpress = new BarcodeXpress(".");
barcodeXpress.Licensing.SetSolutionName("AcmeCorp");
barcodeXpress.Licensing.SetSolutionKey(1, 2, 3, 4);
barcodeXpress.Licensing.SetOEMLicenseKey("2.0.OEMLicenseStringFromAccusoft...");

barcodeXpress.reader.BarcodeTypes = new[]
{
    BarcodeType.Code128Barcode,
    BarcodeType.DataMatrixBarcode,
    BarcodeType.QRCodeBarcode
};

Result[] results = barcodeXpress.reader.Analyze(bitmap);
var value = results.FirstOrDefault()?.BarcodeValue;

IronBarcode replaces this entire block with a single static call:

var value = BarcodeReader.Read(imagePath).First().Value;

IronBarcode vs Accusoft BarcodeXpress: Feature Comparison

FeatureAccusoft BarcodeXpressIronBarcode
License modelSDK key + OEM/runtime key (separate purchases)Single perpetual key
Minimum runtime licenses5 (even for 1 server)No runtime license concept
Evaluation modeDecoded values and generated 2D barcodes stamped with " UNLICENSED accusoft.com "Full values returned; watermark on generated output only
Throughput limit40 PPM (Standard Edition)No limit at any tier
Format auto-detectionManual - must assign a BarcodeType[] array to BarcodeTypesAutomatic across all supported formats
PDF supportRequires external library to render pages to BitmapsNative - BarcodeReader.Read("doc.pdf")
API styleInstance-based; Bitmap input; property/method configurationStatic factory methods, fluent API
Thread safetyInstance-per-thread requiredStateless static methods - thread-safe
Docker license configLicense file mount or license serverSingle environment variable
CI/CD secrets requiredSDK key pair + OEM/runtime keyOne secret
.NET Framework / .NET CoreSeparate packages: Accusoft.BarcodeXpress.Net and Accusoft.BarcodeXpress.NetCoreSingle IronBarcode package (.NET Framework 4.6.2+, .NET Core 3.1+, .NET 5-8)
Linux/macOSYes (via .NetCore package)Yes - Windows x64/x86, Linux x64, macOS x64/ARM
QR code with logoManual GDI+ overlay requiredAddBrandLogo("logo.png") built in
Pricing entry point$1,960+ SDK + minimum 5 runtime licenses$999 perpetual (Lite, 1 developer)
Perpetual licenseNot standard - contact salesYes, all tiers

Quick Start: Accusoft BarcodeXpress to IronBarcode Migration

Step 1: Replace NuGet Package

dotnet remove package Accusoft.BarcodeXpress.NetCore
dotnet add package IronBarcode
SHELL

Step 2: Update Namespaces

// Remove
using Accusoft.BarcodeXpressSdk;

// Add
using IronBarCode;

Step 3: Initialize License

Add license initialization once at application startup in Program.cs, Startup.cs, or your dependency injection configuration:

// Add once at application startup
IronBarCode.License.LicenseKey = "YOUR-LICENSE-KEY";

In production, read the key from an environment variable or your secrets manager:

IronBarCode.License.LicenseKey =
    Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE")
    ?? throw new InvalidOperationException("IronBarcode license key not configured");

No SetSolutionKey, no SetOEMLicenseKey, no per-server runtime activation. That is the complete license setup.

Code Migration Examples

License Initialization

BarcodeXpress Approach:

using Accusoft.BarcodeXpressSdk;

public class BarcodeService
{
    private readonly BarcodeXpress _barcodeXpress;

    public BarcodeService()
    {
        // Constructor takes the path containing the Barcode Xpress runtime files.
        _barcodeXpress = new BarcodeXpress(".");

        // SDK license
        _barcodeXpress.Licensing.SetSolutionName("AcmeCorp");
        _barcodeXpress.Licensing.SetSolutionKey(1, 2, 3, 4);

        // OEM/runtime license — separate purchase, minimum 5 licenses required.
        // Without this call, decoded values and generated 2D barcodes are
        // stamped with " UNLICENSED accusoft.com ".
        _barcodeXpress.Licensing.SetOEMLicenseKey(
            "2.0.OEMLicenseStringFromAccusoft...");
    }
}

IronBarcode Approach:

using IronBarCode;

// In Program.cs
IronBarCode.License.LicenseKey = Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE");

// BarcodeService no longer needs a constructor or any license management
public class BarcodeService
{
    // Ready to use — no initialization needed
}

The BarcodeXpress constructor exists solely to manage two license key systems and the runtime path. IronBarcode replaces it with one line at application startup. The BarcodeService class requires no constructor at all.

Barcode Reading

BarcodeXpress Approach:

using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public string ReadFirstBarcode(string imagePath)
{
    // Analyze takes a System.Drawing.Bitmap; the SDK does not read PDFs directly.
    using var bitmap = new Bitmap(imagePath);

    _barcodeXpress.reader.BarcodeTypes = new[]
    {
        BarcodeType.Code128Barcode,
        BarcodeType.DataMatrixBarcode,
        BarcodeType.QRCodeBarcode
    };

    Result[] results = _barcodeXpress.reader.Analyze(bitmap);

    return results.FirstOrDefault()?.BarcodeValue;
}

IronBarcode Approach:

using IronBarCode;

public string ReadFirstBarcode(string imagePath)
{
    var results = BarcodeReader.Read(imagePath);
    return results.First().Value;
}

The BarcodeTypes array filter and the new Bitmap(...) load step both disappear. IronBarcode auto-detects format across all supported symbologies and accepts a file path directly. If a supplier switches from Code 128 to DataMatrix, IronBarcode continues to work without any code change. Result property names also change: BarcodeValue becomes Value, and BarcodeType becomes Format. A solution-wide search-and-replace handles both renames.

Reading Multiple Barcodes from One Image

BarcodeXpress Approach:

using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public IReadOnlyList<string> ReadAllBarcodes(string imagePath)
{
    using var bitmap = new Bitmap(imagePath);
    _barcodeXpress.reader.BarcodeTypes = new[]
    {
        BarcodeType.Code128Barcode,
        BarcodeType.QRCodeBarcode
    };

    Result[] results = _barcodeXpress.reader.Analyze(bitmap);
    return results.Select(r => r.BarcodeValue).ToList();
}

IronBarcode Approach:

using IronBarCode;

public IReadOnlyList<string> ReadAllBarcodes(string imagePath)
{
    var options = new BarcodeReaderOptions { ExpectMultipleBarcodes = true };
    var results = BarcodeReader.Read(imagePath, options);
    return results.Select(r => r.Value).ToList();
}

ExpectMultipleBarcodes tells IronBarcode to continue scanning after the first match, which is useful for documents with several codes in different regions. For more detail on reading options, see the IronBarcode reading documentation.

Batch Processing

BarcodeXpress is instance-based and its reader object is stateful, so parallel batch processing requires one instance per thread with the full two-layer license initialization repeated per thread. IronBarcode's static methods are stateless, so Parallel.ForEach needs no instance management.

BarcodeXpress Approach:

using System.Collections.Generic;
using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public Dictionary<string, string> ProcessBatch(IEnumerable<string> imagePaths)
{
    var results = new Dictionary<string, string>();

    foreach (var path in imagePaths)
    {
        using var bitmap = new Bitmap(path);
        _barcodeXpress.reader.BarcodeTypes = new[]
        {
            BarcodeType.Code128Barcode,
            BarcodeType.QRCodeBarcode
        };

        Result[] barcodes = _barcodeXpress.reader.Analyze(bitmap);
        if (barcodes.Length > 0)
            results[path] = barcodes[0].BarcodeValue;
    }

    return results;
}

IronBarcode Approach:

using IronBarCode;
using System.Collections.Concurrent;
using System.Threading.Tasks;

public Dictionary<string, string> ProcessBatch(string[] imagePaths)
{
    var results = new ConcurrentDictionary<string, string>();

    Parallel.ForEach(imagePaths, file =>
    {
        var r = BarcodeReader.Read(file);
        var first = r.FirstOrDefault();
        if (first != null)
            results[file] = first.Value;
    });

    return new Dictionary<string, string>(results);
}

If the BarcodeXpress Standard Edition's 40-pages-per-minute ceiling caused you to add rate-limit handling code - sleeping between groups of 40, tracking a per-minute counter, or adding delays - remove that code entirely. IronBarcode has no throughput ceiling.

Adding PDF Support

BarcodeXpress does not read barcodes directly from PDF files. The typical workaround involves adding a separate PDF rendering library, rendering each page to an image in memory, and then passing those images to the barcode reader one at a time.

BarcodeXpress Approach:

// Requires a separate PDF library (not shown — varies by team choice)
// Pattern: render each PDF page to a Bitmap, then pass it to Analyze.
foreach (Bitmap pageBitmap in pdfRenderer.RenderPages("document.pdf"))
{
    using (pageBitmap)
    {
        _barcodeXpress.reader.BarcodeTypes = Enum.GetValues(typeof(BarcodeType));
        Result[] barcodes = _barcodeXpress.reader.Analyze(pageBitmap);
        // ... collect results
    }
}

IronBarcode Approach:

using IronBarCode;

// One call — no rendering step, no external dependency
var results = BarcodeReader.Read("document.pdf");

foreach (var barcode in results)
{
    Console.WriteLine($"Page {barcode.PageNumber}: [{barcode.Format}] {barcode.Value}");
}

If Aspose.PDF, PdfiumViewer, itext7, or any other PDF library was added solely to support the BarcodeXpress reading workflow, it can be removed after migration. See the IronBarcode PDF reading guide for additional options including page range selection.

Barcode Generation

BarcodeXpress Approach:

using System.Drawing;
using Accusoft.BarcodeXpressSdk;

public void GenerateBarcode(string data, string outputPath)
{
    _barcodeXpress.writer.BarcodeType = BarcodeType.Code128Barcode;
    _barcodeXpress.writer.BarcodeValue = data;

    // CreateBitmap returns a System.Drawing.Bitmap; persist via Bitmap.Save.
    using Bitmap bitmap = _barcodeXpress.writer.CreateBitmap();
    bitmap.Save(outputPath);
}

IronBarcode Approach:

using IronBarCode;

public void GenerateBarcode(string data, string outputPath)
{
    BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
        .ResizeTo(400, 100)
        .SaveAsPng(outputPath);
}

The fluent chain replaces the property assignments, the CreateBitmap call, and the Bitmap.Save step. To get the barcode as binary data for storing in a database or returning from an API:

byte[] pngBytes = BarcodeWriter.CreateBarcode(data, BarcodeEncoding.Code128)
    .ToPngBinaryData();

QR Code Generation

BarcodeXpress Approach:

_barcodeXpress.writer.BarcodeType = BarcodeType.QRCodeBarcode;
_barcodeXpress.writer.BarcodeValue = data;

using Bitmap bitmap = _barcodeXpress.writer.CreateBitmap();
bitmap.Save("qr.png");
// Logo overlay required manual GDI+ drawing on the returned Bitmap

IronBarcode Approach:

using IronBarCode;
using IronSoftware.Drawing;

// Simple QR
QRCodeWriter.CreateQrCode("https://example.com", 500)
    .SaveAsPng("qr.png");

// With branded logo
QRCodeWriter.CreateQrCode("https://example.com", 500)
    .AddBrandLogo("logo.png")
    .SaveAsPng("qr-branded.png");

// With high error correction (for logo overlays)
QRCodeWriter.CreateQrCode(
    "https://example.com",
    500,
    QRCodeWriter.QrErrorCorrectionLevel.Highest)
    .AddBrandLogo("logo.png")
    .SaveAsPng("qr-branded-high-ecc.png");

// Colored QR code
QRCodeWriter.CreateQrCode("https://example.com", 300)
    .ChangeBarCodeColor(Color.DarkBlue)
    .SaveAsPng("qr-colored.png");

Logo embedding, error correction level, and color customization are all built into the fluent API. BarcodeXpress requires manual GDI+ drawing after the initial file write for any of these features. For more QR code options, see the QR code generation guide.

Accusoft BarcodeXpress API to IronBarcode Mapping Reference

Accusoft BarcodeXpressIronBarcode
new BarcodeXpress(".")Static methods - no instance required
Licensing.SetSolutionName("...")IronBarCode.License.LicenseKey = "key"
Licensing.SetSolutionKey(a, b, c, d)(removed - not needed)
Licensing.SetOEMLicenseKey(string)(removed - no OEM/runtime key concept)
new Bitmap(path) + reader.Analyze(bitmap)BarcodeReader.Read(path)
reader.BarcodeTypes = new[] { BarcodeType.Code128Barcode, ... }(removed - auto-detection handles all formats)
result.BarcodeValueresult.Value
result.BarcodeTyperesult.Format
writer.BarcodeType = BarcodeType.Code128BarcodeBarcodeWriter.CreateBarcode("data", BarcodeEncoding.Code128)
writer.BarcodeValue = "data"(first argument to CreateBarcode)
writer.CreateBitmap() + bitmap.Save(path).SaveAsPng(path)
writer.BarcodeType = BarcodeType.QRCodeBarcodeQRCodeWriter.CreateQrCode(data, size)
40 PPM Standard limitNo throughput limit at any tier

Common Migration Issues and Solutions

Issue 1: Property Name Compile Errors

BarcodeXpress: Result objects expose BarcodeValue and BarcodeType, which do not exist in IronBarcode.

Solution: Run search-and-replace across the solution before building:

grep -r "\.BarcodeValue" --include="*.cs" .
grep -r "\.BarcodeType" --include="*.cs" .
SHELL

Replace result.BarcodeValue with result.Value and result.BarcodeType with result.Format throughout all files found.

Issue 2: Orphaned License Configuration Calls

BarcodeXpress: SetSolutionName, SetSolutionKey, and SetOEMLicenseKey calls - plus any custom assertions that detect the " UNLICENSED accusoft.com " watermark in decoded output - exist across many codebases as defenses against the watermarked-output failure mode.

Solution: Locate and delete all such call sites - IronBarcode has no equivalent state. The license key is either valid or not, and if it is not, the trial limits apply uniformly rather than degrading individual decoded values:

grep -r "SetOEMLicenseKey" --include="*.cs" .
grep -r "SetSolutionName" --include="*.cs" .
grep -r "SetSolutionKey" --include="*.cs" .
grep -r "UNLICENSED accusoft" --include="*.cs" .
SHELL

All of these call sites can be deleted.

Issue 3: Docker License File Mount to Environment Variable

BarcodeXpress: Docker deployments typically mount a BarcodeXpress license configuration file into the container at a known path using a COPY or volume mount instruction.

Solution: Remove the config file copy and replace with an environment variable:

# Remove this
COPY accusoft-license.lic /app/license/

# Add this
ENV IRONBARCODE_LICENSE=YOUR-LICENSE-KEY
Text

In application startup:

IronBarCode.License.LicenseKey =
    Environment.GetEnvironmentVariable("IRONBARCODE_LICENSE");

In Kubernetes, the license key becomes a secret reference in the pod spec:

env:
  - name: IRONBARCODE_LICENSE
    valueFrom:
      secretKeyRef:
        name: ironbarcode-secrets
        key: license-key
Text

Issue 4: Rate Limit Handling Code

BarcodeXpress: Teams processing large batches under the Standard Edition 40-PPM ceiling often added code to sleep between groups of documents, track per-minute counters, or introduce delays to stay within the limit.

Solution: Remove all rate-limiting code. Locate it with:

grep -r "40\|PPM\|pagesPerMinute\|minuteStart" --include="*.cs" .
SHELL

IronBarcode has no throughput ceiling - process at whatever rate your infrastructure supports.

Issue 5: Thread Safety - Instance Pool Removal

BarcodeXpress: Codebases that support concurrent processing often maintain a pool of BarcodeXpress instances or use a ThreadLocal<BarcodeXpress> pattern to isolate the stateful reader per thread.

Solution: Remove the pooling logic entirely. IronBarcode's BarcodeReader.Read and BarcodeWriter.CreateBarcode are stateless static methods. Concurrent calls from any number of threads do not interfere with each other.

Accusoft BarcodeXpress Migration Checklist

Pre-Migration Tasks

Audit the codebase to identify all BarcodeXpress usage before making any code changes:

grep -r "BarcodeXpress" --include="*.cs" .
grep -r "Accusoft" --include="*.cs" .
grep -r "SetSolutionName" --include="*.cs" .
grep -r "SetSolutionKey" --include="*.cs" .
grep -r "SetOEMLicenseKey" --include="*.cs" .
grep -r "reader\.Analyze" --include="*.cs" .
grep -r "writer\.CreateBitmap" --include="*.cs" .
grep -r "\.BarcodeValue" --include="*.cs" .
grep -r "\.BarcodeType" --include="*.cs" .
grep -r "BarcodeType\." --include="*.cs" .
SHELL
  • Note which barcode formats are explicitly listed in BarcodeTypes assignments - these all become auto-detected in IronBarcode
  • Identify any rate-limit handling code that can be removed
  • Identify any PDF rendering libraries added solely to support BarcodeXpress reading - these can also be removed
  • Obtain your IronBarcode license key and add it to your secrets manager

Code Update Tasks

  1. Remove Accusoft.BarcodeXpress.NetCore from all .csproj files
  2. Add IronBarcode to all .csproj files that need barcode functionality
  3. Replace using Accusoft.BarcodeXpressSdk; with using IronBarCode; across all files
  4. Add IronBarCode.License.LicenseKey = ... to application startup
  5. Delete all BarcodeXpress constructor calls and instance fields
  6. Delete all SetSolutionName, SetSolutionKey, and SetOEMLicenseKey calls
  7. Delete any custom assertions that scan decoded output for the " UNLICENSED accusoft.com " watermark
  8. Replace new Bitmap(path) + reader.Analyze(bitmap) with BarcodeReader.Read(path)
  9. Remove all reader.BarcodeTypes = ... assignments
  10. Replace result.BarcodeValue with result.Value
  11. Replace result.BarcodeType with result.Format
  12. Replace writer.CreateBitmap() + bitmap.Save(path) with BarcodeWriter.CreateBarcode(data, encoding).SaveAsPng(path)
  13. Remove rate-limit throttling code
  14. Remove PDF rendering intermediary code if present
  15. Remove instance pooling or ThreadLocal patterns for BarcodeXpress instances
  16. Remove license file mounts from Dockerfile and docker-compose files
  17. Add IRONBARCODE_LICENSE environment variable to Docker and container configs
  18. Update Kubernetes secrets and pod specs
  19. Update CI/CD pipeline secrets - remove ACCUSOFT_SOLUTION_KEY and ACCUSOFT_RUNTIME_KEY; add IRONBARCODE_LICENSE

Post-Migration Testing

  • Build the solution - fix any remaining compile errors from renamed properties
  • Run unit tests against all barcode read operations
  • Run unit tests against all barcode generation operations
  • Test with PDF inputs if applicable
  • Run a batch processing test to confirm no throughput throttling behavior
  • Deploy to a staging environment and verify the license key resolves correctly from the environment variable

Key Benefits of Migrating to IronBarcode

Elimination of Two-Key License Complexity: The SetSolutionName, SetSolutionKey, and SetOEMLicenseKey setup disappears entirely. One key covers every environment from development to production, and the trial mode returns complete decoded values (rather than stamping each one with " UNLICENSED accusoft.com ") so pre-purchase benchmarking on real documents is possible.

No Runtime License Minimum Purchase: BarcodeXpress requires a minimum of five runtime licenses for any production deployment. IronBarcode has no runtime license concept - the single perpetual key covers any number of production deployments within its tier.

Throughput Without a Ceiling: The Standard Edition 40-PPM cap and any rate-limiting code written to stay within it can be removed. IronBarcode processes at whatever rate the underlying hardware and network support, with no software-imposed ceiling at any pricing tier.

Native PDF Reading: BarcodeReader.Read("document.pdf") processes PDF files directly, returning per-page results with page number, format, value, and confidence score. Any PDF rendering library added solely to support BarcodeXpress can be removed, reducing dependencies and licensing costs.

Stateless Thread Safety: BarcodeReader.Read and BarcodeWriter.CreateBarcode are stateless static methods. Instance pools, ThreadLocal patterns, and per-thread initialization blocks can all be removed. Concurrent processing with Parallel.ForEach requires no structural changes beyond removing the threading workarounds.

Simplified Container Deployment: Docker and Kubernetes deployments use a single environment variable for license configuration. License file distribution, license server infrastructure, and config file mounts are all eliminated.

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