No matter how customers want to do EDI, we've got you covered

Ready for EDI ?

Get the framework

Install ediFabric.Framework using NuGet from the package manager console:

PM> Install-Package ediFabric.Framework

Alternatively you can do a hard reference in your Visual Studio project to EdiFabric.Framework.dll.

Prepare the EDI specs

Browse our collection of standard-compliant and ready to use EDI spec packages, or roll up your sleeves and do your own.

EDI specs come in version packages so you need to identify which versions are required by your partners before moving on.

Include the EDI specs

Add only the C# files that you need to a new or existing project in your solution and add a reference to it. Do the same for the XSD files but additionally set the Build Action of each to Embedded Resource.

The specs can also be loaded dynamically from multiple assemblies. Read more for advanced options.

Read to end

Use X12Reader or EdifactReader to read through all control segments and messages in one go. Uses iterator blocks to yield the results.

X12

using (var ediReader = X12Reader.Create(
    File.OpenRead(@"C:\edi.txt"), "NameOfProjectWithClasses"))
{
    List<object> invoices = ediReader.ReadToEnd().OfType<M_810>();
}

Edifact

using (var ediReader = EdifactReader.Create(
    File.OpenRead(@"C:\edi.txt"), "NameOfProjectWithClasses"))
{
    List<object> ediItems = ediReader.ReadToEnd().OfType<M_INVOIC>();
}

Read with streaming

Use X12Reader or EdifactReader to read through all control segments and messages one at a time. Use for large messages.

X12

