Tutorial: EDI .NET SDK Basics

Before We Start the Tutorial

We will use the popular EDI flow of receiving a purchase order and then sending back an invoice during this tutorial. You might be tempted to skip it because you don't see your transaction - but give it a chance. The techniques you’ll learn in the tutorial are fundamental to building any EDI apps, and mastering them will give you a deep understanding of EdiFabric.

The tutorial is divided into several sections:

  • The overview will teach you the fundamentals of EdiFabric: EDI Templates and attributes
  • EDI Translation will teach you how to parse EDI files using EdiReader
  • What can I do with my EDI Template POCO will teach you the available operations such as validation, save to DB, generate acknowledgment or serialize to JSON/XML
  • EDI Generation will teach you how to generate EDI files using EdiWriter

Part 2 of the tutorial will cover EDI validation, acknowledgments, creating DB structure to save and query, serialize\deserialize to\from JSON & XML.

You don't have to complete all of the sections at once to get the value out of this tutorial. Try to get as far as you can - even if it's one or two sections.

Setup and Prerequisites

You can see what we'll be building here: 

Download C# examples

The narrative will use primarily X12 examples; however, a link to the corresponding EDIFACT examples will be included for every section. We'll assume that you have some familiarity with EDI and X12, but you should be able to follow along even if you're new to EDI. We'll also assume that you're familiar with .NET and C#.

You'll also need Visual Studio to open the example solutions: Get Visual Studio.








Now that you're set-up let's get an overview of EdiFabric!

What is EdiFabric?

EdiFabric is an efficient and flexible .NET library for building EDI applications. It lets you convert between EDI files and C# instances. It's a tiny but powerful library that you can incorporate into your Visual Studio solution as a NuGet package.

EdiFabric has different components and features, but we'll start with the EDI Template, which is the core building block.

EDI Template is the name we've given to the C# model that represents an EDI transaction. In the EDI world, the format (or rule, or specification) of business documents (or transactions) is provided as some sort of a text or pdf file with diagrams and lists, like this:


We've gone a step further and turned all this information into a simple class that is annotated with our EDI attributes and follows the same principle as the Data Annotations in ASP.NET MVC or Entity Framework like this:


So, the most important concept of EdiFabric is a simple C# class, or model as in MVC, that inherits from our own EdiMessage and is comprised of properties annotated with our own EDI attributes.

Additional Information

Great, now that we have established that our EDI transactions are represented with simple C# classes, let's see what we can use them for.







EDI Translation

The main feature of EdiFabric is to translate EDI files into C# instances (of the EDI Templates, remember) and to generate EDI files from C# instances (of the same EDI Templates). In other words, the library allows you to execute additional methods on top of the functionality provided by the .NET Framework or .NET Core.

In order to translate (or parse, or read) an EDI file using EdiFabric, you'll need the following items:

  1. The EDI file itself - download X12 sample file, download EDIFACT sample file
  2. The EDI template(s) for the transaction(s) in the EDI file - see the Quickstart
  3. EdiFabric NuGet package - get the trial

We'll use purchase order, 850, version 4010 for the examples. The corresponding EDIFACT transaction is ORDERS and links to the EDIFACT examples will be provided alongside X12.


It doesn't have to be EDI file, the reader takes System.IO.Stream as an argument so any stream of EDI data can be parsed.

The act of translation is to go over the EDI file, identify each transaction or control segment and load the corresponding EDI Template, and finally parse the transaction data onto an instance of that EDI Template.

Let's assume that we want to translate the following file:


The first thing to do is to identify the transactions, in this case, it's a single purchase order (850 as denoted in the ST segment) of version 4010 (as denoted in the GS segment), all marked in purple. All control segments (ISA, GS, GE, GE) are standard (don't change), and their respective EDI Templates are referenced from EdiFabric.Core.

This means that the block of data between the ST and the SE segment will be transposed into an instance of the EDI Template class that represents purchase order, version 4010. How does the framework work this out? In the general case, it does that by matching the values from the file to the values in the MessageAttribute that is applied to the EDI Template class:

[Message("X12", "004010", "850")]
public class TS850 : EdiMessage

So, to be able to translate EDI files into C# instances, we need to know the classes for those instances. It's a good practice to store all the templates for a standard version in their separate project. Similarly, all partner-specific template customization is better separated from the standard ones, to minimize the impact of modification and re-test.

All EDI templates for a version share the same set of segment and data element classes, as well as EDI codes, and all of them implement common interfaces. This allows you to implement any mapping logic over the interfaces, thus eliminating the duplication of the mapping code.

Let's get back to our example purchase order. Create a new Console project following the Create a New Project tutorial

After you finished it, your code in Program.cs should look like the following:

Stream edi = File.OpenRead(@"C:\PurchaseOrder.txt");

List<IEdiItem> ediItems; using (var ediReader = new X12Reader(edi, "EdiFabric.Templates.X12")) ediItems = ediReader.ReadToEnd().ToList(); var purchaseOrders = ediItems.OfType<TS850>(); 

Change the path in File.OpenRead to the path of the sample purchase order file you've downloaded (no recollection to have downloaded any files ?!?, here's a reminder - download X12 sample file).

That's it, now run this in Debug mode and see the magic happen!

Inspecting the code

What does the code do? Let's delve into the details.

  • The first line loads the EDI data from the sample file into a System.IO.Stream.
  • Then we declare a list of IEdiItem which will hold all of the control segments and transactions that the parser finds, in the order, they were found.
  • Next, we create an instance of the X12Reader and pass two arguments to it:
    • 1. The stream of EDI data to parse
    • 2. The assembly name of the project where the corresponding EDI template will be instantiated from
  • Finally, we call ReadToEnd(), which will read all the data in the sample file, from the beginning to the end

The example code shows the main concepts when reading EDI files:

  1. It's a stream-based, forward-only reader, similar to XmlReader.
  2. All EDI items are presented in an ordered list, matching the order they appear in the file.
  3. There are two reading modes - ReadToEnd and Read, the latter allowing you to stream EDI item by EDI item for large EDI files (> 2MB).
  4. All read modes are provided in an async version as well.
  5. The assembly name of the project with the EDI templates can be found by right-clicking on the project name in Visual Studio and selecting Properties:


Additional information:

Example code







EDI Translation for Large Files

We briefly mentioned that there are two reading modes - ReadToEnd and Read, together with their async counterparts. The reason for the existence of the two is to allow you to either translate a full file at once and have all the EDI items in a list and in-memory or to read only one EDI item at a time and in-memory.

Sometimes EDI files contain batches of transactions, for historical or other reasons, mixed or uni-type, but in large volumes. Plowing through large files requires resources preservation and efficient streaming, which we are going to demonstrate right away.

Open Program.cs and add the following code: 

using System.Diagnostics;
using System.IO;
using System.Reflection;
using EdiFabric.Core.Model.Edi.X12;
using EdiFabric.Framework.Readers;
using EdiFabric.Templates.X12004010;

Stream edi = File.OpenRead(@"C:\PurchaseOrder.txt");
using (var ediReader = new X12Reader(edi, "EdiFabric.Examples.X12.Templates.V4010"))
    while (ediReader.Read())
var po = ediReader.Item as TS850;
if (po != null)
} private static void ProcessPurchaseOrder(ISA isa, GS gs, TS850 purchaseOrder)
// Do something with the purchase order

Inspecting the code

