示例#1
0
        public void TestSerializationOfMessageErrorContext()
        {
            var segContext1 = new SegmentErrorContext("Name", 66, ErrorCodes.ComponentDataElementsTooMany);

            segContext1.Add(ErrorCodes.DataElementsTooMany);
            segContext1.Add("Name1", 66, ErrorCodes.ComponentDataElementsTooMany, 32, 96, "876");
            segContext1.Add("Name2", 88, ErrorCodes.ControlNumberNotMatching, 16, 48, "438");

            var segContext2 = new SegmentErrorContext("Name2", 32, ErrorCodes.ComponentDataElementsTooMany);

            segContext2.Add(ErrorCodes.DataElementsTooMany);
            segContext2.Add("Name1", 66, ErrorCodes.ComponentDataElementsTooMany, 16, 48, "476");
            segContext2.Add("Name2", 88, ErrorCodes.ControlNumberNotMatching, 5, 5, "200");

            var msgContext = new MessageErrorContext("MsgError", "111111");

            msgContext.Add(ErrorCodes.DataElementsTooMany);
            msgContext.Add(segContext1);
            msgContext.Add(segContext2);


            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream    stream    = new MemoryStream();

            formatter.Serialize(stream, msgContext);
            stream.Seek(0, SeekOrigin.Begin);
            var copy = (MessageErrorContext)formatter.Deserialize(stream);

            AssertTwoMessageErrorsAreEqual(msgContext, copy);
        }
示例#2
0
        /// <summary>
        /// Validates EDI document instance.
        /// </summary>
        /// <param name="message">The EDI document instance.</param>
        /// <returns>A collection of validation errors.</returns>
        /// <exception cref="Exception">Throws an exception if the instance is not a valid ediFabric spec.</exception>
        public ValidationException Validate(object message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message");
            }

            string messageName   = null;
            string controlNumber = null;

            try
            {
                var xDoc = Serialize(message);
                if (xDoc.Root == null)
                {
                    throw new Exception("Failed to serialize instance.");
                }

                string format;
                if (!TryGetMessageContext(xDoc.Root, out messageName, out controlNumber, out format))
                {
                    throw new Exception("Failed to extract message name or control number.");
                }

                if (XsdCache.Count > XsdCacheMax)
                {
                    XsdCache.Clear();
                }

                var schemas = XsdCache.GetOrAdd(message.GetType().FullName,
                                                key => NewSchemaSet(_xsdStream(new MessageContext(message)), xDoc.Root.Name.Namespace.NamespaceName));

                var messageContext = new MessageErrorContext(messageName, controlNumber);
                xDoc.Validate(schemas,
                              (o, e) =>
                {
                    var errorCode      = MapErrorCode(GetErrorCode(e));
                    var segmentContext = BuildContext(o as XElement, schemas, errorCode);
                    messageContext.Add(segmentContext);
                });

                foreach (var code in ValidateStructure(xDoc.Root, controlNumber, format))
                {
                    messageContext.Add(code);
                }

                return(new ValidationException("Validation successful.", messageContext));
            }
            catch (Exception ex)
            {
                if (!string.IsNullOrEmpty(messageName) && !string.IsNullOrEmpty(controlNumber))
                {
                    var messageContext = new MessageErrorContext(messageName, controlNumber);
                    messageContext.Add(ErrorCodes.Unknown);
                    return(new ValidationException("Validation failed.", messageContext, ex));
                }

                return(new ValidationException("Validation failed.", null, ex));
            }
        }
示例#3
0
 /// <summary>
 /// Initializes a new instance of the <see cref="MessageEventArgs{T, U}"/> class.
 /// </summary>
 /// <param name="message">The EDI message.</param>
 /// <param name="errorContext">The message error context.</param>
 /// <param name="groupHeader">The group header.</param>
 /// <param name="interchangeHeader">The interchange header.</param>
 /// <param name="inDuplicateGroup">Detects if the message is part of a duplicate group.</param>
 /// <param name="inDuplicateInterchange">Detects if the message is part of a duplicate interchange.</param>
 protected MessageEventArgs(T interchangeHeader, U groupHeader, EdiMessage message, MessageErrorContext errorContext,
                            bool inDuplicateGroup, bool inDuplicateInterchange)
 {
     InterchangeHeader      = interchangeHeader;
     GroupHeader            = groupHeader;
     Message                = message;
     ErrorContext           = errorContext;
     InDuplicateGroup       = inDuplicateGroup;
     InDuplicateInterchange = inDuplicateInterchange;
 }
