Tutorial: EDI .NET SDK Advanced

Before We Start the Tutorial

This is the second part of the tutorial, it is assumed that you have gone through the first part (Tutorial: EdiFabric Basics) and are familiar with the concepts of EDI Template, the C# POCO, and EDI file translation or generation.

The tutorial is divided into several sections:

  • The overview will remind you of the concept of EDI Templates and C# POCOs
  • EDI Validation will teach you how to validate EDI files, including HIPAA Snip Levels, EDI Codes, cross-segment dependencies, and injecting custom code
  • EDI Acknowledgment will teach you how to generate acknowledgments such as 997 or 999
  • EDI to DB will teach you how to create database structure for your transaction and save\pull EDI transactions to\from database using Entity Framework DB context
  • EDI to JSON will teach you how to serialize\deserialize to\from JSON using Newtonsoft Json.NET
  • EDI to XML will teach you how to serialize\deserialize to\from XML using XmlSerializer

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.

 

 

 


 

 

 

Overview

Part 1 introduced the concept of EDI Template, which is nothing more than a C# class, inheriting from our own EdiMessage and comprised of properties annotated with our own EDI attributes. When an EDI file is translated, the resulting POCOs are instantiated by the library from each corresponding EDI Template. Alternatively, when EDI files are created, POCOs are manually instantiated and populated with data, and then written out to EDI files.

Let's take another look at the colorful diagram from Part 1, displaying the main operations you can apply to a POCO, and discuss each operation in more detail.

EDI_Template.png

 

 

 


 

 

 

EDI Validation

Accuracy is one of the selling points when employing EDI processes within any enterprise. To be able to validate data before it is sent out according to the same criteria as the receiver expected it, well, that's saving a lot of turnarounds and delays. Proper validation of EDI documents is essential for businesses and allows them to exchange data rapidly and reliably, thus gaining them a significant competitive advantage.

Touching on the notion of EDI Templates, validation follows the same principle as Microsoft's own data annotations for model validation (MVC) or entity validation (Entity Framework). Just like when the template attributes are applied to a simple C# class to turn it into EDI Template, another set of our own attributes can be applied to the template classes and properties, enabling them for validation.

mceclip1.png

These validation attributes allow us to reflect the EDI rules from the specifications to the template classes and the validation operation IsValid() in EdiFabric to take care of enforcing them and providing appropriate error information back to the consumer.

The following basic validation attributes are available:

  • Required
  • ListCount
  • StringLength
  • DataElement

And the following conditional and inter-segment validation attributes are available:

  • Conditional
  • ConditionalAny
  • Exclusion
  • Paired
  • RequiredAny

So, the validation of EDI transactions is a two-step process:

  1. Apply validation attributes to classes and properties according to the EDI implementation guideline (standard or partner-specific, or both). Being simple classes, EDI templates can have multiple versions, per partner or EDI version, which will be loaded accordingly by the library.
  2. Execute the validation. This is done by calling IsValid() on any POCO deriving from EdiMessage

Create a new Console application project and install EdiFabric from NuGet , and add a project reference to the project we created for the EDI Templates in Part 1:

edifabric-write-edi.png

Great, now open Program.cs and add the following code:

using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using EdiFabric.Core.Model.Edi;
using EdiFabric.Core.Model.Edi.ErrorContexts;
using EdiFabric.Framework.Readers;
using EdiFabric.Templates.X12004010; Stream edi = File.OpenRead(@"C:\\PurchaseOrder.txt"); List<IEdiItem> ediItems; using (var reader = new X12Reader(edi, "EdiFabric.Examples.X12.Templates.V4010")) ediItems = reader.ReadToEnd().ToList(); var purchaseOrders = ediItems.OfType<TS850>(); foreach (var purchaseOrder in purchaseOrders) { // Validate MessageErrorContext errorContext; if (!purchaseOrder.IsValid(out errorContext)) { var errors = errorContext.Flatten(); } else { // purchaseOrder is valid, handle it downstream } }

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).

Inspecting the code

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

  • The lines before the foreach simply translate the sample EDI file, which was covered in Part 1, so we'll leave them out.
  • The foreach iterates through all the purchase orders from the EDI file and each of them is individually validated.

NOTE:

You can't validate bach of transactions, only individually one by one. This is to enure that errors are reported with the index offset from the start (ST or UNH segment)

  • Validation is executed by calling IsValid() for each transaction, which returns a boolean
  • The parameter passed in is of type MessageErrorContext and holds all the error information reported by the validation logic (is null if the transaction is valid)

NOTE:

When manually populating a POCO, that is as part of EDI file generation for example, call IsValid with SkipTrailerValidation property set to true like this:

IsValid(out errorContext, 
new ValidationSettings { SkipTrailerValidation = true }

That's it really. A simple method to kick off an elaborate validation process under the hood and report back any wrong findings in a structured, EDI-friendly manner.

Custom EDI Codes

How about the situation when trading partners introduced their own EDI Codes that are different than the standard ones for X12 or EDIFACT. The standard EDI Templates can be copied per trading partner and then each copy can be modified to adhere to the partner specifications. This is useful when partner formats deviate substantially from the standard. When the changes are only contained to the EDI Codes, then EDI Code maps can be used, leaving the template untouched.

Let's assume that Partner A specifies custom EDI Codes for the Transaction Set Purpose Code X12_ID_35. The standard definition for X12, version 4010 being:

/// 
/// Transaction Set Purpose Code
/// 
[Serializable()]
[DataContract()]
[EdiCodes(",00,01,02,03,04,05,06,07,08,10,11,12,13,14,15,16,17," +
"18,19,20,21,22,24,25,26,27,28,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44," +
"45,46,47,48,49,50,51,52,53,54,55,5,6,5C,77,CN,CO,EX,GR,PR,RH,RV,SU,ZZ,")]
public class X12_ID_353
{
}

Partner A, however, defines it as a set of only two, not included in the standard values:

/// 
/// Transaction Set Purpose Code
/// 
[Serializable()]
[DataContract()]
[EdiCodes(",PA,PB,")]
public class X12_ID_353_PartnerA
{
}

By default when the EDI Template for the standard 850 is used, calling IsValid() will check the values from X12_ID_353, but we want it to check against the values from X12_ID_353_PartnerA regardless.

This is possible by including an EDI Code map as a parameter to IsValid(). In the same Program.cs, change the code to:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using EdiFabric.Core.ErrorCodes;
using EdiFabric.Core.Model.Edi;
using EdiFabric.Core.Model.Edi.ErrorContexts;
using EdiFabric.Framework.Readers;
using EdiFabric.Templates.X12004010; Dictionary<Type, Type> codeSetMap = new Dictionary<Type, Type>();
codeSetMap.Add(typeof(X12_ID_353), typeof(X12_ID_353_PartnerA));

Stream edi = File.OpenRead(@"C:\\PurchaseOrder.txt"); List<IEdiItem> ediItems; using (var reader = new X12Reader(edi, "EdiFabric.Examples.X12.Templates.V4010")) ediItems = reader.ReadToEnd().ToList(); var purchaseOrders = ediItems.OfType<TS850>(); foreach (var purchaseOrder in purchaseOrders) { // Validate MessageErrorContext errorContext; if (!purchaseOrder.IsValid(out errorContext, new ValidationSettings
{ DataElementTypeMap = codeSetMap })) { var errors = errorContext.Flatten(); } else { // purchaseOrder is valid, handle it downstream } }

The changes are:

  • The first two lines define the EDI Code map, that is a dictionary mapping the source to the destination EDI Code type. This way when the validation logic encounters the source type it will apply the validation as according to the destination type.
  • Pass that EDI Code map to IsValid() as DataElementTypeMap in ValidationSettings.

Additional information:

 

Example code

 

 

  


 

 

 

EDI Acknowledgments

In the previous section, we mentioned the importance of accuracy in the exchange of business documents. Validation is a nifty way for a receiver to discern the quality of the data received, however in the cases it is poor, how would it report it back to the sender? What would be a standard way to let the sender that the data was received and it is of a sufficient (or not) quality?

EDI Acknowledgments are a standard approach, implemented as part of the EDI communication, to acknowledge receipt and data consistency between trading partners. Broadly speaking, there are two types of acknowledgments - technical, which confirms the receipt of an interchange called TA1 for X12, CONTRL for EDIFACT, and functional, which confirms that the data received was recognized by the receiver and can be parsed\processed, and are called 997 for X12 and CONTRL for EDIFACT. EDIFACT uses the same transaction but different segments are transmitted when used as technical or functional ack.

EdiFabric employs parallel approach when dealing with acknowledgments, meaning that whilst an EDI file is still being translated, acknowledgments will be raised via .NET events as functional groups and interchanges are encountered. This allows the consumer to do both operations, translation, and acknowledgment, in parallel and potentially in separate threads, thus providing a non-blocking and fast mechanism to respond immediately and to maintain a single acknowledgment in-memory.

Let's acknowledge our sample EDI file which had the following structure:

mceclip1.png

A TA1 (X12 technical acknowledgment) will be created for each interchange (ISA\IEA block). A 997 (or 999) will be created for each functional group (GS\GE block). The ISA segment also contains a flag (in purple) telling us whether the sender expects an acknowledgment or not. This flag can either be honored or ignored or overridden depending on the agreement between the partners.

So we expect 2 acknowledgments to be generated, the first TA1 right after the ISA was read if it had any issues.

Create a new Console application project and install EdiFabric from NuGet , and add a project reference to the project we created for the EDI Templates in Part 1:

edifabric-ack-edi.png

Then add the following code in Program.cs:

using System.Diagnostics;
using System.IO;
using System.Reflection;
using EdiFabric.Core.Model.Edi.X12;
using EdiFabric.Framework.Readers;
using EdiFabric.Plugins.Acknowledgments.X12.Model;
using EdiFabric.Examples.X12.Common;

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

var settings = new AckSettings
{
AckHandler = (s, a) => { var tsTa1 = a.Message as TSTA1; var ts997 = a.Message as TS997; if (tsTa1 != null) { // a.Message is TA1 } if (ts997 != null) { // Inspect the acknowledgment var ackCode = ts997.AK9.FunctionalGroupAcknowledgeCode_01; var ack = AckBuilders.BuildAck(a.InterchangeHeader,
a.GroupHeader,
ts997, AckVersion.X12_997); } }, MessageHandler = (s, a) => { if (!a.ErrorContext.HasErrors) { } }, AckVersion = AckVersion.X12_997 }; using (var ackMan = new Plugins.Acknowledgments.X12.AckMan(settings)) { using (var ediReader = new X12Reader(edi,
"EdiFabric.Examples.X12.Templates.V4010")) { while (ediReader.Read()) ackMan.Publish(ediReader.Item); } }

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).

