Umstellung von Veryfi auf IronOCR
Dieser Leitfaden führt .NET-Entwickler durch den Austausch der Cloud-Dokumentenverarbeitungs-API von Veryfidurch IronOCR, eine lokale OCR-Bibliothek. Sie umfasst den Paketwechsel, die Bereinigung von Namespaces sowie vier vollständige Beispiele für die Codemigration, die sich auf die am häufigsten mit Veryfierstellten Muster konzentrieren: Client-Initialisierung, regionbasierte Feldextraktion, Ausgabenkategorisierung mit strukturierten Daten und Webhook-Ersatz. Das vorherige Lesen des Vergleichsartikels ist nicht erforderlich.
Warum von Veryfimigrieren?
Finanzdokumente durchlaufen die Pipeline von Veryfiin einer Richtung: aus Ihrer Infrastruktur heraus und in deren Infrastruktur hinein. Diese architektonische Tatsache ist der Hauptgrund für die meisten Migrationen. Hier sind die konkreten Probleme, die Teams dazu bewegen, den Wechsel vorzunehmen.
Jeder Dokumentenaufruf übermittelt sensible Finanzdaten an einen Server eines Drittanbieters. Quittungen enthalten die letzten vier Ziffern der Kartennummer sowie Angaben zu Lieferantenbeziehungen. Rechnungen enthalten Bankkontonummern, Bankleitzahlen und Umsatzsteuer-Identifikationsnummern von Lieferanten. Kontoauszüge enthalten die vollständige Transaktionshistorie. Mit Veryfilädt jeder einzelne ProcessDocumentAsync-Aufruf diese Bytes zu api.veryfi.com hoch, verarbeitet sie auf der Infrastruktur von Veryfiund gibt JSON zurück. Ihre Kontrolle über diese Daten endet in dem Moment, in dem die HTTP-Anfrage gesendet wird.
Vier Anmeldedaten sind erforderlich und müssen in jeder Umgebung synchronisiert werden. VeryfiClient erfordert clientId, clientSecret, username und apiKey – vier separate Geheimnisse, die in der Konfiguration gespeichert, planmäßig rotiert, in CI/CD-Pipelines injiziert und auf Offenlegung geprüft werden müssen. Ein einziger Leak von Anmeldedaten unterbricht die Authentifizierung für jedes Dokument, das in der gesamten Anwendung verarbeitet wird.IronOCR benötigt einen Lizenzschlüssel.
Die Preise pro Dokument summieren sich ohne Obergrenze. Quittungen kosten etwa 0,05–0,15 $ pro Stück, Rechnungen 0,10–0,25 $, Kontoauszüge 0,15–0,30 $. Bei 50.000 Dokumenten pro Monat ergibt sich ein Betrag von 5.000–15.000 $ pro Monat bei nutzungsabhängiger Abrechnung, ohne Reduzierung im zweiten oder dritten Jahr. Die IronOCR Professional License für 2.999 US-Dollar deckt unbegrenzt viele Dokumente auf unbefristeter Basis ab – die Amortisationszeit gegenüber monatlichen Veryfi-Kosten von 5.000 US-Dollar beträgt weniger als drei Wochen.
Die API ist ausschließlich asynchron, weil die zugrunde liegende Arbeit remote erfolgt. ProcessDocumentAsync ist nicht asynchron, weil die Verarbeitung rechnerisch aufwendig ist; Es handelt sich um einen asynchronen Vorgang, da das Dokument an einen Server gesendet werden muss, sich hinter anderen Anfragen in die Warteschlange einreiht, die Verarbeitung abgeschlossen wird und eine Antwort über das Netzwerk zurückgesendet wird. Die Latenz ist nicht deterministisch. Die HTTP-429-Ratenbegrenzung erfordert eine Wiederholungslogik. HTTP-402-Zahlungsfehler stoppen die Stapelverarbeitung vollständig. HTTP-500-Fehler in der Infrastruktur von Veryfibringen Ihren Arbeitsablauf zum Erliegen.
Der Dokumentumfang von Veryfiendet an der Grenze des Belegdokuments. Die trainierten Modelle liefern zuverlässig strukturierte Felder für Quittungen, Rechnungen, Schecks, Kontoauszüge, W-2-Formulare und Visitenkarten. Außerhalb dieser Liste – allgemeine Geschäftsdokumente, Verträge, Krankenakten, Versanddokumente, benutzerdefinierte interne Formulare – verschlechtern sich die Ergebnisse oder erfordern ein kostenpflichtiges Training des benutzerdefinierten Modells. Unternehmen, die Veryfifür die Automatisierung der Spesenabrechnung einsetzen, stellen in der Regel innerhalb von 6 bis 12 Monaten fest, dass andere Teams OCR für Dokumente benötigen, für die Veryfinicht ausgelegt ist.
Das proprietäre JSON-Schema von Veryfikoppelt alle Extraktionslogik an einen einzigen Anbieter. Jede Codezeile, die response.Vendor?.Name, response.BankAccount?.RoutingNumber oder response.LineItems liest, ist Code, der nur mit Veryfifunktioniert. Ein Anbieterwechsel – oder der Umstieg auf lokale OCR – bedeutet, die gesamte Extraktionslogik von Grund auf neu zu schreiben.
Das grundsätzliche Problem
// Veryfi: financial data leaves your infrastructure on every call
var client = new VeryfiClient(clientId, clientSecret, username, apiKey); // 4 secrets
var bytes = File.ReadAllBytes("invoice-with-routing-number.pdf");
var response = await client.ProcessDocumentAsync(bytes); // bank details transmitted
var routingNumber = response.BankAccount?.RoutingNumber; // arrived via Veryficloud
// IronOCR: routing numbers never leave your server
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; // 1 key
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf("invoice-with-routing-number.pdf"); // processed locally
var result = ocr.Read(input);
var routingNumber = Regex.Match(result.Text, @"Routing\s*#?\s*:?\s*(\d{9})").Groups[1].Value;
##IronOCR vs. Veryfi: Funktionsvergleich
Die folgende Tabelle stellt die Funktionen beider Produkte gegenüber, um die technische Bewertung zu unterstützen.
| Feature | Veryfi | IronOCR |
|---|---|---|
| Verarbeitungsort | VeryfiCloud-Server | Ihre Infrastruktur |
| Bereitstellungsmodell | Nur Cloud-API | On-Premise, Docker, Azure, AWS, Linux |
| Offline-Unterstützung | Nein | Ja |
| Internet erforderlich | Ja (jedes Dokument) | Nein |
| Daten verlassen die Infrastruktur | Ja (bei jedem Anruf) | Niemals |
| HIPAA-konform ohne BAA | Nein | Ja |
| Unterstützung für luftgesicherte Umgebungen | Nicht möglich | Vollständig unterstützt |
| Preismodell | Pro Dokument (0,05–0,30 $) | Unbefristete Lizenz ($999–2.999 $) |
| Erforderliche Qualifikationen | 4 (clientId, clientSecret, benutzername, apiKey) | 1 Lizenzschlüssel |
| Synchrone API | Nein (nur asynchr) | Ja |
| Ratenbegrenzung | Ja (HTTP 429) | None |
| Dokumentumfang | Quittungen, Rechnungen, Schecks, Kontoauszüge, W-2-Formulare, Visitenkarten | Jeder Dokumenttyp |
| Benutzerdefinierte Dokumenttypen | Schulung zum bezahlten Modell erforderlich | Beliebiges Layout mittels Regex/Musterextraktion |
| PDF-Eingabe | Ja (Byte-Upload) | Ja (einheimisch, lokal) |
| Durchsuchbare PDF-Ausgabe | Nein | Ja (result.SaveAsSearchablePdf()) |
| Regionsbasierte OCR | Nein | Ja (CropRectangle) |
| Barcode-Lesung | Nein | Ja (derselbe OCR-Durchlauf) |
| Strukturierter Zugriff auf Ergebnisse | Vorverarbeitete JSON-Felder | Seiten, Absätze, Zeilen, Wörter mit Koordinaten |
| Konfidenzbewertung | Pro Feld (proprietär) | Pro-Wort und insgesamt (result.Confidence) |
| Unterstützung für mehr als 125 Sprachen | Beschränkt | Ja (NuGet-Sprachpakete) |
| Thread-sichere parallele Verarbeitung | Es gelten HTTP-Parallelitätsbeschränkungen | Vollständig (ein IronTesseract pro Thread) |
| Unit-Tests ohne Mocks | Erfordert HTTP-Mocking | Direkte lokale Tests |
Schnellstart: Migration von Veryfizu IronOCR
Schritt 1: Ersetzen des NuGet-Pakets
Entfernen Sie das VeryfiSDK:
dotnet remove package Veryfi
Installieren Sie IronOCR über NuGet :
Schritt 2: Namespaces aktualisieren
Ersetzen Sie Veryfi-Namespaces durch den IronOCR-Namespace:
// Before (Veryfi)
using Veryfi;
using Veryfi.Models;
// After (IronOCR)
using IronOcr;
using System.Text.RegularExpressions;
Schritt 3: Lizenz initialisieren
Fügen Sie diese Zeile einmal beim Start der Anwendung ein, vor jedem OCR-Aufruf:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"Beispiele für die Code-Migration
Ersatz für den Dokumentenverarbeitungs-Client
Veryfi-Dienste basieren auf Konstruktorinjektion von VeryfiClient. Der Konstruktor mit vier Anmeldedaten ist ein naheliegender Ansatz für die Abhängigkeitsinjektion, erzeugt jedoch vier Geheimnisse, die verwaltet und rotiert werden müssen. Durch den Austausch gegen IronOCR werden die Anmeldedaten in einem einzigen Lizenzschlüssel zusammengefasst und die Instanziierung der Verarbeitungs-Engine in die Service-Klasse selbst verlagert.
Ansatz von Veryfi:
using Veryfi;
using Microsoft.Extensions.Configuration;
public class ExpenseDocumentService
{
private readonly VeryfiClient _client;
// Four credentials injected — four secrets to manage, store, rotate
public ExpenseDocumentService(IConfiguration config)
{
_client = new VeryfiClient(
config["Veryfi:ClientId"], // secret 1
config["Veryfi:ClientSecret"], // secret 2
config["Veryfi:Username"], // secret 3
config["Veryfi:ApiKey"] // secret 4
);
}
public async Task<string> GetVendorNameAsync(string documentPath)
{
var bytes = File.ReadAllBytes(documentPath);
// Document uploaded to Veryfion this call
var response = await _client.ProcessDocumentAsync(bytes);
return response.Vendor?.Name;
}
public async Task<decimal?> GetTotalAsync(string documentPath)
{
var bytes = File.ReadAllBytes(documentPath);
var response = await _client.ProcessDocumentAsync(bytes);
return response.Total;
}
}
IronOCR Ansatz:
using IronOcr;
using System.Text.RegularExpressions;
public class ExpenseDocumentService
{
private readonly IronTesseract _ocr;
// One license key — set once at startup, not per-instance
public ExpenseDocumentService()
{
_ocr = new IronTesseract();
}
public string GetVendorName(string documentPath)
{
// All processing local — document bytes never leave this server
var result = _ocr.Read(documentPath);
// Vendor is typically the first non-whitespace line on a receipt
return result.Pages[0].Paragraphs
.OrderBy(p => p.Y)
.Select(p => p.Text.Trim())
.FirstOrDefault(t => t.Length > 3);
}
public decimal? GetTotal(string documentPath)
{
var result = _ocr.Read(documentPath);
var match = Regex.Match(result.Text,
@"(?:Total|Grand Total|Amount Due):?\s*\$?\s*([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
return match.Success
? decimal.Parse(match.Groups[1].Value.Replace(",", ""))
: (decimal?)null;
}
}
Die Änderung des Konstruktors beseitigt vier Konfigurationseinträge aus jeder Umgebung: appsettings.json, Docker-Geheimnisse, Azure-Schlüsselverweise und CI/CD-Pipeline-Variablen. Die IronTesseract-Instanz ist über mehrere Aufrufe im selben Thread wiederverwendbar. Siehe die IronTesseract-Einrichtungsanleitung für Singleton-Registrierungsmuster in .NET Core-Dependency-Injection-Containern.
Extraktion von Feldern aus Belegen mit regionenbasierter OCR
Veryfi extrahiert Belegfelder, indem es seine trainierten ML-Modelle auf das gesamte Dokumentbild anwendet und eine vorstrukturierte JSON-Antwort zurückgibt. Das Äquivalent von IronOCR ist ein regionsbasiertes OCR mit CropRectangle, das auf spezifische Zonen des Empfangsbildes zielt – Kopfzeile für Anbieter, Fußzeile für Summen – anstatt einen Vollseiten-Durchgang zu laufen und die Ausgabe nach Mustern zu durchsuchen. Dies ist bei bekannten Layouts schneller und genauer, wenn der relevante Bereich klar definiert ist.
Ansatz von Veryfi:
using Veryfi;
public class ReceiptFieldExtractor
{
private readonly VeryfiClient _client;
public ReceiptFieldExtractor(VeryfiClient client)
{
_client = client;
}
public async Task<(string Vendor, decimal? Total, decimal? Tax)>
ExtractReceiptFieldsAsync(string imagePath)
{
var bytes = File.ReadAllBytes(imagePath);
// Full document uploaded — Veryfi's ML returns structured fields
var response = await _client.ProcessDocumentAsync(bytes);
return (
Vendor: response.Vendor?.Name,
Total: response.Total,
Tax: response.Tax
);
}
}
IronOCR Ansatz:
using IronOcr;
using System.Text.RegularExpressions;
public class ReceiptFieldExtractor
{
private readonly IronTesseract _ocr = new IronTesseract();
public (string Vendor, decimal? Total, decimal? Tax)
ExtractReceiptFields(string imagePath)
{
// Region 1: Header zone — vendor name typically in top 15% of receipt
var headerRegion = new CropRectangle(0, 0, 800, 150);
using var headerInput = new OcrInput();
headerInput.LoadImage(imagePath, headerRegion);
headerInput.Deskew();
var headerResult = _ocr.Read(headerInput);
// Region 2: Footer zone — totals typically in bottom 20% of receipt
var footerRegion = new CropRectangle(0, 650, 800, 200);
using var footerInput = new OcrInput();
footerInput.LoadImage(imagePath, footerRegion);
footerInput.DeNoise();
var footerResult = _ocr.Read(footerInput);
var vendor = headerResult.Pages[0].Paragraphs
.OrderBy(p => p.Y)
.Select(p => p.Text.Trim())
.FirstOrDefault(t => t.Length > 3);
var footerText = footerResult.Text;
var totalMatch = Regex.Match(footerText,
@"(?:Total|Grand Total):?\s*\$?\s*([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
var taxMatch = Regex.Match(footerText,
@"(?:Tax|Sales Tax|VAT):?\s*\$?\s*([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
return (
Vendor: vendor,
Total: totalMatch.Success
? decimal.Parse(totalMatch.Groups[1].Value.Replace(",", ""))
: (decimal?)null,
Tax: taxMatch.Success
? decimal.Parse(taxMatch.Groups[1].Value.Replace(",", ""))
: (decimal?)null
);
}
}
CropRectangle nimmt (x, y, width, height) in Pixeln. Die Verarbeitung nur der Kopf- und Fußzeilenbereiche ist schneller als ein vollständiges Einlesen der Seite und vermeidet falsche Übereinstimmungen mit Einzelpostenbeträgen im Hauptteil des Belegs. Der Leitfaden zur regionenbasierten OCR behandelt Koordinatenmessstrategien für Dokumente variabler Größe, und das Beispiel zum Zuschneiden von Regionen zeigt das vollständige Muster.
Kostenkategorisierung mit strukturierten Absatzdaten
Veryfi gibt response.LineItems als vorstrukturiertes Array von Objekten mit bereits analysierten Description, Quantity, UnitPrice und Total zurück.IronOCR bietet das Äquivalent durch result.Pages[0].Paragraphs und result.Lines, die jeden Textblock mit seinen X/Y-Koordinaten offenlegen. Die Logik zur Kategorisierung von Ausgaben – also die Entscheidung, ob es sich bei einem Posten um eine Mahlzeit, eine Reise, Material oder eine Softwaregebühr handelt – funktioniert in beiden Fällen auf der Grundlage desselben Textes. Der Unterschied besteht darin, dass Sie bei IronOCR die Kategorisierungslogik selbst besitzen, anpassen und erweitern können, ohne einen kostenpflichtigen ML-Umschulungszyklus durchlaufen zu müssen.
Ansatz von Veryfi:
using Veryfi;
public class ExpenseCategorizer
{
private readonly VeryfiClient _client;
public ExpenseCategorizer(VeryfiClient client)
{
_client = client;
}
public async Task<Dictionary<string, decimal>> CategorizeExpensesAsync(string receiptPath)
{
var bytes = File.ReadAllBytes(receiptPath);
var response = await _client.ProcessDocumentAsync(bytes);
var categories = new Dictionary<string, decimal>();
// Line items arrive pre-parsed from Veryfi's ML pipeline
foreach (var item in response.LineItems ?? Enumerable.Empty<dynamic>())
{
var category = response.Category ?? "Uncategorized";
var amount = (decimal)(item.Total ?? 0m);
if (!categories.ContainsKey(category))
categories[category] = 0m;
categories[category] += amount;
}
return categories;
}
}
IronOCR Ansatz:
using IronOcr;
using System.Text.RegularExpressions;
public class ExpenseCategorizer
{
private readonly IronTesseract _ocr = new IronTesseract();
// Keyword-based categorization — tune these for your expense policy
private static readonly Dictionary<string, string[]> CategoryKeywords = new()
{
["Meals & Entertainment"] = new[] { "restaurant", "cafe", "coffee", "lunch", "dinner", "food", "bar" },
["Travel"] = new[] { "airline", "hotel", "uber", "lyft", "taxi", "parking", "gas", "fuel" },
["Office Supplies"] = new[] { "staples", "office depot", "paper", "ink", "toner", "supplies" },
["Software & Subscriptions"] = new[] { "adobe", "microsoft", "github", "aws", "azure", "slack" }
};
public Dictionary<string, decimal> CategorizeExpenses(string receiptPath)
{
var result = _ocr.Read(receiptPath);
// Use paragraph coordinates to isolate line items
// Line items typically appear in the middle vertical band of the receipt
var lineItemParagraphs = result.Pages[0].Paragraphs
.Where(p => p.Y > 150 && p.Y < 650) // skip header/footer regions
.OrderBy(p => p.Y)
.ToList();
var categories = new Dictionary<string, decimal>();
var pricePattern = new Regex(@"\$?([\d,]+\.\d{2})$");
var vendorText = result.Text.ToLower();
// Determine top-level category from vendor name
var topCategory = "Uncategorized";
foreach (var (cat, keywords) in CategoryKeywords)
{
if (keywords.Any(kw => vendorText.Contains(kw)))
{
topCategory = cat;
break;
}
}
// Extract individual line item amounts
foreach (var para in lineItemParagraphs)
{
var priceMatch = pricePattern.Match(para.Text.Trim());
if (!priceMatch.Success)
continue;
if (!decimal.TryParse(priceMatch.Groups[1].Value.Replace(",", ""), out var amount))
continue;
// Classify individual items where keywords appear in the description
var itemCategory = topCategory;
var descriptionText = para.Text.ToLower();
foreach (var (cat, keywords) in CategoryKeywords)
{
if (keywords.Any(kw => descriptionText.Contains(kw)))
{
itemCategory = cat;
break;
}
}
if (!categories.ContainsKey(itemCategory))
categories[itemCategory] = 0m;
categories[itemCategory] += amount;
}
return categories;
}
}
Die Paragraphs-Sammlung liefert die Y-Koordinate jedes Textblocks, was es einfach macht, die vertikale Zone zu isolieren, in der Positionen auf einem Standard-Empfangslayout erscheinen. Der Leitfaden für strukturierten Datenzugriff erklärt die vollständige Hierarchie von Pages, Paragraphs, Lines, Words und Characters mit ihren Koordinateneigenschaften. Für Belege mit schlechter Scanqualität – zerknittertes Papier, kontrastarmer Thermodruck – behandelt der Leitfaden zur Bildqualitätskorrektur Vorverarbeitungsfilter, die die Genauigkeit verbessern, bevor die Kategorisierungslogik ausgeführt wird.
Webhook-Eliminierung und synchrone Batch-Ersetzung
Bei hohen Dokumentenvolumina empfiehlt Veryfieine Webhook-basierte Benachrichtigung anstelle von Polling. Das Muster erfordert einen öffentlich zugänglichen HTTPS-Endpunkt, einen Webhook-Schlüssel zur Signaturüberprüfung, eine Warteschlange zur Speicherung der Ergebnisse bis zum Auslösen des Webhooks sowie eine Wiederholungslogik für fehlgeschlagene Übermittlungen. Dies ist eine wichtige Infrastruktur für eine Lösung, die letztlich darauf abzielt, die Tatsache zu umgehen, dass Cloud-OCR im Vergleich zur lokalen Verarbeitung langsam ist.IronOCR verarbeitet synchron. Es gibt keine Async-Lücke, die mit einem Webhook überbrückt werden muss.
Ansatz von Veryfi:
using Veryfi;
using Microsoft.AspNetCore.Mvc;
// Veryfiwebhook receiver — required for high-volume reliable processing
[ApiController]
[Route("webhooks")]
public class VeryfiWebhookController : ControllerBase
{
private readonly IDocumentResultQueue _queue;
public VeryfiWebhookController(IDocumentResultQueue queue)
{
_queue = queue;
}
[HttpPost("veryfi")]
public IActionResult ReceiveWebhook([FromBody] VeryfiWebhookPayload payload,
[FromHeader(Name = "X-Veryfi-Token")] string token)
{
// Validate webhook signature — prevents spoofed payloads
if (!IsValidSignature(token, payload))
return Unauthorized();
// Enqueue result for async downstream consumption
_queue.Enqueue(new DocumentResult
{
DocumentId = payload.Id,
Vendor = payload.Data?.Vendor?.Name,
Total = payload.Data?.Total
});
return Ok();
}
private bool IsValidSignature(string token, VeryfiWebhookPayload payload) =>
// HMAC validation against webhook secret — infrastructure requirement
token == ComputeHmac(payload, Environment.GetEnvironmentVariable("VERYFI_WEBHOOK_SECRET"));
}
// Document batch submission — fire and forget, results arrive via webhook
public class VeryfiDocumentBatchSubmitter
{
private readonly VeryfiClient _client;
public async Task SubmitBatchAsync(string[] documentPaths)
{
foreach (var path in documentPaths)
{
var bytes = File.ReadAllBytes(path);
// Submit — result arrives asynchronously via webhook, not here
await _client.ProcessDocumentAsync(bytes);
}
}
}
IronOCR Ansatz:
using IronOcr;
using System.Text.RegularExpressions;
using System.Collections.Concurrent;
//Neinwebhook controller needed — results are synchronous and local
public class DocumentBatchProcessor
{
// IronTesseract is thread-safe when one instance is created per thread
public List<DocumentResult> ProcessBatch(string[] documentPaths)
{
var results = new ConcurrentBag<DocumentResult>();
Parallel.ForEach(documentPaths, documentPath =>
{
// One IronTesseract per thread — thread-safe pattern
var ocr = new IronTesseract();
var result = ocr.Read(documentPath);
results.Add(new DocumentResult
{
FilePath = documentPath,
Vendor = ExtractVendor(result),
Total = ExtractTotal(result.Text),
Confidence = result.Confidence,
// Result is available immediately — no queue, no webhook
ProcessedAt = DateTime.UtcNow
});
});
return results.OrderBy(r => r.FilePath).ToList();
}
private string ExtractVendor(OcrResult result)
{
// Vendor: first substantive paragraph ordered by vertical position
return result.Pages[0].Paragraphs
.OrderBy(p => p.Y)
.Select(p => p.Text.Trim())
.FirstOrDefault(t => !string.IsNullOrWhiteSpace(t) && t.Length > 3);
}
private decimal? ExtractTotal(string text)
{
var match = Regex.Match(text,
@"(?:Total|Grand Total|Amount Due):?\s*\$?\s*([\d,]+\.\d{2})",
RegexOptions.IgnoreCase);
return match.Success
? decimal.Parse(match.Groups[1].Value.Replace(",", ""))
: (decimal?)null;
}
}
public class DocumentResult
{
public string FilePath { get; set; }
public string Vendor { get; set; }
public decimal? Total { get; set; }
public double Confidence { get; set; }
public DateTime ProcessedAt { get; set; }
}
Durch das Entfernen der Webhook-Schicht entfallen der HTTPS-Endpunkt, die Anforderung zur Rotation des Webhook-Geheimnisses, die Ergebniswarteschlange, die HMAC-Validierungslogik und die Konfiguration für Wiederholungsversuche. Die gesamte nachgelagerte Infrastruktur existiert nur, weil die Ergebnisse von Veryfiasynchron von einem Remote-Server eintreffen. Mit IronOCR ersetzt Parallel.ForEach alles. Das Multithreading-Beispiel zeigt das pro-Thread IronTesseract-Muster im Detail, und der asynchrone OCR-Leitfaden behandelt Task.Run-Integration für UI-Reaktionsfähigkeit. Der Leitfaden zur Geschwindigkeitsoptimierung behandelt die Instanzkonfiguration für maximalen Durchsatz bei Batch-Workloads.
VeryfiAPI zu IronOCR Mapping-Referenz
| Veryfi | IronOCR-Äquivalent |
|---|---|
new VeryfiClient(clientId, clientSecret, username, apiKey) | new IronTesseract() + IronOcr.License.LicenseKey = "key" |
_client.ProcessDocumentAsync(bytes) | ocr.Read(filePath) oder ocr.Read(ocrInput) |
_client.ProcessDocumentAsync(bytes, categories: new[] { "invoices" }) | input.LoadPdf(path); ocr.Read(input) |
_client.ProcessDocumentAsync(bytes, categories: new[] { "bank_statements" }) | input.LoadPdf(path); ocr.Read(input) |
response.Vendor?.Name | Erster Absatz geordnet nach p.Y von result.Pages[0].Paragraphs |
response.Total | Regex.Match(result.Text, @"Total:?\s*\$?([\d,]+\.\d{2})") |
response.Tax | Regex.Match(result.Text, @"Tax:?\s*\$?([\d,]+\.\d{2})") |
response.Date | Regex.Match(result.Text, @"\d{1,2}/\d{1,2}/\d{4}") |
response.LineItems | result.Pages[0].Paragraphs gefiltert nach Y-Koordinatenbereich |
response.InvoiceNumber | Regex.Match(result.Text, @"Invoice\s*#?\s*:?\s*(\w+[-\w]*)") |
response.BankAccount?.AccountNumber | Regex.Match(result.Text, @"Account\s*#?\s*:?\s*(\d{4,})") |
response.BankAccount?.RoutingNumber | Regex.Match(result.Text, @"Routing\s*#?\s*:?\s*(\d{9})") |
response.ConfidenceScore | result.Confidence (insgesamt) oder word.Confidence (pro Wort) |
response.Payment?.Last4 | Regex.Match(result.Text, @"\*{4}\s*(\d{4})") |
VeryfiApiException (401/402/429/500) | Standardmäßige .NET-Ausnahmen – keine HTTP-Fehlercodes für die lokale Verarbeitung |
| Base64-Kodierung vor dem Upload | Nicht erforderlich — ocr.Read(filePath) akzeptiert Dateipfade direkt |
response.Category | Benutzerdefiniertes Schlüsselwort-Matching gegen result.Text |
| Deserialisierung der Webhook-Nutzdaten | Nicht erforderlich — ocr.Read() returned synchron das Ergebnis |
ProcessDocumentAsync mit Wiederholungen/Ausfallsicherung | Nicht erforderlich – keine Ratenbeschränkungen bei der lokalen Verarbeitung |
Gängige Migrationsprobleme und Lösungen
Problem 1: Fehlende vorverarbeitete Felder
Veryfi: response.Vendor?.Name, response.Total und response.LineItems kommen als strukturierte Felder aus einem vortrainierten ML-Modell. Auf der Client-Seite ist keine Extraktionslogik erforderlich.
Lösung: Schreiben Sie Regex-Muster für jedes Feld, das Ihre Anwendung verwendet. Der Zeitaufwand für die Migration beträgt in der Regel 8–24 Stunden, je nachdem, wie viele unterschiedliche Dokumentlayouts Sie bearbeiten. Für gängige Quittungs- und Rechnungsmuster bieten das OCR-Tutorial für Rechnungen und das Tutorial zum Scannen von Quittungen vollständige Implementierungen von Extraktionsmustern.
// Map each Veryfifield to a Regex extraction
private static readonly Dictionary<string, string> FieldPatterns = new()
{
["InvoiceNumber"] = @"Invoice\s*#?\s*:?\s*(\w+[-\w]*)",
["PurchaseOrder"] = @"(?:PO|P\.O\.|Purchase Order)\s*#?\s*:?\s*(\w+)",
["DueDate"] = @"Due\s*(?:Date)?:?\s*(\d{1,2}/\d{1,2}/\d{4})",
["PaymentTerms"] = @"(?:Terms|Net)\s*:?\s*(\w+\s*\d+)"
};
public string ExtractField(string text, string fieldName)
{
if (!FieldPatterns.TryGetValue(fieldName, out var pattern))
return null;
var match = Regex.Match(text, pattern, RegexOptions.IgnoreCase);
return match.Success ? match.Groups[1].Value.Trim() : null;
}
Problem 2: Asynchrone Methodensignaturen im gesamten Code
Veryfi: ProcessDocumentAsync ist asynchron auf der Veryfi-SDK-Ebene. Teams propagieren typischerweise await durch jede aufrufende Methode bis zum Aufrufstack, was bedeutet, dass Dienstklassen, Controller und Hintergrundjobs alle async Task<t>-Signaturen tragen.
Lösung: IronOCRs Read() ist synchron. Bestehende async-Methodensignaturen können beibehalten werden, indem sie während der Übergangsperiode mit Task.Run umwickelt werden. Dadurch werden umfangreiche Signaturänderungen im gesamten Code vermieden, während die Cloud-Abhängigkeit dennoch beseitigt wird.
// Preserve async signature during transition — no codebase-wide refactor needed
public async Task<string> GetVendorNameAsync(string documentPath)
{
return await Task.Run(() =>
{
var result = _ocr.Read(documentPath);
return result.Pages[0].Paragraphs
.OrderBy(p => p.Y)
.Select(p => p.Text.Trim())
.FirstOrDefault(t => t.Length > 3);
});
}
Problem 3: Über verschiedene Umgebungen verteilte Konfiguration von Anmeldedaten
Veryfi: Vier Anmeldedaten (Veryfi:ClientId, Veryfi:ClientSecret, Veryfi:Username, Veryfi:ApiKey) erscheinen in appsettings.json, Blockumgebungen von Umgebungsvariablen in Docker Compose-Dateien, GitHub Actions-Geheimnissen, Azure-Schlüsselverweisen und CI/CD-Pipeline-Konfigurationen.
Lösung: Suchen und entfernen Sie alle vier Anmeldeinformationen aus jeder Umgebung. Fügen Sie eine einzige IRONOCR_LICENSE_KEY-Umgebungsvariable hinzu. Beim Start laden.
# Find all Veryficredential references
grep -r "Veryfi:ClientId\|Veryfi:ClientSecret\|Veryfi:Username\|Veryfi:ApiKey" \
--include="*.json" --include="*.yml" --include="*.yaml" --include="*.env" .
// Load from environment at startup
IronOcr.License.LicenseKey = Environment.GetEnvironmentVariable("IRONOCR_LICENSE_KEY")
?? throw new InvalidOperationException("IRONOCR_LICENSE_KEY not set");
Problem 4: Probleme mit der Scanqualität, die zuvor nicht sichtbar waren
Veryfi: Die Cloud-Verarbeitung umfasst die serverseitige Bildverbesserung vor der Ausführung von ML-Inferenz. Scans von Belegen in schlechter Qualität – zerknittertes Papier, verblasste Thermodrucke, schräge Handyfotos – wurden vor der Feldextraktion automatisch korrigiert.
Lösung: Wenden Sie die Vorverarbeitungs-Pipeline von IronOCR explizit an. Deskew(), DeNoise() und Contrast() decken die Mehrheit der realen Scanqualitätsprobleme von Quittungen ab.
using var input = new OcrInput();
input.LoadImage("receipt-phone-photo.jpg");
input.Deskew(); // correct rotation from angled phone capture
input.DeNoise(); // remove compression artifacts
input.Contrast(); // improve faded thermal print
input.Sharpen(); // recover edge detail
var result = _ocr.Read(input);
Der Leitfaden zur Bildqualitätskorrektur und das Tutorial zu Bildfiltern behandeln, welche Filter bei bestimmten Arten von Scan-Qualitätsverlusten anzuwenden sind.
Thema 5: Durchsatz bei der Verarbeitung großer Datenmengen
Veryfi: Ratenbegrenzungen drosseln die Geschwindigkeit der Dokumentenübermittlung. HTTP-429-Antworten erfordern eine Exponential-Backoff-Logik. Der Durchsatz wird durch das von Veryfifestgelegte Ratenlimit pro Plan begrenzt, nicht durch Ihre Hardware.
**Lösung:**IronOCR ist nur durch die Anzahl der CPU-Kerne begrenzt. Verwenden Sie Parallel.ForEach mit einer IronTesseract-Instanz pro Thread. Auf einem 8-Kern-Server skaliert der Durchsatz in etwa linear mit der Anzahl der Kerne.
// One IronTesseract per thread — do not share instances across threads
Parallel.ForEach(
documentPaths,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
path =>
{
var ocr = new IronTesseract();
var result = ocr.Read(path);
SaveResult(path, result.Text, result.Confidence);
});
Problem 6: Proprietäres JSON-Schema, das an Veryfigebunden ist
Veryfi: Der gesamte Extraktionscode liest aus dem Antwortschema von Veryfi: response.Vendor?.Name, response.LineItems, response.BankAccount?.RoutingNumber. Dieser Code funktioniert nur mit dem SDK von Veryfi. Jede Änderung von Feldnamen in einem Veryfi-API-Update führt zu Fehlern im Anwendungscode.
Lösung: IronOCR-Extraktion verwendet die Standard-.NET System.Text.RegularExpressions.Regex gegen einfachen Text. Die Muster sind portabel, ohne Mocking eines SDK testbar und unter Ihrer Kontrolle. Unit-Tests laufen ohne Netzwerkverbindung.
// Extraction logic that is fully portable and unit-testable
[Fact]
public void ExtractsRoutingNumberFromInvoiceText()
{
const string sampleText = "Routing Number: 021000021\nAccount: 1234567890";
var match = Regex.Match(sampleText, @"Routing\s*(?:Number)?:?\s*(\d{9})",
RegexOptions.IgnoreCase);
Assert.True(match.Success);
Assert.Equal("021000021", match.Groups[1].Value);
}
Veryfi-Migrationscheckliste
Vor der Migration
Überprüfen Sie den Code, um alle Verwendungen von Veryfizu erfassen, bevor Sie Änderungen am Code vornehmen:
# Find all Veryfiusing statements
grep -rn "using Veryfi" --include="*.cs" .
# Find all VeryfiClient instantiations
grep -rn "VeryfiClient\|ProcessDocumentAsync" --include="*.cs" .
# Find all Veryfiresponse field accesses
grep -rn "response\.Vendor\|response\.Total\|response\.LineItems\|response\.BankAccount" --include="*.cs" .
# Find all credential configuration references
grep -r "Veryfi:ClientId\|Veryfi:ClientSecret\|Veryfi:Username\|Veryfi:ApiKey" \
--include="*.json" --include="*.yml" --include="*.yaml" --include="*.env" .
# Find all webhook-related code
grep -rn "VeryfiWebhook\|X-Veryfi-Token\|webhook" --include="*.cs" .
Nehmen Sie die Gesamtanzahl der ProcessDocumentAsync-Aufrufstellen auf, die Liste der Antwortfelder, die pro Aufrufstelle zugegriffen werden, und die Liste der Umgebungen mit Veryfi-Anmeldedaten.
Code-Migration
- Entfernen Sie das
VeryfiNuGet-Paket aus allen Projekten in der Lösung. - Installieren Sie das
IronOcrNuGet-Paket in allen Projekten, die zuvor aufVeryfiverwiesen haben. - Fügen Sie
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";zum Anwendungsstart hinzu (vor jedem OCR-Aufruf). - Ersetzen Sie alle
using Veryfi;undusing Veryfi.Models;Aussagen durchusing IronOcr;. - Ersetzen Sie
VeryfiClientKonstruktorinjektion durchIronTesseractFeldinitialisierung. - Entfernen Sie alle vier Veryfi-Anmeldedateneinträge aus jedem
appsettings.json,appsettings.*.jsonund Geheimniskonfigurationsdatei. - Konvertieren Sie
ProcessDocumentAsync(bytes)-Aufrufe zuocr.Read(filePath)oderocr.Read(ocrInput). - Ersetzen Sie
response.Vendor?.Name-Zugriffe durch absatzgeordnete Textextraktion ausresult.Pages[0].Paragraphs. - Ersetzen Sie
response.Total,response.Tax,response.InvoiceNumberund andere strukturierte Feldzugriffe durch Regex-Muster gegenresult.Text. - Ersetzen Sie
response.LineItemsIteration mit Y-Koordinaten-gefilterterresult.Pages[0].ParagraphsIteration. - Löschen Sie die Webhook-Controller-Klassen und entfernen Sie die Webhook-Endpunkt-Registrierungen.
- Entfernen Sie die geheimen Webhook-Umgebungsvariablen aus allen Umgebungen.
- Fügen Sie
OcrInputmit Vorverarbeitung (Deskew(),DeNoise(),Contrast()) für gescannte Bildinputs hinzu. - Ersetzen Sie einsträngige sequentielle Schleifen mit
Parallel.ForEachmit einemIronTesseractpro Thread. - Fügen Sie
IRONOCR_LICENSE_KEYzu allen Umgebungsvariablenkonfigurationen und CI/CD-Geheimnisspeichern hinzu.
Nach der Migration
- Stellen Sie sicher, dass nach der Migrationsbereitstellung keine Veryfi-Netzwerkaufrufe in den HTTP-Traffic-Protokollen erscheinen.
- Überprüfen Sie anhand einer Stichprobe von 20–50 Belegen, ob die extrahierten Anbieternamen mit den erwarteten Werten übereinstimmen.
- Überprüfen Sie, ob die extrahierten Summen innerhalb einer Toleranz von 0,01 $ mit den erwarteten Werten für denselben Datensatz übereinstimmen.
- Überprüfen Sie, ob die Extraktion der Rechnungsnummern für jedes Rechnungsformat im Dokumentenkorpus erfolgreich ist.
- Testen Sie den Durchsatz der Stapelverarbeitung im Vergleich zum Veryfi-Basisdurchsatz, um die Aufhebung der Ratenbegrenzung zu bestätigen.
- Führen Sie die vollständige Suite der Tests ohne Netzwerkverbindung aus, um die vollständige Unabhängigkeit von der Cloud zu bestätigen.
- Bestätigen Sie, dass
result.Confidence-Ergebnisse über 80 % für saubere Dokumentenscans liegen; Ein Wert unter 80 % deutet darauf hin, dass ein Vorverarbeitungsschritt hinzugefügt werden sollte. - Stellen Sie sicher, dass alle vier Veryfi-Anmeldedaten aus jeder Umgebung (Entwicklung, Staging, Produktion) entfernt wurden.
- Stellen Sie sicher, dass Webhook-Endpunkte den Status 404 zurückgeben oder aus der Routing-Tabelle entfernt wurden.
- Testen Sie das Verhalten bei Scans von Belegen in schlechter Qualität (zerknittert, verblasst, schräg) bei aktivierter Vorverarbeitungs-Pipeline.
Wichtigste Vorteile der Migration zu IronOCR
Lokal verarbeitete Finanzdokumente sind Dokumente, die nicht an Dritte weitergegeben werden können. Nach der Migration werden Bankkontonummern, die aus Rechnungen extrahiert wurden, Bankleitzahlen, die aus Schecks ausgelesen wurden, sowie Transaktionsverläufe, die aus Kontoauszügen gelesen wurden, vollständig auf Ihrer Hardware verarbeitet. Weder Sicherheitsvorfälle bei Dritten noch der Datenzugriff durch Unterauftragsverarbeiter oder eine Verletzung der Veryfi-Infrastruktur können Dokumente offenlegen, die Ihre Server nie verlassen haben.
Die Kosten pro Dokument sinken am Tag der Migrationsbereitstellung auf null. Bei 50.000 Dokumenten pro Monat entfällt der monatliche Veryfi-Posten in Höhe von 5.000 bis 15.000 US-Dollar. The once-only IronOCR Professional License worth 2.999 US dollars amortizes in the first week of the first month. Bei höheren Volumina summieren sich die Einsparungen jedes Jahr, ohne dass Mengenrabatte ausgehandelt oder Verträge verlängert werden müssen.
Der Verarbeitungsdurchsatz skaliert mit der Hardware, nicht mit den Ratenbeschränkungen eines Anbieters. HTTP-429-Antworten, Durchsatzbegrenzungen auf Planebene und saisonale Überziehungsgebühren sind architektonische Artefakte von Cloud-APIs. Mit IronOCR erhöht das Hinzufügen von CPU-Kernen den Durchsatz proportional. Ein Stapel von 10.000 Belegen wird nach Ihrem Zeitplan verarbeitet, nicht nach dem Ratenlimit-Zeitplan von Veryfi.
Jeder Dokumenttyp wird mit derselben API verarbeitet. Das Unternehmen benötigt kein zweites OCR-Tool mehr, wenn die Personalabteilung die Verarbeitung von Onboarding-Formularen anfordert, die Rechtsabteilung die Extraktion von Vertragstexten benötigt oder der Betrieb Daten aus Versanddokumenten benötigt. ocr.Read() verarbeitet alle. Das Tutorial zum Lesen von Text aus Bildern und die speziellen Dokumentenhandbücher decken die gesamte Bandbreite der von IronOCR verarbeiteten Dokumentformate ab.
Die Extraktionslogik wird zu einem integralen Bestandteil des Code-Basis. Regex-Muster befinden sich in der Quellcodeverwaltung, können in Pull-Anfragen überprüft, in Unit-Tests ohne Mocking eines SDK getestet und auf Basis von Produktions-Feedback angepasst werden. Wenn das vortrainierte Modell von Veryfieinen falschen Anbieternamen zurückgibt, gibt es nichts anzupassen. Wenn das Extraktionsmuster von IronOCR einen falschen Anbieternamen zurückgibt, besteht die Korrektur aus einer einzeiligen Änderung des regulären Ausdrucks mit einem Unit-Test. Die Lizenzierungsseite von IronOCR behandelt verschiedene Tarifoptionen, darunter das SaaS-Abonnement für Teams, die eine jährliche Abrechnung einem einmaligen Kauf vorziehen.
**Der Platzbedarf für die Bereitstellung reduziert sich auf ein einziges NuGet-Paket, das überall ausgeführt werden kann.**IronOCR wird als ein einziges Paket installiert, ohne externe Abhängigkeiten, ohne Verwaltung nativer Binärdateien und ohne Konfiguration des Tessdata-Ordners. Die gleiche Paketreferenz wird unter Windows, Linux, macOS, Docker, Azure App Service und AWS Lambda ohne plattformabhängigen Code aufgelöst. Siehe den Docker-Bereitstellungsleitfaden und den Linux-Bereitstellungsleitfaden für containerisierte Umgebungen, in denen die Anforderungen von Veryfian den Netzwerkausgang ein Hindernis für die Bereitstellung darstellen.