示例#4
0
        public void TestSerializationOfParsingException()
        {
            var segContext1 = new SegmentErrorContext("Name", 66, ErrorCodes.ComponentDataElementsTooMany);

            segContext1.Add(ErrorCodes.DataElementsTooMany);
            segContext1.Add("Name1", 66, ErrorCodes.ComponentDataElementsTooMany, 32, 96, "876");
            segContext1.Add("Name2", 88, ErrorCodes.ControlNumberNotMatching, 16, 48, "438");

            var segContext2 = new SegmentErrorContext("Name2", 32, ErrorCodes.ComponentDataElementsTooMany);

            segContext2.Add(ErrorCodes.DataElementsTooMany);
            segContext2.Add("Name1", 66, ErrorCodes.ComponentDataElementsTooMany, 16, 48, "476");
            segContext2.Add("Name2", 88, ErrorCodes.ControlNumberNotMatching, 5, 5, "200");

            var msgContext = new MessageErrorContext("MsgError", "111111");

            msgContext.Add(ErrorCodes.DataElementsTooMany);
            msgContext.Add(segContext1);
            msgContext.Add(segContext2);

            ParsingException ex;

            try
            {
                throw new ParsingException(ErrorCodes.SegmentWithErrors, "message", "HL*1*0*20*1~", msgContext);
            }
            catch (ParsingException thrown)
            {
                ex = thrown;
            }

            BinaryFormatter formatter = new BinaryFormatter();
            MemoryStream    stream    = new MemoryStream();

            formatter.Serialize(stream, ex);
            stream.Seek(0, SeekOrigin.Begin);
            var copy = (ParsingException)formatter.Deserialize(stream);

            //var copy = new ParsingException(ErrorCodes.ControlNumberNotMatching, "message2");

            AssertTwoParsingExceptionsAreEqual(ex, copy);
        }
示例#5
0
        void AssertTwoMessageErrorsAreEqual(MessageErrorContext context, MessageErrorContext other)
        {
            Assert.AreEqual(context.Name, other.Name, "Name");
            Assert.AreEqual(context.ControlNumber, other.ControlNumber, "Position");

            Assert.AreEqual(context.Codes.Count, other.Codes.Count);
            var contextCodesArray = other.Codes.ToArray();
            var copyCodesArray    = context.Codes.ToArray();

            for (int i = 0; i < context.Codes.Count; i++)
            {
                Assert.AreEqual(copyCodesArray[i], contextCodesArray[i]);
            }

            Assert.AreEqual(context.Errors.Count, other.Errors.Count);
            var copyErrorsArray    = context.Errors.ToArray();
            var contextErrorsArray = other.Errors.ToArray();

            for (int i = 0; i < context.Errors.Count; i++)
            {
                AssertTwoSegmentErrorsAreEqual(contextErrorsArray[i], copyErrorsArray[i]);
            }
        }
示例#6
0
        /// <summary>
        /// Validates a message according to its validation attributes.
        /// </summary>
        /// <param name="result">The resulting message context.</param>
        /// <param name="skipTrailer">Whether to validate the trailer. Skip when validating custom created messages.</param>
        /// <returns>Whether the message is valid or not. If not valid then the message error context will contain the reasons.</returns>
        public bool IsValid(out MessageErrorContext result, bool skipTrailer = false)
        {
            result = new MessageErrorContext(Name, ControlNumber, Version, MessagePart, null);

            int segmentsNum;

            result.AddRange(this.Validate(out segmentsNum));

            if (!skipTrailer)
            {
                foreach (var errorCode in ValidateStructure(segmentsNum))
                {
                    result.Add(errorCode);
                }
            }

            if (HasErrors)
            {
                result.AddRange(ErrorContext.Errors);
                result.AddRange(ErrorContext.Codes);
            }

            return(!result.HasErrors);
        }
