{"id":20465713,"url":"https://github.com/tochemey/netcore8583","last_synced_at":"2025-04-05T05:06:38.901Z","repository":{"id":48083491,"uuid":"138026571","full_name":"Tochemey/NetCore8583","owner":"Tochemey","description":"NetCore8583 is a library that helps parse/read and generate ISO 8583 messages for .NET Core","archived":false,"fork":false,"pushed_at":"2025-02-17T20:57:57.000Z","size":167,"stargazers_count":40,"open_issues_count":0,"forks_count":25,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-29T04:08:15.991Z","etag":null,"topics":["banking","csharp","dotnet-core","financial-data","iso8583","netcore"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Tochemey.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":"contributing.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"code_of_conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"tochemey"}},"created_at":"2018-06-20T11:56:31.000Z","updated_at":"2025-02-20T11:31:49.000Z","dependencies_parsed_at":"2024-04-09T22:49:58.153Z","dependency_job_id":"87e1ec82-75ee-4c39-a511-15a2227638d9","html_url":"https://github.com/Tochemey/NetCore8583","commit_stats":{"total_commits":73,"total_committers":3,"mean_commits":"24.333333333333332","dds":0.0273972602739726,"last_synced_commit":"08d36c0e1bcc14231efe57adab5ec34f70a1faac"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tochemey%2FNetCore8583","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tochemey%2FNetCore8583/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tochemey%2FNetCore8583/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Tochemey%2FNetCore8583/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Tochemey","download_url":"https://codeload.github.com/Tochemey/NetCore8583/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247289427,"owners_count":20914464,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["banking","csharp","dotnet-core","financial-data","iso8583","netcore"],"created_at":"2024-11-15T13:19:32.105Z","updated_at":"2025-04-05T05:06:38.865Z","avatar_url":"https://github.com/Tochemey.png","language":"C#","funding_links":["https://github.com/sponsors/tochemey"],"categories":[],"sub_categories":[],"readme":"# NetCore8583\n\n_NetCore8583 is considered feature complete and mature. \nNo future feature development is planned, though bugs and security issues are fixed._\n\n[![GitHub Workflow Status (branch)](https://img.shields.io/github/actions/workflow/status/Tochemey/NetCore8583/ci.yml?branch=main\u0026style=flat-square)](https://github.com/Tochemey/NetCore8583/blob/main/.github/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT)\n[![Nuget](https://img.shields.io/nuget/v/NetCore8583?style=flat-square)](https://www.nuget.org/packages/NetCore8583/)\n[![NuGet Downloads](https://img.shields.io/nuget/dt/NetCore8583?style=flat-square)](https://www.nuget.org/packages/NetCore8583/)\n[![Stability: Maintenance](https://masterminds.github.io/stability/maintenance.svg)](https://masterminds.github.io/stability/maintenance.html)\n\n## Introduction\n\nNetCore8583 is a dotnet core implementation of the ISO 8583 protocol.\n\nNetCore8583 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.\n\n## ISO 8583 overview\n\nISO8583 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.\n\nThe main format of the ISO8583 is something like this:\n\n|ISO header (optional)|Message Type|primary bitmap|secondary bitmap (optional)|data fields|\n|---------------------|------------|--------------|---------------------------|-----------|\n\nThe ISO header is a string containing some code that can vary according to the message type.\n\nThe message type is a number expressed as 4 hex digits (or 2 bytes when using binary format).\n\nThe 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.\n\nThe 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.\n\nWikipedia has [a very good article](http://en.wikipedia.org/wiki/ISO_8583) on the whole specification.\n\n## Usage\n\nThe library is available on nuget package. You can get it via:\n\n```bash\ndotnet add package NetCore8583\n```\n\n## Support\n\nOne can use the following channel to report a bug or discuss a feature or an enhancement:\n\n- [Issue Tracker](https://github.com/Tochemey/NetCore8583/issues)\n- [Discussions](https://github.com/Tochemey/NetCore8583/discussions)\n\nIf you find this library very useful in your day job, kindly show some love by starring it.\n\n## How does NetCore8583 work?\n\nNetCore8583 offers a [`MessageFactory`](./NetCore8583/MessageFactory.cs), 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`](./NetCore8583/IsoMessage.cs) objects, which store [`IsoValue`](./NetCore8583/IsoValue.cs) instances for their data fields. You can work with the [`IsoValue`](./NetCore8583/IsoValue.cs) or use the convenience methods of [`IsoMessage`](./NetCore8583/IsoMessage.cs) to work directly with the stored values.\n\n### MessageFactory and IsoMessage classes\n\nThese are the two main classes you need to use to work with ISO8583 messages. An [`IsoMessage`](./NetCore8583/IsoMessage.cs) can be encoded into a signed byte array. You can set and get the values for each field in an [`IsoMessage`](./NetCore8583/IsoMessage.cs), and it will adjust itself to use a secondary bitmap if necessary. An [`IsoMessage`](./NetCore8583/IsoMessage.cs) 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.\n\nHowever, it can be cumbersome to programmatically create [`IsoMessage`](./NetCore8583/IsoMessage.cs) all the time. The MessageFactory is a big aid in creating [`IsoMessage`](./NetCore8583/IsoMessage.cs)  with predefined values; also, it can set the date and the trace number in each new message.\n\n* There is an extension method that helps switch between signed byte array and unsigned byte array.\n\n#### How to configure the MessageFactory\n\nThere are five main things you need to configure in a [`MessageFactory`](./NetCore8583/MessageFactory.cs): ISO headers, message templates, parsing templates, TraceNumberGenerator, and custom field encoders.\n\n* **Iso headers**: ISO headers are strings that are associated with a message type. Whenever you ask the message factory to create an [`IsoMessage`](./NetCore8583/IsoMessage.cs), it will pass the corresponding ISO header (if present) to the new message.\n\n* **Message Templates**: A message template is an [`IsoMessage`](./NetCore8583/IsoMessage.cs) itself; the [`MessageFactory`](./NetCore8583/MessageFactory.cs) can have a template for each message type it needs to create. When it creates a message and it has a template for that message type, it copies the fields from the template to the new message before returning it.\n\n* **Parsing Templates**: A parsing template is a map containing [`FieldParseInfo`](./NetCore8583/Parse/FieldParseInfo.cs) objects as values and the field numbers as the keys. A [`FieldParseInfo`](./NetCore8583/Parse/FieldParseInfo.cs) object contains an [`IsoType`](./NetCore8583/IsoType.cs) and an optional length; with this information and the field number, the [`MessageFactory`](./NetCore8583/MessageFactory.cs) can parse incoming messages, first analyzing the message type and then using the parsing template for that type; when parsing a message, the [`MessageFactory`](./NetCore8583/MessageFactory.cs) only parses the fields that are specified in the message's bitmap. For example if the bitmap specifies field 4, the factory will get the [`FieldParseInfo`](./NetCore8583/Parse/FieldParseInfo.cs) stored in the map under key 4, and will attempt to parse the field according to the type and length specified by the [`FieldParseInfo`](./NetCore8583/Parse/FieldParseInfo.cs).\nA message does not need to contain all the fields specified in a parsing template, but a parsing template must contain all the fields specified in the bitmap of a message, or the MessageFactory won't be able to parse it because it has no way of knowing how it should parse that field (and also all subsequent fields).\n\n* **ITraceNumberGenerator**: When creating new messages, they usually need to have a unique trace number, contained in field 11. Also, they usually need to have the date they were created (or the date the transaction was originated) in field 7. The [`MessageFactory`](./NetCore8583/MessageFactory.cs) can automatically set the current date on all new messages, you just need to set the assignDate property to true. And it can also assign a new trace number to each message it creates, but for this it needs a TraceNumberGenerator.\nThe [`ITraceNumberGenerator`](./NetCore8583/ITraceNumberGenerator.cs) interface defines a `nextTrace()` method, which must return a new trace number between 1 and 999999. It needs to be cyclic, so it returns 1 again after returning 999999. And usually, it needs to be thread-safe.\nNetCore8583 only defines the interface; in production environments you will usually need to implement your own TraceNumberGenerator, getting the new trace number from a sequence in a database or some similar mechanism. As an example, the library includes the [`SimpleTraceGenerator`](./NetCore8583/Tracer/SimpleTraceGenerator.cs), which simply increments an in-memory value.\n\n* **Custom fields encoders**: Certain implementations of ISO8583 specify fields which contain many subfields. If you only handle strings in those fields, you'll have to encode all those values before storing them in an [`IsoMessage`](./NetCore8583/IsoMessage.cs), and decode them when you get them from an IsoMessage.\nIn these cases you can implement a [`CustomField`](./NetCore8583/ICustomField.cs), which is an interface that defines two methods, one for encoding an object into a String and another for decoding an object from a String. You can pass the [`MessageFactory`](./NetCore8583/MessageFactory.cs) a [`CustomField`](./NetCore8583/ICustomField.cs) for every field where you want to store custom values, so that parsed messages will return the objects decoded by the [`CustomField`](./NetCore8583/ICustomField.cs) instead of just strings; and when you set a value in an [`IsoMessage`](./NetCore8583/IsoMessage.cs), you can specify the CustomField to be used to encode the value as a String\n\n#### Custom Field encoders\n\nSometimes 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.\n\nNetCore8583 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.\n\n### Easy way to configure ISO 8583 messages templates\n\nThe easiest way to configure the message templates and parsing templates is by using a XML config file and pass it to the [`MessageFactory`](./NetCore8583/MessageFactory.cs).\n\n### XML configuration\n\nThe [`MessageFactory`](./NetCore8583/MessageFactory.cs) 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.\nThere 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.\n\n#### Header\n\nSpecify a header element for every type of message that needs an ISO header. Only one per message type:\n\n```xml\n    \u003cheader type=\"0200\"\u003eISO015000050\u003c/header\u003e\n    \u003cheader type=\"0400\"\u003eISO015000050\u003c/header\u003e\n```\n\nYou can define a header as a reference to another header:\n\n```xml\n    \u003cheader type=\"0800\" ref=\"0200\" /\u003e\n```\n\nThe header for 0800 messages will be the same as the header for 0200 messages.\n\n#### Template Element\n\nEach 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`](./NetCore8583/MessageFactory.cs) 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.\n\n```xml\n    \u003ctemplate type=\"0200\"\u003e\n        \u003cfield num=\"3\" type=\"NUMERIC\" length=\"6\"\u003e650000\u003c/field\u003e\n        \u003cfield num=\"32\" type=\"LLVAR\"\u003e456\u003c/field\u003e\n        \u003cfield num=\"35\" type=\"LLVAR\"\u003e4591700012340000=\u003c/field\u003e\n        \u003cfield num=\"43\" type=\"ALPHA\" length=\"40\"\u003eFixed-width data\u003c/field\u003e\n        \u003cfield num=\"48\" type=\"LLLVAR\"\u003eLife, the Universe, and Everything|42\u003c/field\u003e\n        \u003cfield num=\"49\" type=\"ALPHA\" length=\"3\"\u003e840\u003c/field\u003e\n        \u003cfield num=\"60\" type=\"LLLVAR\"\u003eB456PRO1+000\u003c/field\u003e\n        \u003cfield num=\"61\" type=\"LLLVAR\"\u003eThis field can have a value up to 999 characters long.\u003c/field\u003e\n        \u003cfield num=\"100\" type=\"LLVAR\"\u003e999\u003c/field\u003e\n        \u003cfield num=\"102\" type=\"LLVAR\"\u003eABCD\u003c/field\u003e\n    \u003c/template\u003e   \n```\n\nYou 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:\n\n```xml\n    \u003ctemplate type=\"0400\" extends=\"0200\"\u003e\n        \u003cfield num=\"90\" type=\"ALPHA\" length=\"42\"\u003eBla bla\u003c/field\u003e\n        \u003cfield num=\"102\" type=\"exclude\" /\u003e\n    \u003c/template\u003e\n```\n\nIn 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.\n\n#### Parse Element\n\nEach 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`).\n\n```xml\n    \u003cparse type=\"0210\"\u003e\n        \u003cfield num=\"3\" type=\"NUMERIC\" length=\"6\" /\u003e\n        \u003cfield num=\"4\" type=\"AMOUNT\" /\u003e\n        \u003cfield num=\"7\" type=\"DATE10\" /\u003e\n        \u003cfield num=\"11\" type=\"NUMERIC\" length=\"6\" /\u003e\n        \u003cfield num=\"12\" type=\"TIME\" /\u003e\n        \u003cfield num=\"13\" type=\"DATE4\" /\u003e\n        \u003cfield num=\"15\" type=\"DATE4\" /\u003e\n        \u003cfield num=\"17\" type=\"DATE_EXP\" /\u003e\n        \u003cfield num=\"32\" type=\"LLVAR\" /\u003e\n        \u003cfield num=\"35\" type=\"LLVAR\" /\u003e\n        \u003cfield num=\"37\" type=\"NUMERIC\" length=\"12\" /\u003e\n        \u003cfield num=\"38\" type=\"NUMERIC\" length=\"6\" /\u003e\n        \u003cfield num=\"39\" type=\"NUMERIC\" length=\"2\" /\u003e\n        \u003cfield num=\"41\" type=\"ALPHA\" length=\"16\" /\u003e\n        \u003cfield num=\"43\" type=\"ALPHA\" length=\"40\" /\u003e\n        \u003cfield num=\"48\" type=\"LLLVAR\" /\u003e\n        \u003cfield num=\"49\" type=\"ALPHA\" length=\"3\" /\u003e\n        \u003cfield num=\"60\" type=\"LLLVAR\" /\u003e\n        \u003cfield num=\"61\" type=\"LLLVAR\" /\u003e\n        \u003cfield num=\"70\" type=\"ALPHA\" length=\"3\" /\u003e\n        \u003cfield num=\"100\" type=\"LLVAR\" /\u003e\n        \u003cfield num=\"102\" type=\"LLVAR\" /\u003e\n        \u003cfield num=\"126\" type=\"LLLVAR\" /\u003e\n    \u003c/parse\u003e\n```\n\nAs with message templates, you can define parsing guides that extend other parsing guides:\n\n```xml\n    \u003cparse type=\"0410\" extends=\"0210\"\u003e\n        \u003cfield num=\"90\" type=\"ALPHA\" length=\"42\" /\u003e\n        \u003cfield num=\"102\" type=\"exclude\" /\u003e\n    \u003c/parse\u003e\n```\n\n#### Composite Fields\n\nAnother feature is the [`CompositeField`](./NetCore8583/Codecs/CompositeField.cs). This is a [`CustomField`](./NetCore8583/ICustomField.cs) that acts as a container for several [`IsoValue`](./NetCore8583/IsoValue.cs), and it can be configured in the parsing guide of a message type:\n\n```xml\n    \u003cparse type=\"0410\"\u003e\n        \u003cfield num=\"125\" type=\"LLLVAR\"\u003e\n            \u003cfield num=\"1\" type=\"ALPHA\" length=\"5\" /\u003e\n            \u003cfield num=\"2\" type=\"LLVAR\" /\u003e\n            \u003cfield num=\"3\" type=\"NUMERIC\" length=\"6\" /\u003e\n            \u003cfield num=\"4\" type=\"ALPHA\" length=\"2\" /\u003e\n        \u003c/field\u003e\n    \u003c/parse\u003e\n```\n\nIn the above example, when a message with type 0410 is parsed, the value for field 125 will be a [`CompositeField`](./NetCore8583/Codecs/CompositeField.cs) and you can obtain the subfields via **_GetField()_** or **_GetObjectValue()_**. The num attribute of the subfields is ignored.\n\nThis means that you can do this via code:\n\n```c#\n    //Assuming original data for field 125 is \"018one  03two123456OK\"\n    CompositeField f = message.GetObjectValue(125);\n    string sub1 = (string)f.GetObjectValue(0); //\"one  \"\n    string sub2 = (string)f.GetObjectValue(1); //\"two\"\n    string sub3 = (string)f.GetObjectValue(2); //\"123456\"\n    string sub4 = (string)f.GetObjectValue(3); //\"OK\"\n```\n\nYou can also create a [`CompositeField`](./NetCore8583/Codecs/CompositeField.cs), store several subfields inside it, and store it in any field inside an [`IsoMessage`](./NetCore8583/IsoMessage.cs), specifying the same instance as the [`CustomField`](./NetCore8583/ICustomField.cs):\n\n```c#\n    CompositeField f = new CompositeField().AddValue(new IsoValue(IsoType.ALPHA, \"one\", 5))\n    .AddValue(new IsoValue(IsoType.LLVAR, \"two\"))\n    .AddValue(new IsoValue(IsoType.NUMERIC, 123l, 6))\n    .AddValue(new IsoValue(IsoType.ALPHA, \"OK\", 2));\n    message.SetValue(125, f, f, IsoType.LLLVAR, 0);\n```\n\nWhen the message is encoded, field 125 will be \"018one 03two000123OK\".\n\n## Resources\n\n* [ISO 8583](http://en.wikipedia.org/wiki/ISO_8583)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftochemey%2Fnetcore8583","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftochemey%2Fnetcore8583","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftochemey%2Fnetcore8583/lists"}