/// <summary>
        /// Handles the execution exception.
        /// </summary>
        /// <param name="exception">The exception.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public async Task <MessagingContext> HandleExecutionException(Exception exception, MessagingContext context)
        {
            Logger.Error(exception.Message);

            using (DatastoreContext db = _createContext())
            {
                await db.TransactionalAsync(async ctx =>
                {
                    var repository = new DatastoreRepository(ctx);
                    var service    = new ExceptionService(_configuration, repository, _bodyStore);

                    InException entity =
                        context.SubmitMessage != null
                            ? await service.InsertIncomingSubmitExceptionAsync(exception, context.SubmitMessage, context.ReceivingPMode)
                            : await service.InsertIncomingAS4MessageExceptionAsync(exception, context.EbmsMessageId, context.ReceivingPMode);

                    await ctx.SaveChangesAsync();

                    service.InsertRelatedRetryReliability(entity, context.ReceivingPMode?.ExceptionHandling?.Reliability);
                    await ctx.SaveChangesAsync();
                });
            }

            return(new MessagingContext(exception)
            {
                ErrorResult = context.ErrorResult
            });
        }
        public async Task ExceptionOperationIsCorrectlyPersisted()
        {
            long savedId;

            using (var db = GetDataStoreContext())
            {
                var inException = InException.ForEbmsMessageId("message-id", "some-error-happened");
                inException.Operation = Operation.Sent;

                db.InExceptions.Add(inException);

                await db.SaveChangesAsync();

                savedId = inException.Id;

                Assert.NotEqual(default(long), savedId);
            }

            using (var db = GetDataStoreContext())
            {
                var inMessage = db.InExceptions.FirstOrDefault(i => i.Id == savedId);

                Assert.NotNull(inMessage);
                Assert.Equal(Operation.Sent, inMessage.Operation);
            }
        }
        public async Task InExceptionPModeInformationIsCorrectlyPersisted()
        {
            long savedId;

            const string pmodeId      = "pmode-id1";
            const string pmodeContent = "<pmode></pmode>";

            using (var db = GetDataStoreContext())
            {
                var inException = InException.ForEbmsMessageId("message-id", "some-error-happened");
                inException.SetPModeInformation(pmodeId, pmodeContent);

                db.InExceptions.Add(inException);

                await db.SaveChangesAsync();

                savedId = inException.Id;

                Assert.NotEqual(default(long), savedId);
            }

            using (var db = GetDataStoreContext())
            {
                var inException = db.InExceptions.FirstOrDefault(i => i.Id == savedId);

                Assert.NotNull(inException);
                Assert.Equal(pmodeId, inException.PModeId);
                Assert.Equal(pmodeContent, inException.PMode);
            }
        }
Beispiel #4
0
        private static InException CreateInException(string ebmsMessageId, DateTimeOffset insertionTime)
        {
            InException ex = InException.ForEbmsMessageId(ebmsMessageId, exception: string.Empty);

            ex.InsertionTime = insertionTime;

            return(ex);
        }
Beispiel #5
0
        /// <summary>
        /// Insert an <see cref="InException"/> based on an exception that occured during an incoming operation for which we do not have a valid/complete message.
        /// Example: transformation.
        /// </summary>
        /// <param name="exception">The exception which message will be inserted.</param>
        /// <param name="messageStream">The stream that represents the message which caused the exception.</param>
        public async Task InsertIncomingExceptionAsync(Exception exception, Stream messageStream)
        {
            string location = await _bodyStore.SaveAS4MessageStreamAsync(
                _config.InExceptionStoreLocation,
                messageStream);

            InException entity = InException.ForMessageBody(location, exception);

            _repository.InsertInException(entity);
        }
