private static async Task <XmlDocument> RetrieveSmpMetaDataAsync(
            IDynamicDiscoveryProfile profile,
            DynamicDiscoveryConfiguration dynamicDiscovery,
            AS4Party toParty)
        {
            if (dynamicDiscovery == null)
            {
                throw new ConfigurationErrorsException(
                          @"Cannot retrieve SMP metadata: SendingPMode requires a <DynamicDiscovery/> element");
            }

            Dictionary <string, string> customProperties =
                (dynamicDiscovery.Settings ?? new DynamicDiscoverySetting[0])
                ?.ToDictionary(s => s?.Key, s => s?.Value);

            return(await profile.RetrieveSmpMetaDataAsync(
                       party : toParty,
                       properties : customProperties));
        }
        private static async Task <DynamicDiscoveryResult> DynamicDiscoverSendingPModeAsync(
            SendingProcessingMode sendingPMode,
            IDynamicDiscoveryProfile profile,
            AS4Party toParty)
        {
            try
            {
                var clonedPMode = (SendingProcessingMode)sendingPMode.Clone();
                clonedPMode.Id = $"{clonedPMode.Id}_SMP";

                XmlDocument smpMetaData = await RetrieveSmpMetaDataAsync(profile, clonedPMode.DynamicDiscovery, toParty);

                if (smpMetaData == null)
                {
                    Logger.Error($"No SMP meta-data document was retrieved by the Dynamic Discovery profile: {profile.GetType().Name}");
                    throw new InvalidDataException(
                              "No SMP meta-data document was retrieved during the Dynamic Discovery process");
                }

                DynamicDiscoveryResult result = profile.DecoratePModeWithSmpMetaData(clonedPMode, smpMetaData);
                if (result == null)
                {
                    Logger.Error($@"No decorated SendingPMode was returned by the Dynamic Discovery profile: {profile.GetType().Name}");
                    throw new InvalidDataException(
                              "No decorated SendingPMode was returned during the Dynamic Discovery");
                }

                ValidatePMode(result.CompletedSendingPMode);
                return(result);
            }
            catch (Exception ex)
            {
                Logger.Error(
                    $"An exception occured during the Dynamic Discovery process of the profile: {profile.GetType().Name} "
                    + $"with the message having ToParty={toParty} for SendingPMode {sendingPMode.Id}");

                throw new DynamicDiscoveryException(
                          "An exception occured during the Dynamic Discovery process", ex);
            }
        }
        /// <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 == null)
            {
                throw new ArgumentNullException(nameof(messagingContext));
            }

            if (messagingContext.AS4Message == null &&
                messagingContext.Mode == MessagingContextMode.Forward)
            {
                Logger.Error(
                    $"{nameof(DynamicDiscoveryStep)} requires an AS4Message when used in a Forward Agent, "
                    + "please make sure that the ReceivedMessage is deserialized before executing this step."
                    + $"{Environment.NewLine} Possibly this failure happened because the Transformer of the Forward Agent is still using "
                    + "the ForwardMessageTransformer instead of the AS4MessageTransformer");

                throw new InvalidOperationException(
                          "Dynamic Discovery process cannot be used in a Forwarding scenario for messages that are not AS4Messages");
            }

            if (messagingContext.SendingPMode == null ||
                messagingContext.SendingPMode.DynamicDiscoverySpecified == false)
            {
                Logger.Trace($"Skip Dynamic Discovery because SendingPMode {messagingContext.SendingPMode?.Id} is not configured for Dynamic Discovery");
                return(StepResult.Success(messagingContext));
            }

            var clonedPMode = (SendingProcessingMode)messagingContext.SendingPMode.Clone();

            clonedPMode.Id = $"{clonedPMode.Id}_SMP";

            string smpProfile = messagingContext.SendingPMode.DynamicDiscovery.SmpProfile;
            IDynamicDiscoveryProfile profile = _resolveDynamicDiscoveryProfile(smpProfile);

            Logger.Info($"{messagingContext.LogTag} DynamicDiscovery is enabled in SendingPMode - using {profile.GetType().Name}");

            AS4Party toParty =
                messagingContext.Mode == MessagingContextMode.Forward
                ? ResolveAS4ReceiverParty(messagingContext.AS4Message)
                : ResolveSubmitOrPModeReceiverParty(
                    messagingContext.SubmitMessage?.PartyInfo?.ToParty,
                    messagingContext.SendingPMode?.MessagePackaging?.PartyInfo?.ToParty,
                    messagingContext.SendingPMode?.AllowOverride == true);

            DynamicDiscoveryResult result = await DynamicDiscoverSendingPModeAsync(messagingContext.SendingPMode, profile, toParty);

            Logger.Debug($"SendingPMode {result.CompletedSendingPMode.Id} completed with SMP metadata");

            messagingContext.SendingPMode = result.CompletedSendingPMode;
            if (messagingContext.SubmitMessage != null && result.OverrideToParty)
            {
                if (messagingContext.SubmitMessage?.PartyInfo != null)
                {
                    messagingContext.SubmitMessage.PartyInfo.ToParty = null;
                }

                messagingContext.SubmitMessage.PMode = result.CompletedSendingPMode;
            }

            return(StepResult.Success(messagingContext));
        }