/// <summary> /// Execute the step for a given <paramref name="messagingContext" />. /// </summary> /// <param name="messagingContext">Message used during the step execution.</param> /// <returns></returns> public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { var pullRequest = messagingContext?.AS4Message?.FirstSignalMessage as PullRequest; if (pullRequest == null) { throw new InvalidMessageException( "The received message is not a PullRequest message, " + "therefore no UserMessage can be selected to return to the sender"); } (bool hasMatch, OutMessage match) = RetrieveUserMessageForPullRequest(pullRequest); if (hasMatch) { // Retrieve the existing MessageBody and put that stream in the MessagingContext. // The HttpReceiver processor will make sure that it gets serialized to the http response stream. Stream messageBody = await match.RetrieveMessageBody(_messageBodyStore).ConfigureAwait(false); messagingContext.ModifyContext( new ReceivedMessage(messageBody, match.ContentType), MessagingContextMode.Send); messagingContext.SendingPMode = AS4XmlSerializer.FromString <SendingProcessingMode>(match.PMode); return(StepResult.Success(messagingContext)); } AS4Message pullRequestWarning = AS4Message.Create(Error.CreatePullRequestWarning(IdentifierFactory.Instance.Create())); messagingContext.ModifyContext(pullRequestWarning); return(StepResult.Success(messagingContext).AndStopExecution()); }
/// <summary> /// Transform a given <see cref="ReceivedMessage"/> to a Canonical <see cref="MessagingContext"/> instance. /// </summary> /// <param name="message">Given message to transform.</param> /// /// <returns></returns> public async Task <MessagingContext> TransformAsync(ReceivedMessage message) { if (!(message is ReceivedEntityMessage)) { throw new NotSupportedException( $"Minder Deliver Transformer only supports transforming instances of type {typeof(ReceivedEntityMessage)}"); } var as4Transformer = new AS4MessageTransformer(); MessagingContext context = await as4Transformer.TransformAsync(message); var includeAttachments = true; CollaborationInfo collaborationInfo = context.ReceivingPMode?.MessagePackaging?.CollaborationInfo; if (collaborationInfo != null && (collaborationInfo.Action?.Equals("ACT_SIMPLE_ONEWAY_SIZE", StringComparison.OrdinalIgnoreCase) ?? false) && (collaborationInfo.Service?.Value?.Equals("SRV_SIMPLE_ONEWAY_SIZE", StringComparison.OrdinalIgnoreCase) ?? false)) { includeAttachments = false; } DeliverMessageEnvelope deliverMessage = CreateDeliverMessageEnvelope(context.AS4Message, includeAttachments); context.ModifyContext(deliverMessage); return(context); }
private async Task <MessagingContext> InsertReceivedAS4MessageAsync(MessagingContext messagingContext) { using (DatastoreContext context = _createDatastoreContext()) { MessageExchangePattern messageExchangePattern = messagingContext.Mode == MessagingContextMode.PullReceive ? MessageExchangePattern.Pull : MessageExchangePattern.Push; try { var service = new InMessageService(_config, new DatastoreRepository(context)); AS4Message as4Message = await service .InsertAS4MessageAsync( messagingContext.AS4Message, messagingContext.ReceivedMessage, messagingContext.SendingPMode, messageExchangePattern, _messageBodyStore) .ConfigureAwait(false); messagingContext.ModifyContext(as4Message); await context.SaveChangesAsync().ConfigureAwait(false); return(messagingContext); } catch (Exception ex) { return(new MessagingContext(ex)); } } }
/// <summary> /// Send the <see cref="AS4Message" /> /// </summary> /// <param name="messagingContext"></param> /// <returns></returns> public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { if (messagingContext == null) { throw new ArgumentNullException(nameof(messagingContext)); } if (messagingContext.ReceivedMessage == null && messagingContext.AS4Message == null) { throw new InvalidOperationException( $"{nameof(SendAS4MessageStep)} requires a MessagingContext with a ReceivedStream or an AS4Message to correctly send the message"); } if (messagingContext.ReceivedMessage == null && messagingContext.AS4Message.IsPullRequest == false) { throw new InvalidOperationException( $"{nameof(SendAS4MessageStep)} expects a PullRequest AS4Message when the MessagingContext does not contain a ReceivedStream"); } PushConfiguration pushConfig = GetPushConfiguration(messagingContext.SendingPMode, messagingContext.ReceivingPMode); if (pushConfig?.Protocol?.Url == null) { throw new ConfigurationErrorsException( "Message cannot be send because neither the Sending or Receiving PMode has a Protocol.Url child in a <PushConfiguration/> or <ResponseConfiguration/> element"); } AS4Message as4Message = await DeserializeUnderlyingStreamIfPresentAsync( messagingContext.ReceivedMessage, otherwise : messagingContext.AS4Message); try { string contentType = messagingContext.ReceivedMessage?.ContentType ?? messagingContext.AS4Message.ContentType; HttpWebRequest request = CreateWebRequest(pushConfig, contentType.Replace("charset=\"utf-8\"", "")); await WriteToHttpRequestStreamAsync(request, messagingContext).ConfigureAwait(false); messagingContext.ModifyContext(as4Message); return(await HandleHttpResponseAsync(request, messagingContext).ConfigureAwait(false)); } catch { await UpdateRetryStatusForMessageAsync(messagingContext, SendResult.RetryableFail); return(StepResult.Failed(messagingContext).AndStopExecution()); } }
/// <summary> /// It is only executed when the external message (received) is an AS4 UserMessage /// </summary> /// <param name="messagingContext"></param> public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { if (messagingContext == null) { throw new ArgumentNullException(nameof(messagingContext)); } if (messagingContext.AS4Message == null) { throw new InvalidOperationException( $"{nameof(CreateAS4ReceiptStep)} requires an AS4Message to create ebMS Receipts but no AS4Message is present in the MessagingContext"); } bool receiptSigning = messagingContext.ReceivingPMode?.ReplyHandling?.ResponseSigning?.IsEnabled ?? false; bool useNRRFormat = messagingContext.ReceivingPMode?.ReplyHandling?.ReceiptHandling?.UseNRRFormat ?? false; if (!receiptSigning && useNRRFormat) { Logger.Error( "Cannot create Non-Repudiation Receipts that aren\'t signed, please change either the " + $"ReceivingPMode {messagingContext.ReceivingPMode.Id} ReplyHandling.ReceiptHandling.UseNRRFormat or the ReplyHandling.ResponseSigning"); messagingContext.ErrorResult = new ErrorResult( "Cannot create Non-Repudiation Receipts that aren't signed", ErrorAlias.InvalidReceipt); return(StepResult.Failed(messagingContext)); } AS4Message receivedMessage = messagingContext.AS4Message; AS4Message receiptMessage = AS4Message.Empty; receiptMessage.SigningId = receivedMessage.SigningId; foreach (UserMessage userMessage in receivedMessage.UserMessages) { Receipt receipt = CreateReferencedReceipt(userMessage, receivedMessage, messagingContext.ReceivingPMode); receiptMessage.AddMessageUnit(receipt); } if (Logger.IsInfoEnabled && receiptMessage.MessageUnits.Any()) { Logger.Info($"{messagingContext.LogTag} {receiptMessage.MessageUnits.Count()} Receipt message(s) has been created for received AS4 UserMessages"); } messagingContext.ModifyContext(receiptMessage); return(await StepResult.SuccessAsync(messagingContext)); }
/// <summary> /// Transform a given <see cref="ReceivedMessage" /> to a Canonical <see cref="MessagingContext" /> instance. /// </summary> /// <param name="message">Given message to transform.</param> /// <returns></returns> public async Task <MessagingContext> TransformAsync(ReceivedMessage message) { if (message == null) { throw new ArgumentNullException(nameof(message)); } if (!(message is ReceivedEntityMessage entityMessage) || !(entityMessage.Entity is MessageEntity me)) { throw new InvalidDataException( $"The message that must be transformed should be of type {nameof(ReceivedEntityMessage)} with a {nameof(MessageEntity)} as Entity"); } MessagingContext context = await AS4MessageTransformer.TransformAsync(entityMessage); AS4Message as4Message = context.AS4Message; UserMessage toBeDeliveredUserMessage = as4Message.UserMessages.FirstOrDefault(u => u.MessageId == me.EbmsMessageId); if (toBeDeliveredUserMessage == null) { throw new InvalidOperationException( $"No UserMessage {me.EbmsMessageId} can be found in stored record for delivering"); } IEnumerable <Attachment> toBeUploadedAttachments = as4Message.Attachments .Where(a => a.MatchesAny(toBeDeliveredUserMessage.PayloadInfo)) .ToArray(); DeliverMessage deliverMessage = CreateDeliverMessage( toBeDeliveredUserMessage, toBeUploadedAttachments, context.ReceivingPMode); Logger.Info($"(Deliver) Created DeliverMessage from (first) UserMessage {as4Message.FirstUserMessage.MessageId}"); var envelope = new DeliverMessageEnvelope( message: deliverMessage, contentType: "application/xml", attachments: toBeUploadedAttachments); context.ModifyContext(envelope); return(context); }
public void OverrideMessageWithAS4Message() { // Arrange var context = new MessagingContext(AS4MessageWithEbmsMessageId(), MessagingContextMode.Unknown) { ReceivingPMode = new ReceivingProcessingMode(), SendingPMode = new SendingProcessingMode() }; // Act context.ModifyContext(AS4MessageWithoutEbmsMessageId()); // Assert Assert.Equal(AS4MessageWithoutEbmsMessageId(), context.AS4Message); Assert.NotNull(context.SendingPMode); Assert.NotNull(context.ReceivingPMode); }
/// <summary> /// Transform a given <see cref="ReceivedMessage"/> to a Canonical <see cref="MessagingContext"/> instance. /// </summary> /// <param name="message">Given message to transform.</param> /// <returns></returns> public async Task <MessagingContext> TransformAsync(ReceivedMessage message) { if (message == null) { throw new ArgumentNullException(nameof(message)); } if (!(message is ReceivedEntityMessage receivedMessage)) { throw new NotSupportedException( $"Incoming message stream from {message.Origin} that must be transformed should be of type {nameof(ReceivedEntityMessage)}"); } if (receivedMessage.Entity is ExceptionEntity ex) { string ebmsMessageId = IdentifierFactory.Instance.Create(); Error error = Error.FromErrorResult( ebmsMessageId, ex.EbmsRefToMessageId, new ErrorResult(ex.Exception, ErrorAlias.Other)); NotifyMessageEnvelope notifyEnvelope = await CreateNotifyMessageEnvelopeAsync(AS4Message.Create(error), ebmsMessageId, ex.GetType()); return(new MessagingContext(notifyEnvelope, receivedMessage)); } if (receivedMessage.Entity is MessageEntity me) { var as4Transformer = new AS4MessageTransformer(); MessagingContext ctx = await as4Transformer.TransformAsync(receivedMessage); // Normally the message shouldn't have any attachments // but to be sure we should dispose them since we don't need attachments for notifying. ctx.AS4Message.CloseAttachments(); NotifyMessageEnvelope notifyEnvelope = await CreateNotifyMessageEnvelopeAsync(ctx.AS4Message, me.EbmsMessageId, me.GetType()); ctx.ModifyContext(notifyEnvelope, receivedMessage.Entity.Id); return(ctx); } throw new InvalidOperationException(); }
/// <summary> /// Start creating <see cref="Error"/> /// </summary> /// <param name="messagingContext"></param> /// <returns></returns> /// <exception cref="System.Exception">A delegate callback throws an exception.</exception> public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { if (messagingContext == null) { throw new ArgumentNullException(nameof(messagingContext)); } if (messagingContext.AS4Message == null) { throw new InvalidOperationException( $"{nameof(CreateAS4ErrorStep)} requires an AS4Message to create an Error but no AS4Message is present in the MessagingContext"); } if (messagingContext.AS4Message.IsEmpty && messagingContext?.ErrorResult == null) { Logger.Warn("Skip creating AS4 Error because AS4Message and ErrorResult is empty in the MessagingContext"); return(await StepResult.SuccessAsync(messagingContext)); } ErrorResult errorResult = messagingContext.ErrorResult; AS4Message errorMessage = CreateAS4ErrorWithPossibleMultihop(received: messagingContext.AS4Message, occurredError: errorResult); if (errorResult != null) { Logger.Error($"AS4 Error(s) created with {errorResult.Code.GetString()} {errorResult.Alias}, {errorResult.Description}"); await InsertInExceptionsForNowExceptionedInMessageAsync( messagingContext.AS4Message.SignalMessages, messagingContext.ErrorResult, messagingContext.ReceivingPMode); } messagingContext.ModifyContext(errorMessage); if (Logger.IsInfoEnabled && errorMessage.MessageUnits.Any()) { Logger.Info( $"{messagingContext.LogTag} {errorMessage.MessageUnits.Count()} Error(s) has been created for received AS4 UserMessages"); } return(await StepResult.SuccessAsync(messagingContext)); }
/// <summary> /// Handle the given <paramref name="response" />, but delegate to the next handler if you can't. /// </summary> /// <param name="response"></param> /// <returns></returns> public async Task <StepResult> HandleResponse(IAS4Response response) { if (response == null) { throw new ArgumentNullException(nameof(response)); } MessagingContext request = response.OriginalRequest; if (request?.AS4Message?.IsPullRequest == true) { bool pullRequestWasPiggyBacked = request.AS4Message.SignalMessages.Any(s => !(s is PullRequest)); if (pullRequestWasPiggyBacked) { using (DatastoreContext ctx = _createContext()) { SendResult result = response.StatusCode == HttpStatusCode.Accepted || response.StatusCode == HttpStatusCode.OK ? SendResult.Success : SendResult.RetryableFail; var service = new PiggyBackingService(ctx); service.ResetSignalMessagesToBePiggyBacked(request.AS4Message.SignalMessages, result); await ctx.SaveChangesAsync().ConfigureAwait(false); } } bool isEmptyChannelWarning = (response.ReceivedAS4Message?.FirstSignalMessage as Error)?.IsPullRequestWarning == true; if (isEmptyChannelWarning) { request.ModifyContext(response.ReceivedAS4Message, MessagingContextMode.Send); return(StepResult.Success(response.OriginalRequest).AndStopExecution()); } } return(await _nextHandler.HandleResponse(response)); }
private static MessagingContext CreateNotifyMessage <T>(string ebmsMessageId, Entity entity) { var envelope = new NotifyMessageEnvelope( new MessageInfo { MessageId = ebmsMessageId, RefToMessageId = ebmsMessageId }, Status.Delivered, new byte[0], "content-type", typeof(T)); var ctx = new MessagingContext( new ReceivedEntityMessage(entity), MessagingContextMode.Notify) { SendingPMode = new SendingProcessingMode { ReceiptHandling = { NotifyMethod = new Method { Type = "FILE" } }, ErrorHandling = { NotifyMethod = new Method { Type = "FILE" } }, ExceptionHandling = { NotifyMethod = new Method { Type = "FILE" } } } }; ctx.ModifyContext(envelope); return(ctx); }
public void OverrideMessageWithDeliverMessage() { // Arrange var filledNotify = new DeliverMessageEnvelope(new MessageInfo(), new byte[0], "type"); var context = new MessagingContext(filledNotify) { SendingPMode = new SendingProcessingMode(), ReceivingPMode = new ReceivingProcessingMode() }; var anonymousDeliver = new DeliverMessageEnvelope(new MessageInfo(), new byte[0], "type"); // Act context.ModifyContext(anonymousDeliver); // Assert Assert.Equal(anonymousDeliver, context.DeliverMessage); Assert.NotNull(context.SendingPMode); Assert.NotNull(context.ReceivingPMode); }
public void OverrideMessageWithNotifyMessage() { // Arrange var filledNotify = new NotifyMessageEnvelope(new AS4.Model.Notify.MessageInfo(), Status.Delivered, new byte[0], "type", typeof(InMessage)); var context = new MessagingContext(filledNotify) { SendingPMode = new SendingProcessingMode(), ReceivingPMode = new ReceivingProcessingMode() }; var anonymousNotify = new NotifyMessageEnvelope(null, default(Status), null, null, typeof(InMessage)); // Act context.ModifyContext(anonymousNotify); // Assert Assert.Equal(anonymousNotify, context.NotifyMessage); Assert.NotNull(context.SendingPMode); Assert.NotNull(context.ReceivingPMode); }
protected MessagingContext CreateReceivedMessagingContext(AS4Message as4Message, ReceivingProcessingMode receivingPMode) { var stream = new MemoryStream(); SerializerProvider .Default .Get(as4Message.ContentType) .Serialize(as4Message, stream); stream.Position = 0; var ctx = new MessagingContext( new ReceivedMessage(stream, as4Message.ContentType), MessagingContextMode.Receive) { ReceivingPMode = receivingPMode }; ctx.ModifyContext(as4Message); return(ctx); }
/// <summary> /// Execute the step for a given <paramref name="messagingContext"/>. /// </summary> /// <param name="messagingContext">Message used during the step execution.</param> /// <returns></returns> public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { if (messagingContext?.AS4Message == null) { throw new InvalidOperationException( $"{nameof(UpdateReceivedAS4MessageBodyStep)} requires an AS4Message to update but no AS4Message is present in the MessagingContext"); } Logger.Trace("Updating the received message body..."); using (DatastoreContext datastoreContext = _createDatastoreContext()) { var repository = new DatastoreRepository(datastoreContext); var service = new InMessageService(_configuration, repository); service.UpdateAS4MessageForMessageHandling( messagingContext.AS4Message, messagingContext.SendingPMode, messagingContext.ReceivingPMode, _messageBodyStore); await datastoreContext.SaveChangesAsync().ConfigureAwait(false); } if (messagingContext.ReceivedMessageMustBeForwarded) { // When the Message has to be forwarded, the remaining Steps must not be executed. // The MSH must answer with a HTTP Accepted status-code, so an empty context must be returned. messagingContext.ModifyContext(AS4Message.Empty); Logger.Info( "Stops execution to return empty SOAP envelope to the orignal sender. " + "This happens when the message must be forwarded"); return(StepResult.Success(messagingContext).AndStopExecution()); } return(StepResult.Success(messagingContext)); }
/// <summary> /// Transform a given <see cref="ReceivedMessage"/> to a Canonical <see cref="MessagingContext"/> instance. /// </summary> /// <param name="message">Given message to transform.</param> /// <returns></returns> public async Task <MessagingContext> TransformAsync(ReceivedMessage message) { var receivedEntityMessage = message as ReceivedEntityMessage; if (receivedEntityMessage == null) { throw new NotSupportedException( $"Minder Notify Transformer only supports transforming instances of type {typeof(ReceivedEntityMessage)}"); } var as4Transformer = new AS4MessageTransformer(); MessagingContext context = await as4Transformer.TransformAsync(message); NotifyMessageEnvelope notifyMessage = await CreateNotifyMessageEnvelope( context.AS4Message, context.AS4Message.GetPrimaryMessageId(), receivedEntityMessage.Entity.GetType()); context.ModifyContext(notifyMessage); return(context); }
/// <summary> /// Start Mapping from a <see cref="SubmitMessage"/> /// to an <see cref="AS4Message"/> /// </summary> /// <param name="messagingContext"></param> /// <returns></returns> public async Task <StepResult> ExecuteAsync(MessagingContext messagingContext) { if (messagingContext == null) { throw new ArgumentNullException(nameof(messagingContext)); } SubmitMessage submitMessage = messagingContext.SubmitMessage; if (submitMessage == null) { throw new InvalidOperationException( $"{nameof(CreateAS4MessageStep)} requires a SubmitMessage to create an AS4Message from but no AS4Message is present in the MessagingContext"); } if (messagingContext.SendingPMode == null) { Logger.Debug("No SendingPMode was found, only use information from SubmitMessage to create AS4 UserMessage"); } ValidateSubmitMessage(submitMessage); Logger.Trace("Create UserMessage for SubmitMessage"); UserMessage userMessage = SubmitMessageMap.CreateUserMessage(submitMessage, submitMessage.PMode); Logger.Info($"{messagingContext.LogTag} UserMessage with Id \"{userMessage.MessageId}\" created from SubmitMessage"); AS4Message as4Message = AS4Message.Create(userMessage, messagingContext.SendingPMode); IEnumerable <Attachment> attachments = await RetrieveAttachmentsForAS4MessageAsync(submitMessage.Payloads) .ConfigureAwait(false); as4Message.AddAttachments(attachments); messagingContext.ModifyContext(as4Message); return(StepResult.Success(messagingContext)); }