Tochemey / NetCore8583

NetCore8583 is a library that helps parse/read and generate ISO 8583 messages for .NET Core
MIT License
30 stars 19 forks source link
banking csharp dotnet-core financial-data iso8583 netcore

NetCore8583

Stability: Maintenance

NetCore8583 is considered feature complete and mature. No future feature development is planned, though bugs and security issues are fixed.

GitHub Workflow Status (branch) License: MIT Nuget

Introduction

NetCore8583 is a dotnet core implementation of the ISO 8583 protocol.

NetCore8583 is a library that helps parse/read and generate ISO 8583 messages. It does not handle sending or reading them over a network connection, but it does parse the data you have read and can generate the data you need to write over a network connection.

ISO 8583 overview

ISO8583 is a message format used for credit card transactions, banking and other commercial interaction between different systems. It has an ASCII variant and a binary one, and it is somewhat convoluted and difficult to implement.

The main format of the ISO8583 is something like this:

ISO header (optional) Message Type primary bitmap secondary bitmap (optional) data fields

The ISO header is a string containing some code that can vary according to the message type.

The message type is a number expressed as 4 hex digits (or 2 bytes when using binary format).

The bitmap is 64 bits long and it is encoded as 16 hex characters or as 8 bytes when using binary format. Every bit that is set in the bitmap indicates that the corresponding field is present. If the first bit is set, then field 1 is present, and so on.

The fields in the message are numbered from 1 to 64. Field 1 is the secondary bitmap, if present. The secondary bitmap allows for the message to have fields from 65 to 128.

Wikipedia has a very good article on the whole specification.

Usage

The library is available on nuget package. You can get it via:

dotnet add package NetCore8583

How does NetCore8583 work?

NetCore8583 offers a MessageFactory, which once properly configured, can create different message types with some values predefined, and can also parse a byte array to create an ISO message. Messages are represented by IsoMessage objects, which store IsoValue instances for their data fields. You can work with the IsoValues or use the convenience methods of IsoMessage to work directly with the stored values.

MessageFactory and IsoMessage classes

These are the two main classes you need to use to work with ISO8583 messages. An IsoMessage can be encoded into a signed byte array. You can set and get the values for each field in an IsoMessage, and it will adjust itself to use a secondary bitmap if necessary. An IsoMessage has settings to encode itself in binary or ASCII, to use a secondary bitmap even if it's not necessary, and it can have its own ISO header.

However, it can be cumbersome to programmatically create IsoMessages all the time. The MessageFactory is a big aid in creating IsoMessages with predefined values; also, it can set the date and the trace number in each new message.

How to configure the MessageFactory

There are five main things you need to configure in a MessageFactory: ISO headers, message templates, parsing templates, TraceNumberGenerator, and custom field encoders.

Custom Field encoders

Sometimes there are fields that contain several sub-fields or separate pieces of data. NetCore8583 will only parse the field for you, but you still have to parse those pieces of data from the field when you parse a message, and/or encode several pieces of data into a field when creating a message.

NetCore8583 can help with this process, by means of the custom field encoders. To use this feature, first you need to implement the ICustomField interface. You can see how it is done in the following test classes TestParsing.cs and TestIsoMessage.cs using the CustomField48.cs class.

Easy way to configure ISO 8583 messages templates

The easiest way to configure the message templates and parsing templates is by using a XML config file and pass it to the MessageFactory.

XML configuration

The MessageFactory can read a XML file to setup message templates, ISO headers by type and parsing templates, which are the most cumbersome parts to configure programmatically. There are three types of main elements that you need to specify in the config file: header, template, and parse. All these must be contained in a single n8583-config element.

Header

Specify a header element for every type of message that needs an ISO header. Only one per message type:

    <header type="0200">ISO015000050</header>
    <header type="0400">ISO015000050</header>

You can define a header as a reference to another header:

    <header type="0800" ref="0200" />

The header for 0800 messages will be the same as the header for 0200 messages.

Template Element

