Releases: Tochemey/NetCore8583
v2.5.0
Highlights
This release introduces EMV TLV (Tag-Length-Value) support for chip card data, enabling first-class parsing, building, and integration of BER-TLV encoded data -- commonly carried in ISO 8583 field 55. The implementation follows the EMV v4.3 Specification and ISO/IEC 8825-1 BER encoding rules.
New Features
-
TlvParser-- Parses BER-TLV encoded byte arrays into structuredTlvTagrecords. Handles single-byte tags, multi-byte tags (2-3+ bytes), short-form and long-form lengths, constructed (nested) tags, and inter-TLV padding bytes (0x00,0xFF). -
TlvBuilder-- Fluent API for constructing BER-TLV byte sequences:byte[] data = new TlvBuilder() .AddTag("9F26", cryptogramValue) .AddTag("9F27", cidValue) .Build();
-
TlvTag-- Immutable record type representing a single TLV data object withTag(hex string),Length,Value(byte array), and optionalDescription. SupportsIsConstructeddetection andGetNestedTags()for constructed data objects. -
EmvTags-- Built-inFrozenDictionaryof 38 common EMV tag descriptions sourced from EMV v4.3 Book 3 (Annex A) and ISO/IEC 7816-4, with case-insensitive lookup. Spec version exposed viaEmvTags.SpecVersion. -
TlvField--ICustomBinaryFieldimplementation that allows field 55 (or any field) to be registered as a TLV-aware composite field in both XML and programmatic (MessageFactoryBuilder) configurations. -
IsoMessageTLV extension methods -- Convenience helpers for field 55 access:GetTlvTags()-- retrieve parsed TLV tagsSetTlvTags()-- set TLV tags on the messageGetTlvBytes()-- retrieve raw TLV bytesFindTlvTag(string tag)-- find a specific tag by hex identifier
Improvements
- Expanded test coverage: Added new test classes with comprehensive unit tests covering single-byte tags, multi-byte tags, nested constructed tags, round-trip encode/decode,
TlvFieldintegration,IsoMessageextension methods, andEmvTagsdictionary validation. - MIT license headers Added to all C# source files across the entire solution.
- Documentation: Comprehensive README section covering BER-TLV encoding rules, standalone usage, XML and programmatic configuration, and
IsoMessageextension methods, with a full EMV tag reference table.
Bug Fixes
- Fixed date/time related test failures.
Supported Frameworks
- .NET 8.0
- .NET 9.0
- .NET 10.0
Pull Requests
- test: add tests to validate a bug reported sometime ago by @Tochemey in #45
- feat: ✨ add emv v4.3 field 55 parser support by @Tochemey in #47
Full Changelog: 2.4.0...v2.5.0
2.4.0
🚀 What's Changed
✨ Fluent Message Factory Builder API
- Code-first configuration without XML — a new
MessageFactoryBuilder<T>provides a fluent, type-safe API for constructing fully-configuredMessageFactoryinstances entirely in code. - 🧩 Supports all configuration options previously available only through XML: headers, templates, parse maps, custom fields, composite fields, and all factory properties.
- 🔗 Template and parse-map inheritance via
Extends(), with field-level override and exclusion support. - 🏗️ New builder classes:
MessageFactoryBuilder<T>,TemplateBuilder,ParseMapBuilder, andCompositeFieldBuilder.
var factory = new MessageFactoryBuilder<IsoMessage>()
.WithEncoding(Encoding.UTF8)
.WithHeader(0x0200, "ISO")
.WithTemplate(0x0200, t => t
.Field(3, IsoType.NUMERIC, "000000", 6)
.Field(11, IsoType.NUMERIC, "000001", 6)
.Field(41, IsoType.ALPHA, "TERMINAL", 8))
.WithTemplate(0x0210, t => t
.Extends(0x0200)
.Field(39, IsoType.ALPHA, "00", 2))
.WithParseMap(0x0200, p => p
.Field(3, IsoType.NUMERIC, 6)
.Field(11, IsoType.NUMERIC, 6)
.Field(41, IsoType.ALPHA, 8))
.WithParseMap(0x0210, p => p
.Extends(0x0200)
.Field(39, IsoType.ALPHA, 2))
.Build();📎 PR: #42
⚡ Performance: Zero-Copy Parsing, Span<T>, Bitmap128 & Allocation Reductions
- 🧮
Bitmap128struct backed byUInt128replacesBitArrayfor field-presence tracking — significantly faster bit operations with zero heap allocations. - 🔬
Span<T>andReadOnlySpan<T>used throughout parsing and encoding, enabling zero-copy byte/string conversions and eliminating intermediate array allocations. - 🔄 Zero-copy byte utilities (
Bytesextensions) usingMemoryMarshal.Castfor reinterpreting betweenbyte[]andsbyte[]without copying. - 🧵
Stringxextensions withGetSignedBytes()overloads that encode directly into destination buffers, plusArrayPool<T>pooled variants for hot paths. - 💾
EncodingCacheto avoid repeated encoding lookups. - 📦 Reorganised internal utilities from
NetCore8583.Util→NetCore8583.Extensionsnamespace for clearer separation. - 🔧 All field parsers,
IsoMessage,IsoValue,MessageFactory, and codec classes updated to use the new span-based APIs.
📎 PR: #41
⚠️ Breaking Changes
- The
NetCore8583.Utilnamespace has been reorganised intoNetCore8583.Extensions. If you reference types likeHexCodec,Bcd,Arrays,OsUtil,Enumm,DictionaryExtensions, orParseExceptiondirectly, update yourusingstatements accordingly. - 🗑️ Removed:
ByteUtil,DateUtil,StringUtil,DictionaryExtensions,Enumm, andParseExceptionfromNetCore8583.Util(replaced by equivalents inNetCore8583.Extensions).
Full Changelog: 2.3.0...2.4.0
2.3.0
🚀 What’s Changed
✨ Features
- Add support for .NET 10
Includes test fixes to ensure compatibility and stability.
Thanks to @fernandoareias 🙌
→ #37
🧹 Maintenance
- Upgrade dependencies & sunset legacy frameworks
- Updated project dependencies to their latest compatible versions
- Dropped support for .NET 6 and .NET 7 (now end-of-life / nearing EOL)
→ #39
⚠️ Breaking Changes
- Support for .NET 6 and .NET 7 has been removed.
Please upgrade to a supported .NET version before updating.
👋 New Contributors
- 🎉 @fernandoareias made their first contribution!
Thanks for helping move the project forward 💙
→ #37
Full Changelog: 2.2.2...2.3.0
2.2.2
2.2.1
2.2.0
2.1.0
2.0.0
1.0.3
1.0.2
Noteworthy
- Upgraded to NET 5.0
- Bug fixing in LLLBinParseInfo
- Bug fix: 128th field in referenced template is missing when using extends in template element
- Bug fix: LLLLBIN length calculation when element is more than 1000 bytes
- Configurable radix for integer parsing.
- New behavior for MessageFactory.createResponse(): The new behavior for the createResponse method within the MessageFactory class (while preserving the existing one), in order to be able to create a response with only the fields in the template, overriding the values with the contents of the request only for those fields.