This project has moved. For the latest updates, please go here.

Issue with EDI Serialize

Feb 24, 2014 at 10:02 PM
I have a trouble on EDI serializing an 810( INVOIC) format, the XML generated is correct :

<S_BIG>
<D_373_1>20120213</D_373_1>
<D_76_2>0924303824</D_76_2>
<D_373_3>20120213</D_373_3>
<D_324_4>0000000000</D_324_4>
</S_BIG>

However when i serialize this node to EDI, i get something like ( the order for the parameters is broken ) : BIG201202132012021309243038240000000000.

Thanks for the help.
Feb 25, 2014 at 12:34 AM
The problem was de property order generated by Type.GetProperties() method. The GetParseTree internal method is used to generate datacontext for each segment/element in the source. But it uses reflection to get all properties for the segment/element.

The segment BIG, has the data element 373 at the positions : 1 - 3. When reflection is used to get the properties for this segment, then de properties are obteined in an incorrect order; instead of get:
  • D_373_1
  • D_76_2
  • D_373_3
  • D_324_4
I get :
  • D_373_1
  • D_373_3
  • D_76_2
  • D_324_4
This bad-sorting causes that the generated EDI file results in a data-element order issue. The solution that i found is order the properties before generate the context.

On the file EdiFabric / Framework / Helpers / ParserHelper
        private static ParseTree GetParseTree(string typeName, string assemblyName, Func<ParseTree, bool> limit)
        {
            if (string.IsNullOrEmpty(typeName)) throw new ArgumentNullException("typeName");
            if (limit == null) throw new ArgumentNullException("limit");
            if (assemblyName == null) assemblyName = string.Empty;

            var ediElement = Type.GetType(typeName + assemblyName);
            
            

            if (ediElement == null)
            {
                throw new ParserException("Can't find defnition for " + typeName);
            }

            var result = new ParseTree
                {
                    Name = ediElement.Name,
                    Children = new List<ParseTree>(),
                    TypeName = typeName,
                    AssemblyName = assemblyName
                };

            if (limit(result))
            {
                var properties = ediElement.GetProperties();

                // order by key, only if this  property is an segment
                if (ediElement.Name.StartsWith("S_")) {
                    Dictionary<Int32, PropertyInfo> dictionary_properties = new Dictionary<int, PropertyInfo>();
                    var sorted_properties = new List<PropertyInfo>();

                    foreach (var prop in properties)
                    {
                        Int32 reference = 1;

                        // get the position reference only if the property is an data-element.
                        if (prop.Name.StartsWith("D_"))
                        {
                            String name = prop.Name.Split("_".ToCharArray())[2];

                            Int32.TryParse(name, out reference);
                        }
                        else {
                            // generate an index if the property is a compound element
                            reference = dictionary_properties.Keys.Count + 1;
                        }

                        dictionary_properties.Add(reference, prop);
                    }

                    // order keys
                    var keys_sorted = dictionary_properties.Keys.ToList();
                    keys_sorted.Sort();

                    // use the ordered keys for order the properties
                    foreach (Int32 key in keys_sorted)
                    {
                        sorted_properties.Add(dictionary_properties[key]);
                    }

                    properties = sorted_properties.ToArray();
                }

                foreach (var propertyInfo in properties)
                {
                    var childTypeName = propertyInfo.PropertyType.FullName;

                    if (typeof(IList).IsAssignableFrom(propertyInfo.PropertyType)
                        && propertyInfo.PropertyType.IsGenericType)
                    {
                        childTypeName = propertyInfo.PropertyType.GetGenericArguments()[0].FullName;
                    }

                    var child = propertyInfo.PropertyType.FullName == "System.String"
                                    ? new ParseTree { Name = propertyInfo.Name }
                                    : GetParseTree(childTypeName, assemblyName, limit);

                    child.Parent = result;
                    result.Children.Add(child);
                }

            }

            return result;
        }
Coordinator
Apr 7, 2014 at 7:37 PM
Thank you for that, very well spotted. I will bookmark this for addition to the next release.

Kamen
Coordinator
Apr 30, 2014 at 9:17 AM
This has now been resolved in Release 2.0
It was a major bug (the most striking so far) and was resolved by decorating the public properties in the definition file with xmlelement order attribute.

Thank you again for raising this.

Cheers,
Kamen