Each template element defines a message template, with the message type and the fields that the template should include. Every new message of that type that the MessageFactory creates will contain those same values, so this is very useful for defining fixed values, which will be the same in every message. Only one template per type.

    <template type="0200">
        <field num="3" type="NUMERIC" length="6">650000</field>
        <field num="32" type="LLVAR">456</field>
        <field num="35" type="LLVAR">4591700012340000=</field>
        <field num="43" type="ALPHA" length="40">Fixed-width data</field>
        <field num="48" type="LLLVAR">Life, the Universe, and Everything|42</field>
        <field num="49" type="ALPHA" length="3">840</field>
        <field num="60" type="LLLVAR">B456PRO1+000</field>
        <field num="61" type="LLLVAR">This field can have a value up to 999 characters long.</field>
        <field num="100" type="LLVAR">999</field>
        <field num="102" type="LLVAR">ABCD</field>
    </template>   

You can define a template as extending another template, so that it includes all the fields from the referenced template as well as any new fields defined in it, as well as excluding fields from the referenced template:

    <template type="0400" extends="0200">
        <field num="90" type="ALPHA" length="42">Bla bla</field>
        <field num="102" type="exclude" />
    </template>

In the above example, the template for message type 0400 will include all fields defined in the template for message type 0200 except field 102, and will additionally include field 90.

Parse Element

Each parse element defines a parsing template for a message type. It must include all the fields that an incoming message can contain, each field with its type and length (if needed). Only ALPHA and NUMERIC types need to have a length specified. The other types either have a fixed length, or have their length specified as part of the field (LLVAR and LLLVAR).

    <parse type="0210">
        <field num="3" type="NUMERIC" length="6" />
        <field num="4" type="AMOUNT" />
        <field num="7" type="DATE10" />
        <field num="11" type="NUMERIC" length="6" />
        <field num="12" type="TIME" />
        <field num="13" type="DATE4" />
        <field num="15" type="DATE4" />
        <field num="17" type="DATE_EXP" />
        <field num="32" type="LLVAR" />
        <field num="35" type="LLVAR" />
        <field num="37" type="NUMERIC" length="12" />
        <field num="38" type="NUMERIC" length="6" />
        <field num="39" type="NUMERIC" length="2" />
        <field num="41" type="ALPHA" length="16" />
        <field num="43" type="ALPHA" length="40" />
        <field num="48" type="LLLVAR" />
        <field num="49" type="ALPHA" length="3" />
        <field num="60" type="LLLVAR" />
        <field num="61" type="LLLVAR" />
        <field num="70" type="ALPHA" length="3" />
        <field num="100" type="LLVAR" />
        <field num="102" type="LLVAR" />
        <field num="126" type="LLLVAR" />
    </parse>

As with message templates, you can define parsing guides that extend other parsing guides:

    <parse type="0410" extends="0210">
        <field num="90" type="ALPHA" length="42" />
        <field num="102" type="exclude" />
    </parse>

Composite Fields

Another feature is the CompositeField. This is a CustomField that acts as a container for several IsoValues, and it can be configured in the parsing guide of a message type:

    <parse type="0410">
        <field num="125" type="LLLVAR">
            <field num="1" type="ALPHA" length="5" />
            <field num="2" type="LLVAR" />
            <field num="3" type="NUMERIC" length="6" />
            <field num="4" type="ALPHA" length="2" />
        </field>
    </parse>

In the above example, when a message with type 0410 is parsed, the value for field 125 will be a CompositeField and you can obtain the subfields via GetField() or GetObjectValue(). The num attribute of the subfields is ignored.

This means that you can do this via code:

    //Assuming original data for field 125 is "018one  03two123456OK"
    CompositeField f = message.GetObjectValue(125);
    string sub1 = (string)f.GetObjectValue(0); //"one  "
    string sub2 = (string)f.GetObjectValue(1); //"two"
    string sub3 = (string)f.GetObjectValue(2); //"123456"
    string sub4 = (string)f.GetObjectValue(3); //"OK"

You can also create a CompositeField, store several subfields inside it, and store it in any field inside an IsoMessage, specifying the same instance as the CustomField:

    CompositeField f = new CompositeField().AddValue(new IsoValue(IsoType.ALPHA, "one", 5))
    .AddValue(new IsoValue(IsoType.LLVAR, "two"))
    .AddValue(new IsoValue(IsoType.NUMERIC, 123l, 6))
    .AddValue(new IsoValue(IsoType.ALPHA, "OK", 2));
    message.SetValue(125, f, f, IsoType.LLLVAR, 0);

When the message is encoded, field 125 will be "018one 03two000123OK".

Resources