示例#7
0
        public MessageErrorContext Analyze(IEnumerable <SegmentContext> segments, MessageContext messageContext,
                                           Separators separators, int partsIndex, int segmentIndex)
        {
            var errorContext = new MessageErrorContext(messageContext.Name, messageContext.ControlNumber,
                                                       messageContext.Version, partsIndex,
                                                       "Message was parsed with errors.");

            var currSeg = Children.First() as Segment;
            var index   = segmentIndex;

            foreach (var segment in segments)
            {
                Segment tempSeg;
                index++;
                if (segment.IsJump)
                {
                    tempSeg =
                        this.Descendants <Segment>()
                        .LastOrDefault(
                            d => d.EdiName == "HL" && d.Children.Count > 1 && d.Children.ElementAt(1).Value == segment.SecondValue);

                    if (tempSeg != null)
                    {
                        currSeg = tempSeg;
                    }
                }

                tempSeg = currSeg.TraverseDepthFirst().FirstOrDefault(n => n.Match(segment));
                if (tempSeg == null)
                {
                    var      errorCode       = SegmentErrorCode.SegmentNotInProperSequence;
                    TypeInfo type            = null;
                    var      notFoundSegment = this.Descendants <Segment>().FirstOrDefault(d => d.EdiName == segment.Name);
                    if (notFoundSegment == null)
                    {
                        errorCode = SegmentErrorCode.UnrecognizedSegment;
                    }
                    else
                    {
                        type = notFoundSegment.TypeInfo;
                    }

                    errorContext.Add(new SegmentErrorContext(segment.Name, index, type,
                                                             segment.Value, errorCode));

                    if (messageContext.PartialAllowed)
                    {
                        // ReSharper disable once RedundantAssignment
                        tempSeg = currSeg;
                        continue;
                    }

                    return(errorContext);
                }

                currSeg = tempSeg;

                if (currSeg.IsParsed)
                {
                    currSeg = (Segment)currSeg.InsertRepetition();
                }

                try
                {
                    if (separators == null)
                    {
                        currSeg.Parse(segment.Value, messageContext.PartialAllowed);
                    }
                    else
                    {
                        currSeg.Parse(segment.Value, separators, messageContext.PartialAllowed);
                    }
                }
                catch (ParserSegmentException ex)
                {
                    var segmentContext = new SegmentErrorContext(segment.Name, index, currSeg.TypeInfo, segment.Value);
                    segmentContext.Add(ex.ErrorContext);
                    errorContext.Add(segmentContext);

                    if (messageContext.PartialAllowed)
                    {
                        continue;
                    }

                    return(errorContext);
                }
            }

            return(errorContext.HasErrors ? errorContext : null);
        }