Beispiel #6
0
        /// <summary>
        /// Insert a given <see cref="InException"/> into the Data store.</summary>
        /// <param name="inException"></param>
        public void InsertInException(InException inException)
        {
            if (inException == null)
            {
                throw new ArgumentNullException(nameof(inException));
            }

            inException.ModificationTime = DateTimeOffset.Now;
            inException.InsertionTime    = DateTimeOffset.Now;

            _datastoreContext.InExceptions.Add(inException);
        }
        public async void ThenInExceptionIsTransformedToNotifyEnvelope()
        {
            // Arrange
            ReceivedEntityMessage receivedMessage = CreateReceivedExceptionMessage(InException.ForEbmsMessageId("id", "error"), Operation.ToBeNotified);
            var transformer = new NotifyMessageTransformer();
            var result      = await transformer.TransformAsync(receivedMessage);

            Assert.NotNull(result.NotifyMessage);
            Assert.Equal(
                ((ExceptionEntity)receivedMessage.Entity).EbmsRefToMessageId,
                result.NotifyMessage.MessageInfo.RefToMessageId);
        }
Beispiel #8
0
        /// <summary>
        /// Updates a single <see cref="InException"/> for a given <paramref name="id"/>.
        /// </summary>
        /// <param name="id">The identifier to locate the <see cref="InException"/> entity</param>
        /// <param name="update">The update function to change the <see cref="InException"/> entity</param>
        public void UpdateInException(long id, Action <InException> update)
        {
            if (update == null)
            {
                throw new ArgumentNullException(nameof(update));
            }

            InException entity = _datastoreContext.InExceptions.Single(ex => ex.Id == id);

            update(entity);

            entity.ModificationTime = DateTimeOffset.Now;
        }
        public async void ThenTransformSucceedsWithValidInExceptionForErrorProperties()
        {
            // Arrange
            ReceivedEntityMessage receivedMessage = CreateReceivedExceptionMessage(InException.ForEbmsMessageId("id", "error"), Operation.ToBeNotified);
            var transformer = new NotifyMessageTransformer();

            // Act
            MessagingContext messagingContext =
                await transformer.TransformAsync(receivedMessage);

            // Assert
            Assert.Equal(Status.Exception, messagingContext.NotifyMessage.StatusCode);
            Assert.Equal(((InException)receivedMessage.Entity).EbmsRefToMessageId, messagingContext.NotifyMessage.MessageInfo.RefToMessageId);
        }