What does the code do? Loading the EDI file to stream and creating the X12Reader is the same as the last example. The difference is in the reading mode:

  • Use Read() instead of ReadToEnd() in a while loop
  • Each iteration will return an EDI item, so for our sample file there will be 5 iterations with 5 EDI items returned:
    1. ISA
    2. GS
    3. The only purchase order or 850
    4. GE
    5. IEA
  • The current item can be accessed by ediReader.Item where the type of the item determines which transaction or control segment it is
  • The items we are interested in can be processed (it's a good idea to offload that processing asynchronously or in a different thread) downstream and then disposed of as the file is being read.
  • Each current item holds references to its ISA (ediReader.CurrentInterchangeHeader) and GS (ediReader.CurrentGroupHeader) as well as the delimiters used (ediReader.Separators) and the offset of bytes from the start of the reading operation (ediReader.BytesRead)


Sometimes the transactions themselves are large and contain a specific loop that bundles many items, such as order lines or patient claims for example. In this situation the streaming won't do much good and the transaction itself will need to be broken into parts. This is called splitting and you can learn more about it in the Large EDI files translation by splitting article.

Example code

Now that we've covered the EDI translation techniques, let's move on and do something with the EDI transaction instance.







What can I do with my EDI Template POCO?

The diagram below colorfully depicts the main operations:


As you can see, the EDI Template POCO is at the center of all operations, and that is exactly because it is a C# POCO (or POCO-like if we want to be precise because it does depend on our DOM attributes and base class, but let's not be overly meticulous).

Once you have the POCO, either by having it translated from an EDI file or manually instantiated and populated, you can immediately:

  • Write it out to an EDI file (or stream for that matter)
  • Save it to a database using Microsoft Entity Framework
  • Validate it for the relevant EDI compliance, such as the HIPAA Snip Levels
  • Serialize it to JSON using Newtonsoft Json.NET
  • Generate acknowledgments such as 997 or 999 (that is on the whole interchange or group and not just the transaction)
  • Serialize it to XML using Microsoft XmlSerializer
  • Export it to CSV using custom code and file format
  • Map it to another POCO or domain object
  • Process it downstream to another application or service, etc.

As part of this tutorial, we'll demonstrate the first step and leave all the other steps to part two of the tutorial.







EDI Generation

My trading partner wants me to send her EDI files, can I do that with EdiFabric? Does that sound familiar, or at least some of it? If yes, then read on.

Having learned about the EDI Templates, we can happily assume that if we can instantiate the correct EDI Template for the transaction and version we need, and populate it with data, we can then somehow turn it into an EDI file.

So, generating (or creating) and EDI file is a two-step process:

  1. Create an instance of EDI Template and populate it
  2. Write the instance(s) to an EDI file (or stream)

Create an instance of EDI Template and populate it

The data to go out to a trading partner usually originates in a domain entity, internal database, CSV file, XML output or service response in JSON. Whatever the casting, the data will need to be mapped to the EDI Template we've identified. There are multiple approaches to this; however, the topic of converting data structures from one to another is outside the scope of our discussion.

The general idea is to reuse the existing mapping pattern for all other, non-EDI, processes in your other (personal or work) projects and to apply it for EDI as well.

We'll use invoice, 810, version 4010 for the examples. The corresponding EDIFACT transaction is INVOIC and links to the EDIFACT examples will be provided alongside X12.

Here are some instantiation\mapping ideas which might be useful pointers:

To recap: let's say that you need to send an EDI file to a trading partner that contains an invoice, 810 in version 4010, as a response to a previously received purchase order from that same trading partner.

You've pulled the invoice from your invoicing system in some format, and converted it to its corresponding EDI Template instance. That is, step 1 completed.

Write the instance(s) to an EDI file (or stream)

To create the destination EDI file, we'll use the EdiWriter. Once you have the file, you can transport it to the recipient; however, the communication part is not a feature of EdiFabric.

Back in our Visual Studio Tutorial solution, create another Console application project, install EdiFabric from NuGet , and add a project reference to the library project we created for the EDI Templates:


Open Program.cs and add the following code:

using System.Diagnostics;
using System.IO;
using System.Reflection;
using EdiFabric.Examples.X12.Common;
using EdiFabric.Examples.X12.Templates.V4010;
using EdiFabric.Framework.Writers; var invoice = EF_X12_004010_810_Builder.BuildInvoice("1"); using (var stream = new MemoryStream()) { using (var writer = new X12Writer(stream)) { writer.Write(SegmentBuilders.BuildIsa("1")); writer.Write(SegmentBuilders.BuildGs("1")); writer.Write(invoice); } string edi = stream.LoadToString(); }

Inspecting the code

The first line creates an invoice POCO by manually instantiating an 810, version 4010, and populating it with hard-coded data. In reality, this will be the end product of a mapping component\code\routine\deserialization\etc.


  • A new MemoryStream is created (it could be any stream really, such as FileStream, etc.). This is where all the EDI data will be written to
  • Next, an instance of the X12Writer is created (EdifactWriter for EDIFACT), taking the stream as a parameter
  • Then, write to the stream beginning with the ISA segment:
public static ISA BuildIsa(string controlNumber, 
            string senderId = "SENDER1", 
            string senderQ = "14", 
            string receiverId = "RECEIVER1", 
            string receiverQ = "16", 
            string ackRequested = "1", 
            string testIndicator = "T")
	return new ISA
		//  Authorization Information Qualifier
		AuthorizationInformationQualifier_1 = "00",
		//  Authorization Information
		AuthorizationInformation_2 = "".PadRight(10),
		//  Security Information Qualifier
		SecurityInformationQualifier_3 = "00",
		//  Security Information
		SecurityInformation_4 = "".PadRight(10),
		//  Interchange ID Qualifier
		SenderIDQualifier_5 = senderQ,
		//  Interchange Sender
		InterchangeSenderID_6 = senderId.PadRight(15),
		//  Interchange ID Qualifier
		ReceiverIDQualifier_7 = receiverQ,
		//  Interchange Receiver
		InterchangeReceiverID_8 = receiverId.PadRight(15),
		//  Date
		InterchangeDate_9 = DateTime.Now.Date.ToString("yyMMdd"),
		//  Time
		InterchangeTime_10 = DateTime.Now.TimeOfDay.ToString("hhmm"),
		//  Standard identifier
		InterchangeControlStandardsIdentifier_11 = "U",
		//  Interchange Version ID
		//  This is the ISA version and not the transaction sets versions
		InterchangeControlVersionNumber_12 = "00204",
		//  Interchange Control Number
		InterchangeControlNumber_13 = controlNumber.PadLeft(9, '0'),
		//  Acknowledgment Requested (0 or 1)
		AcknowledgementRequested_14 = ackRequested,
		//  Test Indicator
		UsageIndicator_15 = testIndicator,
  •  Followed by the GS segment:
public static GS BuildGs(string controlNumber, 
            string senderId = "SENDER1", 
            string receiverId = "RECEIVER1")
	return new GS
		//  Functional ID Code
		CodeIdentifyingInformationType_1 = "IN",
		//  Application Senders Code
		SenderIDCode_2 = senderId,
		//  Application Receivers Code
		ReceiverIDCode_3 = receiverId,
		//  Date
		Date_4 = DateTime.Now.Date.ToString("yyMMdd"),
		//  Time
		Time_5 = DateTime.Now.TimeOfDay.ToString("hhmm"),
		//  Group Control Number
		//  Must be unique to both partners for this interchange
		GroupControlNumber_6 = controlNumber.PadLeft(9, '0'),
		//  Responsible Agency Code
		TransactionTypeCode_7 = "X",
		//  Version/Release/Industry id code
		VersionAndRelease_8 = "004010"
  • Lastly, we write our invoice out


You don't need to close the group (write GE segment) or the interchange (write the IEA segment), the X12Writer does that automatically for you.


By default the writer uses the standard separators. If you want to use different separator don't set it in the ISA object, but use the Separators object when writing the ISA out:


Perhaps you need the file to have each segment on a new line for readability ? You can do so by setting a post-fix in the WriterSettings:

The stream now contains our EDI data and we can write it out to a file, turn into a string or do anything else we want with it.

Additional information:

Example code







Wrapping Up

Congratulations! You've created code that translates EDI files and generates EDI files.

Nice work! We hope you now feel like you have a decent grasp on how EdiFabric works.

Check out the full example solutions here:

Throughout this tutorial, we touched on EdiFabric concepts including EDI Templates, EDI translation, and EDI generation. For a more detailed explanation of each of these topics, check out the second part of this tutorial that covers the advanced features or the rest of the documentation.

Was this article helpful?
8 out of 12 found this helpful