示例#8
0
        private void ReadAttributes(Func <MessageContext, Assembly> rulesAssembly)
        {
            if (rulesAssembly == null)
            {
                throw new ArgumentNullException("rulesAssembly");
            }

            if (MessageType != null)
            {
                return;
            }

            Assembly assembly;

            try
            {
                assembly = rulesAssembly(this);
            }
            catch (Exception ex)
            {
                var errorContext = new MessageErrorContext(Name, ControlNumber, Version, 0, ex.Message,
                                                           MessageErrorCode.TransactionSetNotSupported);
                throw new ParserMessageException(errorContext);
            }

            var matches = assembly.GetTypes().Where(m =>
            {
                var att = ((MessageAttribute)m.GetTypeInfo().GetCustomAttribute(typeof(MessageAttribute)));
                if (att == null)
                {
                    return(false);
                }

                if (att.Format == Format && att.Version == Version && att.Id == Name)
                {
                    PartialAllowed = att.IsEvaluation;
                    SplitterRegex  = att.SplitterRegex;
                    return(true);
                }
                return(false);
            }).ToList();

            var attribute = "[Message(" + Format + ", " + Version + ", " + Name + ")]";

            if (!matches.Any())
            {
                var msg = String.Format("Type with attribute'{0}' was not found in assembly '{1}'.", attribute,
                                        assembly.FullName);

                var errorContext = new MessageErrorContext(Name, ControlNumber, Version, 0, msg,
                                                           MessageErrorCode.TransactionSetNotSupported);
                throw new ParserMessageException(errorContext);
            }

            if (matches.Count > 1)
            {
                var msg = String.Format("Multiple types with attribute'{0}' were found in assembly '{1}'.", attribute,
                                        assembly.FullName);

                var errorContext = new MessageErrorContext(Name, ControlNumber, Version, 0, msg,
                                                           MessageErrorCode.TransactionSetNotSupported);
                throw new ParserMessageException(errorContext);
            }

            MessageType = matches.First().GetTypeInfo();
        }
示例#9
0
        internal static void ParseSegment(this ParseNode parseNode, string line, Separators separators, MessageErrorContext errorContext = null)
        {
            if (parseNode == null)
            {
                throw new ArgumentNullException("parseNode");
            }
            if (String.IsNullOrEmpty(line))
            {
                throw new ArgumentNullException("line");
            }
            if (separators == null)
            {
                throw new ArgumentNullException("separators");
            }

            if (parseNode.Prefix != Prefixes.S)
            {
                throw new Exception(String.Format("Only segments are supported: {0}", parseNode.Name));
            }

            var dataElementsGrammar = ParseNode.BuldTree(parseNode.Type, false).Children;
            var dataElements        = line.GetDataElements(separators);

            for (var deIndex = 0; deIndex < dataElements.Length; deIndex++)
            {
                var currentDataElement = dataElements[deIndex];
                if (String.IsNullOrEmpty(currentDataElement))
                {
                    continue;
                }
                if (dataElementsGrammar.Count <= deIndex)
                {
                    if (errorContext != null)
                    {
                        errorContext.Add(parseNode.EdiName, parseNode.IndexInParent() + 1, ErrorCodes.DataElementsTooMany);
                    }
                    throw new ParsingException(ErrorCodes.InvalidInterchangeContent, "Too many data elements in segment.", line, errorContext);
                }

                var currentDataElementGrammar = dataElementsGrammar.ElementAt(deIndex);

                var repetitions = currentDataElementGrammar.IsX12RepetitionSeparator()
                    ? new[] { currentDataElement }
                    : currentDataElement.GetRepetitions(separators);
                foreach (var repetition in repetitions)
                {
                    if (String.IsNullOrEmpty(repetition))
                    {
                        continue;
                    }

                    var childParseNode = parseNode.AddChild(currentDataElementGrammar.Type,
                                                            currentDataElementGrammar.Name,
                                                            currentDataElementGrammar.Prefix == Prefixes.D ? repetition.UnEscapeLine(separators) : null);

                    if (currentDataElementGrammar.Prefix != Prefixes.C)
                    {
                        continue;
                    }

                    var componentDataElementsGrammar = currentDataElementGrammar.Children;
                    var componentDataElements        = repetition.GetComponentDataElements(separators);
                    for (var cdeIndex = 0; cdeIndex < componentDataElements.Length; cdeIndex++)
                    {
                        var currentComponentDataElement = componentDataElements[cdeIndex];
                        if (String.IsNullOrEmpty(currentComponentDataElement))
                        {
                            continue;
                        }

                        var currentComponentDataElementGrammar = componentDataElementsGrammar.ElementAt(cdeIndex);
                        if (componentDataElementsGrammar.Count <= cdeIndex)
                        {
                            if (errorContext != null)
                            {
                                errorContext.Add(parseNode.EdiName, parseNode.IndexInParent() + 1,
                                                 currentComponentDataElementGrammar.Name,
                                                 currentDataElementGrammar.IndexInParent() + 1,
                                                 ErrorCodes.ComponentDataElementsTooMany,
                                                 currentComponentDataElementGrammar.IndexInParent() + 1,
                                                 repetitions.ToList().IndexOf(repetition) + 1, currentComponentDataElement);
                            }

                            throw new ParsingException(ErrorCodes.InvalidInterchangeContent,
                                                       "Too many component data elements.", line, errorContext);
                        }

                        childParseNode.AddChild(currentComponentDataElementGrammar.Type,
                                                currentComponentDataElementGrammar.Name,
                                                currentComponentDataElement.UnEscapeLine(separators));
                    }
                }
            }
        }