Beispiel #10
0
        /// <summary>
        /// Insert an <see cref="InException"/> based on an exception that occured during the incoming processing of an <see cref="AS4Message"/>.
        /// </summary>
        /// <param name="exception">The exception which message will be inserted.</param>
        /// <param name="ebmsMessageId">The primary message id of the <see cref="AS4Message"/> that caused the exception.</param>
        /// <param name="pmode">The PMode that was being used during the processing.</param>
        public async Task <InException> InsertIncomingAS4MessageExceptionAsync(Exception exception, string ebmsMessageId, ReceivingProcessingMode pmode)
        {
            InException entity =
                InException
                .ForEbmsMessageId(ebmsMessageId, exception)
                .SetOperationFor(pmode?.ExceptionHandling);

            await entity.SetPModeInformationAsync(pmode);

            _repository.InsertInException(entity);
            _repository.UpdateInMessage(ebmsMessageId, m => m.SetStatus(InStatus.Exception));

            return(entity);
        }
        private async Task <MessagingContext> HandleNotifyException(Exception exception, MessagingContext context)
        {
            Logger.Error(exception.Message);

            using (var dbContext = _createContext())
            {
                var repository = new DatastoreRepository(dbContext);

                if (context.NotifyMessage.EntityType == typeof(InMessage) ||
                    context.NotifyMessage.EntityType == typeof(InException))
                {
                    var inException = InException.ForEbmsMessageId(context.EbmsMessageId, exception);
                    repository.InsertInException(inException);

                    if (context.NotifyMessage.EntityType == typeof(InMessage))
                    {
                        Logger.Debug("Fatal fail in notification, set InMessage(s).Status=Exception");
                        repository.UpdateInMessage(context.EbmsMessageId, i => i.SetStatus(InStatus.Exception));
                    }
                }
                else if (context.NotifyMessage.EntityType != typeof(OutMessage) ||
                         context.NotifyMessage.EntityType == typeof(OutException))
                {
                    var outException = OutException.ForEbmsMessageId(context.EbmsMessageId, exception);
                    repository.InsertOutException(outException);

                    if (context.NotifyMessage.EntityType == typeof(OutMessage) &&
                        context.MessageEntityId != null)
                    {
                        Logger.Debug("Fatal fail in notification, set OutMessage.Status=Exception");
                        repository.UpdateOutMessage(
                            context.MessageEntityId.Value,
                            o => o.SetStatus(OutStatus.Exception));
                    }
                }

                if (context.MessageEntityId != null)
                {
                    Logger.Debug("Abort retry operation due to fatal notification exception, set Status=Completed");
                    repository.UpdateRetryReliability(
                        context.MessageEntityId.Value,
                        r => r.Status = RetryStatus.Completed);
                }

                await dbContext.SaveChangesAsync();
            }

            return(new MessagingContext(exception));
        }
        private async Task InsertReferencedInException(
            MessagingContext messagingContext,
            CancellationToken cancellation)
        {
            using (DatastoreContext context = _createContext())
            {
                var repository = new DatastoreRepository(context);
                var exception  = InException.ForEbmsMessageId(
                    messagingContext.AS4Message?.FirstSignalMessage?.RefToMessageId,
                    new Exception(messagingContext.ErrorResult.Description));

                repository.InsertInException(exception);
                await context.SaveChangesAsync(cancellation).ConfigureAwait(false);
            }
        }
            public async Task ThenInsertInExceptionSucceeds()
            {
                // Arrange
                var inException = InException.ForEbmsMessageId($"inex-{Guid.NewGuid()}", "error");

                // Act
                using (DatastoreContext context = GetDataStoreContext())
                {
                    new DatastoreRepository(context).InsertInException(inException);

                    await context.SaveChangesAsync();
                }

                GetDataStoreContext.AssertInException(inException.EbmsRefToMessageId, Assert.NotNull);
            }
Beispiel #14
0
        public async Task InException_Is_Set_To_Notified_When_Retry_Happen_Within_Allowed_MaxRetry(
            HttpStatusCode secondAttempt,
            Operation expected)
        {
            await TestComponentWithSettings(
                "inexception_notify_reliability_settings.xml",
                async (settings, as4Msh) =>
            {
                // Arrange
                var handler = new InboundExceptionHandler(
                    () => new DatastoreContext(as4Msh.GetConfiguration()),
                    as4Msh.GetConfiguration(),
                    Registry.Instance.MessageBodyStore);

                const string url     = "http://localhost:7071/business/inexception/";
                string ebmsMessageId = $"entity-{Guid.NewGuid()}";

                // Act
                await handler.HandleExecutionException(
                    new Exception("This is an test exception"),
                    new MessagingContext(
                        new ReceivedEntityMessage(new InMessage(ebmsMessageId)),
                        MessagingContextMode.Deliver)
                {
                    ReceivingPMode = NotifyExceptionReceivePMode(url)
                });

                // Assert
                SimulateNotifyFailureOnFirstAttempt(url, secondAttempt);

                var spy = new DatabaseSpy(as4Msh.GetConfiguration());
                InException notified = await PollUntilPresent(
                    () => spy.GetInExceptions(
                        ex => ex.Operation == expected).FirstOrDefault(),
                    timeout: TimeSpan.FromSeconds(10));

                Entities.RetryReliability referenced = await PollUntilPresent(
                    () => spy.GetRetryReliabilityFor(r => r.RefToInExceptionId == notified.Id),
                    timeout: TimeSpan.FromSeconds(5));
                Assert.Equal(RetryStatus.Completed, referenced.Status);
            });
        }