Inspecting the code

It begins with creating an instance of AckSettings which holds references to the bodies of the events where the acknowledgments will be raised. This example defines them inline but you can code it in your preferred way. AckSettings defines two event handlers:

  1. AckHandler - where all events will be raised, both technical and functional
  2. MessageHandler - where each POCO will be reported, e.g. our purchase order in this case

The reason for having a separate handler for the transactions is to be able to process them in it, as opposed to in the EDI reader while loop because:

  • The will be validated already
  • They will be checked for duplicates
  • They will be marked as being in a duplicate functional group or interchange

If you need to ensure any of the 3 points above are valid before processing the transaction downstream, then do so in the MessageHandler .

The AckHandler provides the acks as POCOs (all EDI Templates for the standard acknowledgments can be referenced from EdiFabric.Core), so you can inspect or manipulate them at this stage. You can then generate a final EDI acknowledgment using the EDI Generation routine we learned about in Part 1 of the tutorial. The original ISA and GS are also included in the event so you can reuse some of the information to create their response counterparts if needed. With that information at hand, the EDI acknowledgment can be turned to a string or written out to a file.

The last step is how to actually inject that AckSettings instance as part of the reader, or any list of EDI items for that matter? You need to create an instance of AckMan taking the AckSettings as a parameter.

using (var ackMan = new Plugins.Acknowledgments.X12.AckMan(settings)) 

Then whilst you read, add the extra step of publishing the currently read item to AckMan

NOTE:

You don't need to validate the transactions separately when reading, they come already validated in the MessageHandler, simply inspect their ErrorContext

while (ediReader.Read()) 
ackMan.Publish(ediReader.Item);

NOTE:

The ack in AckHandler is a normal POCO, instance of an EDI Template (see EDI Acknowledgment Reference below) and you can manipulate it or write to an EDI file straight away bu using the normal EDI Generation operation (discussed in Part 1)

Additional information:

Example code

 

 

 


 

 

 

EDI to DB

EdiFabric allows you to automatically create a database structure for all EDI Templates, sharing segments and complex data elements across all transactions in the same version. Each EDI Template is prepared for use by the Entity Framework, so that:

  • An Id property is included for every class
  • Complex properties are defined as virtual
  • Collections of properties are defined as List<>
  • A separate DB context is provided for each EDI version

It's amazing how quickly you can create a new database and start saving EDI transactions to it. Let's demonstrate it:

Create a new ClassLibrary project, install Entity Framework and EdiFabric from NuGet, and then add a project reference to the EDI Templates project we created in Part 1, which contains the EDI Template for 850 purchase order.

mceclip3.png

Then add the DbContext.cs file for version 4010 to that project.

The DbContext.cs file contains System.Data.Entity.DbSet for every EDI Template in the selected EDI version, however for our example we only need the purchase order and you'll have to manually remove all other DbSets pointing to items that are not included.

NOTE:

You can add ALL EDI Templates for version 4010 in the EdiFabric.Examples.X12.Templates.V4010 templates project to save time correcting the DbContext file.

Excellent, so we have out Entity Framework DB context ready, let's use it.