示例#10
0
        internal static object Analyze(this List <SegmentContext> segments, Separators separators,
                                       MessageContext messageContext)
        {
            if (segments == null)
            {
                throw new ArgumentNullException("segments");
            }
            if (separators == null)
            {
                throw new ArgumentNullException("separators");
            }
            if (messageContext == null)
            {
                throw new ArgumentNullException("messageContext");
            }

            var messageGrammar = ParseNode.BuldTree(messageContext.SystemType, true);

            if (messageGrammar.Prefix != Prefixes.M)
            {
                throw new Exception(String.Format("Only messages are supported: {0}", messageGrammar.Name));
            }

            var errorContext     = new MessageErrorContext(messageContext.Tag, messageContext.ControlNumber);
            var segmentPosition  = messageGrammar.Children.First();
            var instancePosition = new ParseNode(messageContext.SystemType);

            foreach (var segment in segments)
            {
                if (segment.IsControl)
                {
                    continue;
                }

                Logger.Log(String.Format("Segment to match: {0}", segment.LogName));
                // Jump back to HL segment if needed
                if (segment.IsJump)
                {
                    try
                    {
                        segmentPosition = messageGrammar.JumpToHl(instancePosition.Root(), segment.ParentId);
                    }
                    catch (Exception ex)
                    {
                        errorContext.Add(segment.Name, segments.IndexOf(segment) + 1, ErrorCodes.UnexpectedSegment);
                        throw new ParsingException(ErrorCodes.InvalidInterchangeContent,
                                                   "Unable to resolve HL.", ex, segment.Value, errorContext);
                    }
                }

                var currSeg = segmentPosition.TraverseSegmentsDepthFirst().FirstOrDefault(n => n.IsEqual(segment));
                if (currSeg == null)
                {
                    if (messageGrammar.Descendants().All(d => d.EdiName != segment.Name))
                    {
                        errorContext.Add(segment.Name, segments.IndexOf(segment) + 1, ErrorCodes.UnrecognizedSegment);
                        throw new ParsingException(ErrorCodes.InvalidInterchangeContent,
                                                   "Segment is not supported in rules class.", segment.Value, errorContext);
                    }

                    errorContext.Add(segment.Name, segments.IndexOf(segment) + 1, ErrorCodes.UnexpectedSegment);
                    throw new ParsingException(ErrorCodes.InvalidInterchangeContent,
                                               "Segment was not in the correct position according to the rules class.", segment.Value,
                                               errorContext);
                }

                var segmentTree = currSeg.AncestorsToIntersection(segmentPosition);
                instancePosition =
                    instancePosition.AncestorsAndSelf().Last(nt => nt.Name == segmentTree.First().Parent.Name);
                foreach (var parseTree in segmentTree)
                {
                    instancePosition = instancePosition.AddChild(parseTree.Type, parseTree.Type.Name);
                    if (parseTree.Prefix == Prefixes.S)
                    {
                        instancePosition.ParseSegment(segment.Value, separators, errorContext);
                    }
                }
                segmentPosition = currSeg;
                Logger.Log(String.Format("Matched segment: {0}", segmentPosition.Name));
            }

            return(instancePosition.Root().ToInstance());
        }
示例#11
0
 public ParserMessageException(MessageErrorContext messageErrorContext)
     : base(messageErrorContext.Message)
 {
     MessageErrorContext = messageErrorContext;
 }