Beispiel #15
0
        /// <summary>
        /// Insert an <see cref="InException"/> based on an exception that occurred dring the incoming Submit operation.
        /// </summary>
        /// <param name="exception">The exception which message will be inserted.</param>
        /// <param name="submit">The original message that caused the exception.</param>
        /// <param name="pmode">The PMode that was being used during the Submit operation.</param>
        public async Task <InException> InsertIncomingSubmitExceptionAsync(
            Exception exception,
            SubmitMessage submit,
            ReceivingProcessingMode pmode)
        {
            Stream stream = await AS4XmlSerializer.ToStreamAsync(submit);

            string location = await _bodyStore.SaveAS4MessageStreamAsync(
                _config.InExceptionStoreLocation,
                stream);

            InException entity =
                InException
                .ForMessageBody(messageLocation: location, exception: exception)
                .SetOperationFor(pmode?.ExceptionHandling);

            await entity.SetPModeInformationAsync(pmode);

            _repository.InsertInException(entity);

            return(entity);
        }
Beispiel #16
0
        private async Task InsertInExceptionsForNowExceptionedInMessageAsync(
            IEnumerable <SignalMessage> signalMessages,
            ErrorResult occurredError,
            ReceivingProcessingMode receivePMode)
        {
            if (signalMessages.Any() == false)
            {
                return;
            }

            using (DatastoreContext dbContext = _createDatastoreContext())
            {
                var repository = new DatastoreRepository(dbContext);

                foreach (SignalMessage signal in signalMessages.Where(s => !(s is PullRequest)))
                {
                    var ex = InException.ForEbmsMessageId(signal.MessageId, occurredError.Description);
                    await ex.SetPModeInformationAsync(receivePMode);

                    Logger.Debug(
                        $"Insert InException for {signal.GetType().Name} {signal.MessageId} with {{Exception={occurredError.Description}}}");

                    repository.InsertInException(ex);
                }

                IEnumerable <string> ebmsMessageIds = signalMessages.Select(s => s.MessageId).ToArray();
                repository.UpdateInMessages(
                    m => ebmsMessageIds.Contains(m.EbmsMessageId),
                    m =>
                {
                    Logger.Debug($"Update {m.EbmsMessageType} InMessage {m.EbmsMessageId} Status=Exception");
                    m.SetStatus(InStatus.Exception);
                });

                await dbContext.SaveChangesAsync();
            }
        }
Beispiel #17
0
        /// <summary>
        /// Insert a <see cref="RetryReliability"/> record for an stored <see cref="InException"/> record.
        /// </summary>
        /// <param name="referenced">The referenced exception record.</param>
        /// <param name="reliability">Reliability to populate the record with retry information.</param>
        public void InsertRelatedRetryReliability(InException referenced, RetryReliability reliability)
        {
            if (referenced == null)
            {
                throw new ArgumentNullException(nameof(referenced));
            }

            if (referenced.Id <= 0)
            {
                throw new InvalidOperationException(
                          "Requires to have a stored InException to insert a referenced RetryReliability record");
            }

            if (reliability != null && reliability.IsEnabled)
            {
                var r = Entities.RetryReliability.CreateForInException(
                    refToInExceptionId: referenced.Id,
                    maxRetryCount: reliability.RetryCount,
                    retryInterval: reliability.RetryInterval.AsTimeSpan(),
                    type: RetryType.Notification);

                _repository.InsertRetryReliability(r);
            }
        }