Create a new Console project and install Entity Framework and EdiFabric from NuGet, and then add project references to the EDI Templates project we created in Part 1, and to the Entity Framework project we created in the previous step:

mceclip4.png

Add the following code to Program.cs:

using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using EdiFabric.Core.Model.Edi;
using EdiFabric.Framework.Readers;
using EdiFabric.Templates.X12004010;
Stream edi = File.OpenRead(@"C:\\PurchaseOrder.txt");

List<IEdiItem> ediItems;
using (var reader = new X12Reader(edi, "EdiFabric.Examples.X12.Templates.V4010"))
ediItems = reader.ReadToEnd().ToList();

var purchaseOrders = ediItems.OfType<TS850>();

using (var db = new X12Context()) { db.TS850.AddRange(purchaseOrders); db.SaveChanges(); } 

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).

Inspecting the code

The top part reads our sample EDI file. Once we have all the purchase order POCOs to save to a database we create an instance of the DB Context, add the purchase orders to the corresponding entity and save it.

The save operation will create the database structure the first time it is executed:

mceclip5.png

NOTE:

Edit the connection string to point to a specific SQL Server instance.

That's it. Now you can enjoy the full power of Entity Framework (or other data access technology if you prefer so) to query the database.

Example code

 

 

 


 

 

 

EDI to JSON

Do you need any specific operations to convert to or from JSON? Not at all. Your EDI data, transactions and control segments, is represented as C# POCOs, hence you can employ the familiar Newtonsoft Json.NET to serialize to JSON and deserialize from JSON.

Create a new Console project and install EdiFabric from NuGet, and then add project references to the EDI Templates project we created in Part 1:

mceclip6.png

Add the following code to Program.cs:

using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using EdiFabric.Core.Model.Edi;
using EdiFabric.Framework.Readers;
using EdiFabric.Templates.X12004010; Stream edi = File.OpenRead(@"C:\\PurchaseOrder.txt");

List<IEdiItem> ediItems;
using (var reader = new X12Reader(edi, "EdiFabric.Examples.X12.Templates.V4010"))
ediItems = reader.ReadToEnd().ToList();

var purchaseOrders = ediItems.OfType<TS850>();

foreach (var transaction in transactions)
{
string json = Newtonsoft.Json.JsonConvert.SerializeObject(transaction);
}

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).

Inspecting the code

The top part reads our sample EDI file. Then we iterate through each purchase order in the EDI file and convert it to JSON. Deserialization is the other way around, we take a JSON conforming to the EDI Template for 850 and deserialize it to POCO:

var purchaseOrder = Newtonsoft.Json.JsonConvert.DeserializeObject<TS850>(json);

Additional information:

 

Example code

 

 

 


 

 

 

EDI to XML

Following from EDI to JSON, we can rely on the familiar XmlSerializer and DataContractSerializer to serialize to XML and deserialize from XML.

Create a new Console project and install EdiFabric from NuGet, and then add project references to the EDI Templates project we created in Part 1:

mceclip7.png

Add the following code to Program.cs:

using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using EdiFabric.Core.Model.Edi;
using EdiFabric.Framework.Readers;
using EdiFabric.Templates.X12004010; Stream edi = File.OpenRead(@"C:\\PurchaseOrder.txt");

List<IEdiItem> ediItems;
using (var reader = new X12Reader(edi, "EdiFabric.Examples.X12.Templates.V4010"))
ediItems = reader.ReadToEnd().ToList();

var purchaseOrders = ediItems.OfType<TS850>();

foreach (var transaction in transactions)
{
var xml = Serialize(transaction);
} public static XDocument Serialize(EdiMessage instance) { if (instance == null) throw new ArgumentNullException("instance"); var serializer = new XmlSerializer(instance.GetType()); using (var ms = new MemoryStream()) { serializer.Serialize(ms, instance); ms.Position = 0; return XDocument.Load(ms, LoadOptions.PreserveWhitespace); } }

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).

Inspecting the code

The top part reads our sample EDI file. Then we iterate through each purchase order in the EDI file and convert it to XML. Deserialization is the other way around, we take an XML conforming to the EDI Template for 850 and deserialize it to POCO:

var purchaseOrder = Deserialize<TS850>(xml);
public static T Deserialize<T>(XElement xml)
{
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(xml.CreateReader());
}

Additional information:

 

Example code

 

 

 


 

 

 

Wrapping Up

Congratulations again! You've created code that validates EDI transactions, acknowledges EDI interchanges and groups, creates DB structure to save and query EDI transactions, and serializes\deserializes to\from JSON & XML.

Check out the full example solutions here:

For a more detailed explanation of each of these topics, check out the rest of the documentation.

 

Was this article helpful?
4 out of 5 found this helpful