using (var ediReader = X12Reader.Create(
    File.OpenRead(@"C:\edi.txt"), "NameOfProjectWithClasses"))
{
    while (ediReader.Read())
     {
        object currentItem = ediReader.Item;
        if (currentItem is IEdiControl) { // ... (ISA, GS, GE, IEA) } 
        if (currentItem is ParsingException) { // inspect the error ... }
        if (currentItem is M_810) { // handle the message ... }
     }
}

Edifact

using (var ediReader = EdifactReader.Create(
    File.OpenRead(@"C:\edi.txt"), "NameOfProjectWithClasses"))
{
    while (ediReader.Read())
     {
        object currentItem = ediReader.Item;
        if (currentItem is IEdiControl) { // ... (UNB, UNG, UNE, UNZ) } 
        if (currentItem is ParsingException) { // inspect the error ... }
        if (currentItem is M_INVOIC) { // handle the message ... }
     }
}

Create

Use X12Group and X12Interchange to create a collection of segment strings and then aggregate them into an EDI message.

X12

var m810 = new M_810();
// construct the message ...
var groupHeader = = new S_GS();
// construct the group header ...
var interchangeHeader = = new S_ISA();
// construct the interchange header ...
 
var ediGroup = new X12Group<M_810>(groupHeader);
ediGroup.AddItem(m810);
var ediInterchange = new X12Interchange(interchangeHeader);
ediInterchange.AddItem(ediGroup);
 
IEnumerable<string> ediSegments = ediInterchange.GenerateEdi();
 
// your EDI message without postfix
string edi = ediSegments.Aggregate("",
                (current, segment) => current + segment);
 
// your EDI message with new line as postfix
string ediPostfix = ediSegments.Aggregate("",
                (current, segment) =>
                    current + segment + Environment.NewLine);

Edifact

var mInvoic = new M_INVOIC();
// construct the message ...
// Edifact usually do not need to be wrapped up in a group
// only do groups if necessary
var interchangeHeader = new S_UNB();
// construct the interchange header ...
 
var ediGroup = new EdifactGroup<M_INVOIC>(null);
ediGroup.AddItem(mInvoic);
var ediInterchange = new EdifactInterchange(interchangeHeader);
ediInterchange.AddItem(ediGroup);
 
IEnumerable<string> ediSegments = ediInterchange.GenerateEdi();
 
// your EDI message
string edi = ediSegments.Aggregate("",
                (current, segment) => current + segment);
 
// your EDI message with new line as postfix
string ediPostfix = ediSegments.Aggregate("",
                (current, segment) =>
                    current + segment + Environment.NewLine);

Create with custom separators

Use Separators to create with custom separators.

X12

var interchangeHeader = = new S_ISA();
// construct the interchange header ...
var ediInterchange = new X12Interchange(interchangeHeader);
// construct the interchange ...
var defaultSep = Separators.DefaultX12();
var newSep = new Separators('>', ':', defaultSep.DataElement,
     defaultSep.RepetitionDataElement, null);
 
IEnumerable<string> ediSegments = ediInterchange.GenerateEdi(newSep);

Edifact

var interchangeHeader = new S_UNB();
// construct the interchange header ...
var ediInterchange = new EdifactInterchange(interchangeHeader);
// construct the interchange ... 
var defaultSep = Separators.DefaultEdifact();
var newSep = new Separators('>', ':', defaultSep.DataElement,
     defaultSep.RepetitionDataElement, defaultSep.Escape);
 
IEnumerable<string> ediSegments = ediInterchange.GenerateEdi(newSep);

Validate

Ensure your EDI objects adhere to the EDI specs. Use ErrorContext and FailedLine to locate the exact position of the error within the message.

X12

var m810 = new M_810();
// ...
var result = EdiValidator.Create("NameOfProjectWithXsd").Validate(mInvoic);
if (result.HasErrors) { // inspect the errors ... }

Edifact

var mInvoic = new M_INVOIC();
// ...
var result = EdiValidator.Create("NameOfProjectWithXsd").Validate(mInvoic);
if (result.HasErrors) { // inspect the errors ... }

Prepare acknowledgments

Use the AckMan add-on to generate TA1, 997 or 999 acknowledgments which are raised as events whilst the stream is read along.

Generate acknowledgments and handle rejected messages

var settings = new AckSettings
{
    AckHandler = (s, a) =>
    {
        if (a.AckType == AckType.AckTa1) {
        // a.AckInterchange is TA1 
        }
        if (a.AckType == AckType.Ack999) {
        var ediSegments = a.AckInterchange.GenerateEdi();
        var ack = ediSegments.Aggregate("", (current, item) => 
                        current + item + Environment.NewLine);
        }
    },
    MessageHandler = (s, a) =>
    {
        if (!a.ErrorContext.HasErrors && 
                        !a.IsInDuplicateGroup && 
                            !a.IsInDuplicateInterchange) {
        // do something with the message a.Message
        }
    },
    AckVersion = AckVersions.Hipaa_999
};
var ackMan = new AckMan(settings);
using (var ediReader = X12Reader.Create(edi)) {
while (ediReader.Read()) {
    ackMan.Publish(ediReader.Item);
    }
}
ackMan.Complete();

Detect duplicates and generate custom control numbers

var settings = new AckSettings
{
    AckHandler = AckHandler,
    MessageHandler = MessageHandler,
    AckVersion = AckVersions.X12_997,
    TransactionSetDuplicates = true,
    GroupDuplicates = true,
    InterchangeDuplicates = MyDuplicateCheckFunc,
    Incrementers = new ControlIncrementers(MyControlNumberFunc, null, null)
};
public bool MyDuplicateCheckFunc(string controlNumber)
{
    return controlNumber == "somectrlnr";
}
public int MyControlNumberFunc()
{
    return 123;
}
public void AckHandler(object sender, AckEventArgs ackEventArgs)
{
    var ediSegments = ackEventArgs.AckInterchange.GenerateEdi();
    var ack = ediSegments.Aggregate("", (current, item) => 
                current + item + Environment.NewLine);
}
public void MessageHandler(object sender, MessageEventArgs messageEventArgs)
{
    if (!messageEventArgs.ErrorContext.HasErrors &&
          !messageEventArgs.IsInDuplicateGroup &&
          !messageEventArgs.IsInDuplicateInterchange)
    { // do something with the message a.Message }
}