Beispiel #18
0
 /// <summary>
 /// Inserts the given <see cref="InException"/> into the <see cref="DatastoreContext"/>.
 /// </summary>
 /// <param name="ex">The message.</param>
 public void InsertInException(InException ex) => ChangeContext(ctx => ctx.InExceptions.Add(ex));
        protected virtual void SetupDataStore()
        {
            using (datastoreContext = new DatastoreContext(options, StubConfig.Default))
            {
                string pmodeString = AS4XmlSerializer.ToString(pmode);
                string pmodeId     = pmode.Id;

                {
                    var message = new InMessage(ebmsMessageId: InEbmsMessageId1)
                    {
                        EbmsRefToMessageId = InEbmsRefToMessageId1,
                        InsertionTime      = DateTime.UtcNow.AddMinutes(-1),
                    };
                    message.SetStatus(InStatus.Created);
                    message.SetPModeInformation(pmodeId, pmodeString);
                    datastoreContext.InMessages.Add(message);
                }

                {
                    var message = new InMessage(ebmsMessageId: InEbmsMessageId2)
                    {
                        EbmsRefToMessageId = InEbmsRefToMessageId2,
                        InsertionTime      = DateTime.UtcNow.AddMinutes(-1)
                    };
                    message.SetStatus(InStatus.Received);
                    datastoreContext.InMessages.Add(message);
                }

                {
                    var message = new OutMessage(OutEbmsMessageId1)
                    {
                        EbmsRefToMessageId = OutEbmsRefToMessageId1,
                        InsertionTime      = DateTime.UtcNow.AddMinutes(-1)
                    };
                    message.SetStatus(OutStatus.Created);

                    datastoreContext.OutMessages.Add(message);
                }

                {
                    var message = new OutMessage(OutEbmsMessageId2)
                    {
                        EbmsRefToMessageId = OutEbmsRefToMessageId2,

                        InsertionTime = DateTime.UtcNow.AddMinutes(-1)
                    };
                    message.SetStatus(OutStatus.Created);
                    datastoreContext.OutMessages.Add(message);
                }

                InException inEx1 = Entities.InException.ForEbmsMessageId(InEbmsMessageId1, InException);
                inEx1.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.InExceptions.Add(inEx1);

                InException inEx2 = Entities.InException.ForEbmsMessageId(InEbmsMessageId1, InException);
                inEx2.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.InExceptions.Add(inEx2);

                InException inEx3 = Entities.InException.ForMessageBody(MessageLocation, InException);
                inEx3.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.InExceptions.Add(inEx3);

                OutException outEx1 = Entities.OutException.ForEbmsMessageId(OutEbmsRefToMessageId1, InException);
                outEx1.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.OutExceptions.Add(outEx1);

                OutException outEx2 = OutException.ForEbmsMessageId(InEbmsRefToMessageId1, Exception);
                outEx2.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.OutExceptions.Add(outEx2);

                OutException outEx3 = OutException.ForMessageBody(MessageLocation, Exception);
                outEx3.InsertionTime = DateTime.UtcNow.AddMinutes(-1);
                datastoreContext.OutExceptions.Add(outEx3);

                datastoreContext.SaveChanges();

                foreach (var inMessage in datastoreContext.InMessages)
                {
                    inMessage.SetPModeInformation(pmodeId, pmodeString);
                }

                foreach (var outMessage in datastoreContext.OutMessages)
                {
                    outMessage.SetPModeInformation(pmodeId, pmodeString);
                }

                foreach (var inException in datastoreContext.InExceptions)
                {
                    inException.SetPModeInformation(pmodeId, pmodeString);
                }

                foreach (var outException in datastoreContext.OutExceptions)
                {
                    outException.SetPModeInformation(pmodeId, pmodeString);
                }

                datastoreContext.SaveChanges();
            }
        }
        /// <summary>
        /// Inserts the in exception.
        /// </summary>
        /// <param name="createContext">The create context.</param>
        /// <param name="inException">The in exception.</param>
        public static InException InsertInException(this Func <DatastoreContext> createContext, InException inException)
        {
            using (DatastoreContext context = createContext())
            {
                context.InExceptions.Add(inException);
                context.SaveChanges();

                return(inException);
            }
        }