From f6acb82b7ad3192c8176c9d6d4b2998268ab4cfd Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Sun, 10 Jul 2022 21:49:40 -0300 Subject: [PATCH 01/13] Service Bus API implementation --- dotnet/DotNetStandardClasses.sln | 19 +- .../GxClasses/Properties/AssemblyInfo.cs | 1 + .../GXAzureServiceBus/AzureServiceBus.cs | 399 ++++++++++++++++++ .../GXAzureServiceBus.csproj | 15 + .../ServiceBusMessageBrokerProvider.cs | 20 + .../GXMessageBroker/GXMessageBroker.csproj | 12 + .../GXMessageBroker/MessageBroker.cs | 113 +++++ .../GXMessageBroker/MessageBrokerBase.cs | 33 ++ .../GXMessageBroker/MessageBrokerProvider.cs | 116 +++++ .../Messaging/GXMessageBroker/MessageQueue.cs | 320 ++++++++++++++ .../GXMessageBroker/PropertyConstants.cs | 17 + .../GXMessageBroker/ServiceSettings.cs | 101 +++++ .../GxClasses/Services/Storage/GXServices.cs | 1 + .../DotNetCoreUnitTest.csproj | 1 + .../MessageBroker/AzureMessageBrokerTest.cs | 75 ++++ .../MessageBroker/AzureServiceBusTest.cs | 13 + 16 files changed, 1254 insertions(+), 2 deletions(-) create mode 100644 dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs create mode 100644 dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj create mode 100644 dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs create mode 100644 dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj create mode 100644 dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs create mode 100644 dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerBase.cs create mode 100644 dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs create mode 100644 dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs create mode 100644 dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs create mode 100644 dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs create mode 100644 dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs create mode 100644 dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureServiceBusTest.cs diff --git a/dotnet/DotNetStandardClasses.sln b/dotnet/DotNetStandardClasses.sln index be80e4fa5..9013ef07d 100644 --- a/dotnet/DotNetStandardClasses.sln +++ b/dotnet/DotNetStandardClasses.sln @@ -208,10 +208,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestMockDBAccess", "src\ext EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneXus.Programs.Common", "src\extensions\Azure\test\GeneXus.Programs.Common\GeneXus.Programs.Common.csproj", "{DCEC0B38-93B6-4003-81E6-9FBC2BB4F163}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GXAmazonSQS", "src\dotnetcore\Providers\Messaging\GXAmazonSQS\GXAmazonSQS.csproj", "{F8BA0D65-267D-491F-BFAB-33F5E5B61AD7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GXAmazonSQS", "src\dotnetcore\Providers\Messaging\GXAmazonSQS\GXAmazonSQS.csproj", "{F8BA0D65-267D-491F-BFAB-33F5E5B61AD7}" +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "apiattractions", "src\extensions\Azure\test\apiattractions\apiattractions.csproj", "{E85FDB0F-FA81-4CDD-8BF3-865269CE2DB3}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotNetRedisTest", "test\DotNetRedisTest\DotNetRedisTest.csproj", "{48430E50-043A-47A2-8278-B86A4420758A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetRedisTest", "test\DotNetRedisTest\DotNetRedisTest.csproj", "{48430E50-043A-47A2-8278-B86A4420758A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GXMessageBroker", "src\dotnetcore\Providers\Messaging\GXMessageBroker\GXMessageBroker.csproj", "{3B1B5706-E896-4CEB-A551-E30226303BDB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GXAzureServiceBus", "src\dotnetcore\Providers\Messaging\GXAzureServiceBus\GXAzureServiceBus.csproj", "{F8ABEA82-F823-4E9C-96FA-26AF24C932E0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -519,6 +524,14 @@ Global {48430E50-043A-47A2-8278-B86A4420758A}.Debug|Any CPU.Build.0 = Debug|Any CPU {48430E50-043A-47A2-8278-B86A4420758A}.Release|Any CPU.ActiveCfg = Release|Any CPU {48430E50-043A-47A2-8278-B86A4420758A}.Release|Any CPU.Build.0 = Release|Any CPU + {3B1B5706-E896-4CEB-A551-E30226303BDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3B1B5706-E896-4CEB-A551-E30226303BDB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B1B5706-E896-4CEB-A551-E30226303BDB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3B1B5706-E896-4CEB-A551-E30226303BDB}.Release|Any CPU.Build.0 = Release|Any CPU + {F8ABEA82-F823-4E9C-96FA-26AF24C932E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F8ABEA82-F823-4E9C-96FA-26AF24C932E0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F8ABEA82-F823-4E9C-96FA-26AF24C932E0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F8ABEA82-F823-4E9C-96FA-26AF24C932E0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -622,6 +635,8 @@ Global {F8BA0D65-267D-491F-BFAB-33F5E5B61AD7} = {30159B0F-BE61-4DB7-AC02-02851426BE4B} {E85FDB0F-FA81-4CDD-8BF3-865269CE2DB3} = {7BA5A2CE-7992-4F87-9D84-91AE4D046F5A} {48430E50-043A-47A2-8278-B86A4420758A} = {1D6F1776-FF4B-46C2-9B3D-BC46CCF049DC} + {3B1B5706-E896-4CEB-A551-E30226303BDB} = {4C43F2DA-59E5-46F5-B691-195449498555} + {F8ABEA82-F823-4E9C-96FA-26AF24C932E0} = {30159B0F-BE61-4DB7-AC02-02851426BE4B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E18684C9-7D76-45CD-BF24-E3944B7F174C} diff --git a/dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs b/dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs index 1d7f35bd7..21c4953f3 100644 --- a/dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs +++ b/dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs @@ -5,3 +5,4 @@ [assembly: InternalsVisibleTo("GxSearch")] [assembly: InternalsVisibleTo("GxNetCoreStartup")] [assembly: InternalsVisibleTo("GXQueue")] +[assembly: InternalsVisibleTo("GXMessageBroker")] \ No newline at end of file diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs new file mode 100644 index 000000000..863df75d1 --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs @@ -0,0 +1,399 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading.Tasks; +using Azure.Messaging.ServiceBus; +using GeneXus.Messaging.Common; +using GeneXus.Services; +using GeneXus.Utils; +using log4net; + +namespace GeneXus.Messaging.GXAzureServiceBus +{ + public class AzureServiceBus : MessageBrokerBase, IMessageBroker + { + + public static String Name = "AZURESB"; + ServiceBusClient _serviceBusClient { get; set; } + private string _queueOrTopicName { get; set; } + private string _connectionString { get; set; } + private ServiceBusSender _sender { get; set; } + + static readonly ILog logger = log4net.LogManager.GetLogger(typeof(AzureServiceBus)); + + public AzureServiceBus() : this(null) + { + } + + public AzureServiceBus(GXService providerService) : base(providerService) + { + Initialize(providerService); + } + + public void Dispose() + { + Task task = Task.Run(async () => await ServiceClientDisposeAsync()); + } + private async Task ServiceClientDisposeAsync() + { + await _serviceBusClient.DisposeAsync().ConfigureAwait(false); + } + + private async Task RemoveMessageAsync(ServiceBusReceivedMessage serviceBusReceivedMessage) + { + ServiceBusReceiver receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName); + await receiver.CompleteMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false); + await receiver.DisposeAsync().ConfigureAwait(false); + } + + private void Initialize(GXService providerService) + { + ServiceSettings serviceSettings = new(PropertyConstants.MESSAGE_BROKER, Name, providerService); + _queueOrTopicName = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.QUEUE_NAME); + _connectionString = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.QUEUE_CONNECTION_STRING); + + //TO DO Consider connection options here + try + { + _serviceBusClient = new ServiceBusClient(_connectionString); + if (_serviceBusClient != null) + { + _sender = _serviceBusClient.CreateSender(_queueOrTopicName); + } + } + catch (Exception ex) + { + GXLogging.Error(logger, ex.Message); + } + } + + public bool GetMessageFromException(Exception ex, SdtMessages_Message msg) + { + try + { + Azure.RequestFailedException az_ex = (Azure.RequestFailedException)ex; + msg.gxTpr_Id = az_ex.ErrorCode; + msg.gxTpr_Description = az_ex.Message; + return true; + } + catch (Exception) + { + return false; + } + } + + public override string GetName() + { + return Name; + } + + public bool SendMessage(BrokerMessage brokerMessage) + { + bool success = false; + ServiceBusMessage serviceBusMessage = BrokerMessageToServiceBusMessage(brokerMessage); + try + { + Task task; + if (_sender != null) + { + task = Task.Run(async () => await sendAsync(serviceBusMessage)); + success = task.Result; + } + else + { + throw new Exception("There was an error at the Message Broker initialization."); + } + } + catch (AggregateException ae) + { + throw ae; + } + return success; + } + + private async Task sendAsync(ServiceBusMessage serviceBusMessage) + { + try + { + await _sender.SendMessageAsync(serviceBusMessage).ConfigureAwait(false); + return true; + } + catch (Exception ex) + { + return false; + throw ex; + } + } + bool IMessageBroker.SendMessages(IList brokerMessages, BrokerMessageOptions messageQueueOptions) + { + bool success = false; + try + { + Task task = Task.Run(async () => await SendMessagesBatchAsync(brokerMessages)); + success = task.Result; + } + catch (AggregateException ae) + { + throw ae; + } + return success; + } + + private async Task SendMessagesBatchAsync(IList brokerMessages) + { + bool success = false; + if (_sender == null) + { + throw new Exception("There was an error at the Message Broker initialization."); + } + else + { + ServiceBusMessage serviceBusMessage; + IList serviceBusMessages = new List(); + foreach (BrokerMessage brokerMessage in brokerMessages) + { + serviceBusMessage = BrokerMessageToServiceBusMessage(brokerMessage); + serviceBusMessages.Add(serviceBusMessage); + } + try + { + await _sender.SendMessagesAsync(serviceBusMessages).ConfigureAwait(false); + success = true; + } + catch (Exception ex) + { + GXLogging.Error(logger, ex.Message.ToString()); + } + } + return success; + } + IList IMessageBroker.GetMessages(BrokerMessageOptions messageQueueOptions, out bool success) + { + IList brokerMessages = new List(); + success = false; + try + { + Task> receivedMessages = Task>.Run(async () => await ReceiveMessagesAsync(messageQueueOptions)); + if (receivedMessages != null && receivedMessages.Result != null) + { + foreach (ServiceBusReceivedMessage serviceBusReceivedMessage in receivedMessages.Result) + { + brokerMessages.Add(SBReceivedMessageToBrokerMessage(serviceBusReceivedMessage)); + } + success = true; + } + } + catch (AggregateException ae) + { + throw ae; + } + return brokerMessages; + } + + private async Task> ReceiveMessagesAsync(BrokerMessageOptions messageQueueOptions) + { + IReadOnlyList receivedMessages; + try + { + ServiceBusReceiverOptions serviceBusReceiverOptions = new ServiceBusReceiverOptions(); + + if (messageQueueOptions.ReceiveMode == 1) // Valid values : PeekLock (0), ReceiveAndDelete (1) + serviceBusReceiverOptions.ReceiveMode = ServiceBusReceiveMode.ReceiveAndDelete; + + if (messageQueueOptions.PrefetchCount != 0) + serviceBusReceiverOptions.PrefetchCount = messageQueueOptions.PrefetchCount; + + ServiceBusReceiver receiver; + + if (!string.IsNullOrEmpty(messageQueueOptions.SubscriptionName)) + { + receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, messageQueueOptions.SubscriptionName, serviceBusReceiverOptions); + } + else + { + receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, serviceBusReceiverOptions); + } + + int maxMessagesReceive = 1; + TimeSpan maxWaitTimeout = TimeSpan.Zero; + if (messageQueueOptions != null && messageQueueOptions.WaitTimeout != 0) + maxWaitTimeout = TimeSpan.FromSeconds(messageQueueOptions.WaitTimeout); + + if (messageQueueOptions != null && messageQueueOptions.MaxNumberOfMessages != 0) + maxMessagesReceive = messageQueueOptions.MaxNumberOfMessages; + + if (maxWaitTimeout == TimeSpan.Zero) + receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive).ConfigureAwait(false); + else + receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive, maxWaitTime: maxWaitTimeout).ConfigureAwait(false); + + await receiver.DisposeAsync().ConfigureAwait(false); + + return receivedMessages; + } + catch (Exception ex) + { + GXLogging.Error(logger, ex.Message.ToString()); + } + return null; + } + + #region Transform Methods + private ServiceBusMessage BrokerMessageToServiceBusMessage(BrokerMessage brokerMessage) + { + ServiceBusMessage serviceBusMessage = new ServiceBusMessage(brokerMessage.MessageBody); + serviceBusMessage.MessageId = brokerMessage.MessageId; + + GXProperties messageAttributes = brokerMessage.MessageAttributes; + if (messageAttributes != null) + LoadMessageProperties(messageAttributes, ref serviceBusMessage); + + return serviceBusMessage; + } + private BrokerMessage SBReceivedMessageToBrokerMessage(ServiceBusReceivedMessage serviceBusReceivedMessage) + { + BrokerMessage brokerMessage = new BrokerMessage(); + brokerMessage.MessageId = serviceBusReceivedMessage.MessageId; + brokerMessage.MessageBody = serviceBusReceivedMessage.Body.ToString(); + + LoadReceivedMessageProperties(serviceBusReceivedMessage, ref brokerMessage); + return brokerMessage; + } + + private void LoadReceivedMessageProperties(ServiceBusReceivedMessage serviceBusReceivedMessage, ref BrokerMessage brokerMessage) + { + GXProperties properties = new GXProperties(); + + if (serviceBusReceivedMessage != null) + { + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.Subject)) + properties.Add("Subject", serviceBusReceivedMessage.Subject); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.ReplyToSessionId)) + properties.Add("ReplyToSessionId", serviceBusReceivedMessage.ReplyToSessionId); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.DeadLetterSource)) + properties.Add("DeadLetterSource", serviceBusReceivedMessage.DeadLetterSource); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.ContentType)) + properties.Add("ContentType", serviceBusReceivedMessage.ContentType); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.CorrelationId)) + properties.Add("CorrelationId", serviceBusReceivedMessage.CorrelationId); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.DeadLetterErrorDescription)) + properties.Add("DeadLetterErrorDescription", serviceBusReceivedMessage.DeadLetterErrorDescription); + + if (string.IsNullOrEmpty(serviceBusReceivedMessage.DeadLetterReason)) + properties.Add("DeadLetterReason", serviceBusReceivedMessage.DeadLetterReason); + + if (serviceBusReceivedMessage.DeliveryCount != 0) + properties.Add("DeliveryCount", serviceBusReceivedMessage.DeliveryCount.ToString()); + + if (serviceBusReceivedMessage.EnqueuedSequenceNumber != 0) + properties.Add("EnqueuedSequenceNumber", serviceBusReceivedMessage.EnqueuedSequenceNumber.ToString()); + + properties.Add("EnqueuedTime", serviceBusReceivedMessage.EnqueuedTime.UtcDateTime.ToString()); + + properties.Add("ExpiresAt", serviceBusReceivedMessage.ExpiresAt.UtcDateTime.ToString()); + properties.Add("LockedUntil", serviceBusReceivedMessage.LockedUntil.UtcDateTime.ToString()); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.LockToken)) + properties.Add("LockToken", serviceBusReceivedMessage.LockToken); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.PartitionKey)) + properties.Add("PartitionKey", serviceBusReceivedMessage.PartitionKey); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.ReplyTo)) + properties.Add("ReplyTo", serviceBusReceivedMessage.ReplyTo); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.SessionId)) + properties.Add("SessionId", serviceBusReceivedMessage.SessionId); + + properties.Add("TimeToLive", serviceBusReceivedMessage.TimeToLive.ToString()); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.ReplyToSessionId)) + properties.Add("ReplyToSessionId", serviceBusReceivedMessage.ReplyToSessionId); + + properties.Add("ScheduledEnqueueTime", serviceBusReceivedMessage.ScheduledEnqueueTime.UtcDateTime.ToString()); + + if (serviceBusReceivedMessage.SequenceNumber != 0) + properties.Add("SequenceNumber", serviceBusReceivedMessage.SequenceNumber.ToString()); + + properties.Add("State", serviceBusReceivedMessage.State.ToString()); + + if (!string.IsNullOrEmpty(serviceBusReceivedMessage.TransactionPartitionKey)) + properties.Add("TransactionPartitionKey", serviceBusReceivedMessage.TransactionPartitionKey); + + //Application Properties + brokerMessage.MessageAttributes = new GXProperties(); + Type t = serviceBusReceivedMessage.GetType(); + PropertyInfo[] props = t.GetProperties(); + foreach (PropertyInfo prop in props) + { + object value; + if (prop.GetIndexParameters().Length == 0 && serviceBusReceivedMessage != null) + { + value = prop.GetValue(serviceBusReceivedMessage); + if (value != null) + brokerMessage.MessageAttributes.Add(prop.Name, value.ToString()); + } + } + } + brokerMessage.MessageAttributes = properties; + } + private void LoadMessageProperties(GXProperties properties, ref ServiceBusMessage serviceBusMessage) + { + if (properties != null) + { + GxKeyValuePair messageAttribute = new GxKeyValuePair(); + messageAttribute = properties.GetFirst(); + while (!properties.Eof()) + { + switch (messageAttribute.Key.ToLower()) + { + case "timetolive": + serviceBusMessage.TimeToLive = System.TimeSpan.Parse(messageAttribute.Value); + break; + case "to": + serviceBusMessage.To = messageAttribute.Value; + break; + case "subject": + serviceBusMessage.Subject = messageAttribute.Value; + break; + case "partitionkey": + serviceBusMessage.PartitionKey = messageAttribute.Value; + break; + case "transactionpartitionkey": + serviceBusMessage.TransactionPartitionKey = messageAttribute.Value; + break; + case "contenttype": + serviceBusMessage.ContentType = messageAttribute.Value; + break; + case "correlationid": + serviceBusMessage.CorrelationId = messageAttribute.Value; + break; + case "replyto": + serviceBusMessage.ReplyTo = messageAttribute.Value; + break; + case "replytosessionid": + serviceBusMessage.ReplyToSessionId = messageAttribute.Value; + break; + case "sessionid": + serviceBusMessage.SessionId = messageAttribute.Value; + break; + case "scheduledenqueuetime": + serviceBusMessage.ScheduledEnqueueTime = System.DateTimeOffset.Parse(messageAttribute.Value); + break; + default: + serviceBusMessage.ApplicationProperties.Add(messageAttribute.Key, messageAttribute.Value); + break; + } + messageAttribute = properties.GetNext(); + } + } + } + + #endregion + } +} diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj new file mode 100644 index 000000000..472f9f52b --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj @@ -0,0 +1,15 @@ + + + + net6.0 + + + + + + + + + + + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs new file mode 100644 index 000000000..6fadcf7dc --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs @@ -0,0 +1,20 @@ +using GeneXus.Messaging.Common; +using GeneXus.Utils; + +namespace GeneXus.Messaging.GXAzureServiceBus +{ + public class ServiceBusMessageBrokerProvider + { + public MessageQueue Connect(string queueName, string queueConnection, out GXBaseCollection errorMessages, out bool success) + { + MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); + GXProperties properties = new GXProperties(); + properties.Add(PropertyConstants. MESSAGEBROKER_AZURESB_QUEUENAME, queueName); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUECONNECTION, queueConnection); + MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect); + errorMessages = errorMessagesConnect; + success = successConnect; + return messageQueue; + } + } +} diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj new file mode 100644 index 000000000..0e32bdadb --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj @@ -0,0 +1,12 @@ + + + + net6.0 + TRACE;DEBUG;NETCORE + + + + + + + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs new file mode 100644 index 000000000..f86bb79ca --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using GeneXus.Utils; + +namespace GeneXus.Messaging.Common +{ + public interface IMessageBroker + { + bool SendMessage(BrokerMessage brokerMessage); + bool SendMessages(IList brokerMessages, BrokerMessageOptions messageQueueOptions); + IList GetMessages(BrokerMessageOptions messageQueueOptions, out bool success); + void Dispose(); + bool GetMessageFromException(Exception ex, SdtMessages_Message msg); + } + public class BrokerMessage : GxUserType + { + public string MessageId { get; set; } + public string MessageBody { get; set; } + public GXProperties MessageAttributes { get; set; } + public string MessageHandleId { get; set; } + + #region Json + private static Hashtable mapper; + public override String JsonMap(String value) + { + if (mapper == null) + { + mapper = new Hashtable(); + } + return (String)mapper[value]; ; + } + + public override void ToJSON() + { + ToJSON(true); + return; + } + + public override void ToJSON(bool includeState) + { + AddObjectProperty("MessageId", MessageId, false); + AddObjectProperty("MessageBody", MessageBody, false); + AddObjectProperty("MessageHandleId", MessageHandleId, false); + return; + } + + #endregion + + } + + public class BrokerMessageResult : GxUserType + { + public string MessageId { get; set; } + public string ServerMessageId { get; set; } + public GXProperties MessageAttributes { get; set; } + public string MessageHandleId { get; set; } + public string MessageStatus { get; set; } = "Unknown"; + + #region Json + private static Hashtable mapper; + public override String JsonMap(String value) + { + if (mapper == null) + { + mapper = new Hashtable(); + } + return (String)mapper[value]; ; + } + + public override void ToJSON() + { + ToJSON(true); + return; + } + + public override void ToJSON(bool includeState) + { + AddObjectProperty("MessageId", MessageId, false); + AddObjectProperty("ServerMessageId", ServerMessageId, false); + AddObjectProperty("MessageHandleId", MessageHandleId, false); + AddObjectProperty("MessageStatus", MessageStatus, false); + + return; + } + + #endregion + } + + public class BrokerMessageOptions : GxUserType + { + public short MaxNumberOfMessages { get; set; } + public bool DeleteConsumedMessages { get; set; } + public int WaitTimeout { get; set; } + public int VisibilityTimeout { get; set; } + public int TimetoLive { get; set; } + public int DelaySeconds { get; set; } + public string ReceiveRequestAttemptId { get; set; } + public bool ReceiveMessageAttributes { get; set; } + public int ReceiveMode { get; set; } + public int PrefetchCount { get; set; } + public string SubscriptionName { get; set; } + + } + + public static class BrokerMessageResultStatus + { + public const string Unknown = "Unknown"; + public const string Sent = "Sent"; + public const string Deleted = "Deleted"; + public const string Failed = "Failed"; + } +} diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerBase.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerBase.cs new file mode 100644 index 000000000..da044c4ef --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerBase.cs @@ -0,0 +1,33 @@ +using System; +using GeneXus.Services; +using log4net; + +namespace GeneXus.Messaging.Common +{ + public abstract class MessageBrokerBase + { + static readonly ILog logger = log4net.LogManager.GetLogger(typeof(MessageBrokerBase)); + internal GXService service; + public MessageBrokerBase() + { + } + + public MessageBrokerBase(GXService s) + { + if (s == null) + { + try + { + s = ServiceFactory.GetGXServices().Get(GXServices.MESSAGEBROKER_SERVICE); + } + catch (Exception) + { + GXLogging.Warn(logger, "MESSAGEBROKER_SERVICE is not activated"); + } + } + + service = s; + } + public abstract String GetName(); + } +} diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs new file mode 100644 index 000000000..e890964d0 --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs @@ -0,0 +1,116 @@ +using System; +using GeneXus.Attributes; +using GeneXus.Encryption; +using GeneXus.Services; +using GeneXus.Utils; +using GxClasses.Helpers; +using log4net; + +namespace GeneXus.Messaging.Common +{ + [GXApi] + public class MessageBrokerProvider : MessageQueue + { + static readonly ILog logger = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private static GXService providerService; + public MessageBrokerProvider() + { + + } + + public MessageQueue Connect(string providerTypeName, GXProperties properties, out GXBaseCollection errorMessages, out bool success) + { + errorMessages = new GXBaseCollection(); + MessageQueue messageQueue = new MessageQueue(); + if (string.IsNullOrEmpty(providerTypeName)) + { + GXUtil.ErrorToMessages("GXMessageBroker1000", "Message Broker provider cannot be empty", errorMessages); + GXLogging.Error(logger, "(GXMessageBroker1000)Failed to Connect to a Message Broker : Provider cannot be empty."); + success = false; + return messageQueue; + } + try + { + if (providerService == null || !string.Equals(providerService.Name, providerTypeName, StringComparison.OrdinalIgnoreCase)) + { + providerService = new GXService(); + providerService.Type = GXServices.MESSAGEBROKER_SERVICE; + providerService.Name = providerTypeName; + providerService.AllowMultiple = false; + providerService.Properties = new GXProperties(); + } + Preprocess(providerTypeName, properties); + + GxKeyValuePair prop = properties.GetFirst(); + while (!properties.Eof()) + { + providerService.Properties.Set(prop.Key, prop.Value); + prop = properties.GetNext(); + } + + string typeFullName = providerService.ClassName; + GXLogging.Debug(logger, "Loading Message Broker provider: " + typeFullName); + Type type = AssemblyLoader.GetType(typeFullName); + messageQueue.messageBroker = (IMessageBroker)Activator.CreateInstance(type, new object[] { providerService }); + + } + catch (Exception ex) + { + GXLogging.Error(logger, "(GXMessageBroker1001)Couldn't connect to Message Broker provider: " + ExceptionExtensions.GetInnermostException(ex)); + GXUtil.ErrorToMessages("GXMessageBroker1001", ex, errorMessages); + success = false; + return messageQueue; + } + success = true; + return (messageQueue); + } + private static void Preprocess(String name, GXProperties properties) + { + string className; + + switch (name) + { + case Providers.AzureServiceBus: + className = PropertyConstants.AZURE_SB_CLASSNAME; + SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME); + SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_QUEUECONNECTION); + if (string.IsNullOrEmpty(providerService.ClassName) || !providerService.ClassName.Contains(className)) + { + providerService.ClassName = PropertyConstants.AZURE_SB_PROVIDER_CLASSNAME; + } + break; + default: + throw new SystemException(string.Format("Provider {0} is not supported.", name)); + } + } + private static void SetEncryptedProperty(GXProperties properties, String prop) + { + String value = properties.Get(prop); + if (string.IsNullOrEmpty(value)) + value = String.Empty; + value = CryptoImpl.Encrypt(value); + properties.Set(prop, value); + } + + } + public static class ExceptionExtensions + { + public static string GetInnermostException(Exception e) + { + Exception ex = e; + if (ex != null) + { + while (ex.InnerException != null) + { + ex = ex.InnerException; + } + + } + return ex.Message; + } + } + static class Providers + { + public const string AzureServiceBus = "AZURESERVICEBUS"; + } +} diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs new file mode 100644 index 000000000..8345212b8 --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs @@ -0,0 +1,320 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using GeneXus.Application; +using GeneXus.Services; +using GeneXus.Utils; +using GxClasses.Helpers; +using log4net; + +namespace GeneXus.Messaging.Common +{ + public class MessageQueue + { + internal IMessageBroker messageBroker = null; + public static Assembly assembly; + static readonly ILog logger = log4net.LogManager.GetLogger(typeof(MessageQueue)); + private const string SDT_MESSAGE_CLASS_NAME = @"SdtMessage"; + private const string SDT_MESSAGEPROPERTY_CLASS_NAME = @"SdtMessageProperty"; + //private const string SDT_MESSAGERESULT_CLASS_NAME = @"SdtMessageResult"; + private const string NAMESPACE = @"GeneXus.Programs.genexusmessagingqueue.MessageBroker"; + private const string GENEXUS_COMMON_DLL = @"GeneXus.Programs.Common.dll"; + + public MessageQueue() + { + } + public MessageQueue(MessageQueue other) + { + messageBroker = other.messageBroker; + } + void ValidQueue() + { + if (messageBroker == null) + { + GXLogging.Error(logger, "Message Broker was not instantiated."); + throw new Exception("Message Broker was not instantiated."); + } + } + private static Assembly LoadAssembly(string fileName) + { + if (File.Exists(fileName)) + { + Assembly assemblyLoaded = Assembly.LoadFrom(fileName); + return assemblyLoaded; + } + else + return null; + } + + private static void LoadAssemblyIfRequired() + { + if (assembly == null) + { + assembly = LoadAssembly(Path.Combine(GxContext.StaticPhysicalPath(), GENEXUS_COMMON_DLL)); + if (assembly == null) + assembly = LoadAssembly(Path.Combine(GxContext.StaticPhysicalPath(), "bin", GENEXUS_COMMON_DLL)); + } + } + + public void Dispose() + { + try + { + ValidQueue(); + messageBroker.Dispose(); + } + catch (Exception ex) + { + GXLogging.Error(logger, ex); + + } + } + + public IList GetMessages(GxUserType messageQueueOptions, out GXBaseCollection errorMessages, out bool success) + { + errorMessages = new GXBaseCollection(); + IList resultMessages = new List(); + success = false; + try + { + BrokerMessageOptions options = TransformOptions(messageQueueOptions); + + try + { + ValidQueue(); + IList brokerMessages = messageBroker.GetMessages(options, out success); + LoadAssemblyIfRequired(); + foreach (BrokerMessage brokerMessage in brokerMessages) + { + if (TransformBrokerMessage(brokerMessage) is GxUserType result) + resultMessages.Add(result); + } + success = true; + + } + catch (Exception ex) + { + QueueErrorMessagesSetup(ex, out errorMessages); + GXLogging.Error(logger, ex); + success = false; + } + } + catch (Exception ex) + { + GXLogging.Error(logger, ex); + success = false; + throw ex; + } + + return resultMessages; + } + public bool SendMessage(GxUserType messageQueue, out GXBaseCollection errorMessages) + { + bool success = false; + errorMessages = new GXBaseCollection(); + GxUserType result = new GxUserType(); + try + { + BrokerMessage brokerQueueMessage = TransformGXUserTypeToBrokerMessage(messageQueue); + LoadAssemblyIfRequired(); + try + { + ValidQueue(); + return(messageBroker.SendMessage(brokerQueueMessage)); + } + catch (Exception ex) + { + QueueErrorMessagesSetup(ex, out errorMessages); + success = false; + GXLogging.Error(logger, ex); + } + } + catch (Exception ex) + { + success = false; + GXLogging.Error(logger,ex); + throw ex; + } + return success; + } + + public bool SendMessages(IList queueMessages, GxUserType messageQueueOptions, out GXBaseCollection errorMessages) + { + errorMessages = new GXBaseCollection(); + bool success = false; + try + { + BrokerMessageOptions options = TransformOptions(messageQueueOptions); + IList brokerMessagesList = new List(); + foreach (GxUserType queueMessage in queueMessages) + { + if (TransformGXUserTypeToBrokerMessage(queueMessage) is BrokerMessage brokerMessage) + brokerMessagesList.Add(brokerMessage); + } + try + { + ValidQueue(); + success = messageBroker.SendMessages(brokerMessagesList, options); + LoadAssemblyIfRequired(); + + } + catch (Exception ex) + { + QueueErrorMessagesSetup(ex, out errorMessages); + success = false; + GXLogging.Error(logger, ex); + } + } + catch (Exception ex) + { + GXLogging.Error(logger, ex); + throw ex; + } + return success; + } + + protected void QueueErrorMessagesSetup(Exception ex, out GXBaseCollection errorMessages) + { + errorMessages = new GXBaseCollection(); + if (errorMessages != null && ex != null) + { + SdtMessages_Message msg = new SdtMessages_Message(); + if (messageBroker != null && messageBroker.GetMessageFromException(ex, msg)) + { + msg.gxTpr_Type = 1; + StringBuilder str = new StringBuilder(); + str.Append(ex.Message); + while (ex.InnerException != null) + { + str.Append(ex.InnerException.Message); + ex = ex.InnerException; + } + msg.gxTpr_Description = str.ToString(); + errorMessages.Add(msg); + } + else + { + GXLogging.Error(logger, "(GXServiceBus1002)Queue Error", ex); + GXUtil.ErrorToMessages("GXServiceBus1002", ex, errorMessages); + } + } + } + #region Transform operations + + private GxUserType TransformBrokerMessage(BrokerMessage brokerMessage) + { + Type classType = assembly.GetType(NAMESPACE + "." + SDT_MESSAGE_CLASS_NAME, false, ignoreCase: true); + Type propertyClassType = assembly.GetType(NAMESPACE + "." + SDT_MESSAGEPROPERTY_CLASS_NAME, false, ignoreCase: true); + + if (classType != null && Activator.CreateInstance(classType) is GxUserType messageSDT) + { + messageSDT.SetPropertyValue("Messageid", brokerMessage.MessageId); + messageSDT.SetPropertyValue("Messagebody", brokerMessage.MessageBody); + messageSDT.SetPropertyValue("Messagehandleid", brokerMessage.MessageHandleId); + + IList messageResultSDTAttributes = (IList)Activator.CreateInstance(classType.GetProperty("gxTpr_Messageattributes").PropertyType, new object[] { messageSDT.context, "MessageProperty", string.Empty }); + + if ((brokerMessage != null) && (brokerMessage.MessageAttributes != null)) + { + GxKeyValuePair prop = brokerMessage.MessageAttributes.GetFirst(); + while (!brokerMessage.MessageAttributes.Eof()) + { + if (propertyClassType != null && Activator.CreateInstance(propertyClassType) is GxUserType propertyClassTypeSDT) + { + propertyClassTypeSDT.SetPropertyValue("Propertykey", prop.Key); + propertyClassTypeSDT.SetPropertyValue("Propertyvalue", prop.Value); + messageResultSDTAttributes.Add(propertyClassTypeSDT); + prop = brokerMessage.MessageAttributes.GetNext(); + } + } + messageSDT.SetPropertyValue("Messageattributes", messageResultSDTAttributes); + } + return messageSDT; + } + return null; + } + private BrokerMessageOptions TransformOptions(GxUserType messageQueueOptions) + { + BrokerMessageOptions options = new BrokerMessageOptions(); + //TO DO Check the valid options, ex + //https://docs.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.createmessagebatchoptions.maxsizeinbytes?view=azure-dotnet#azure-messaging-servicebus-createmessagebatchoptions-maxsizeinbytes + + options.MaxNumberOfMessages = messageQueueOptions.GetPropertyValue("Maxnumberofmessages"); + options.DeleteConsumedMessages = messageQueueOptions.GetPropertyValue("Deleteconsumedmessages"); + options.WaitTimeout = messageQueueOptions.GetPropertyValue("Waittimeout"); + options.VisibilityTimeout = messageQueueOptions.GetPropertyValue("Visibilitytimeout"); + options.TimetoLive = messageQueueOptions.GetPropertyValue("Timetolive"); + return options; + } + + private BrokerMessage TransformGXUserTypeToBrokerMessage(GxUserType queueMessage) + { + BrokerMessage brokerQueueMessage = new BrokerMessage(); + brokerQueueMessage.MessageId = queueMessage.GetPropertyValue("Messageid"); + brokerQueueMessage.MessageBody = queueMessage.GetPropertyValue("Messagebody"); + brokerQueueMessage.MessageHandleId = queueMessage.GetPropertyValue("Messagehandleid"); + IList messageAttributes = queueMessage.GetPropertyValue("Messageattributes_GXBaseCollection"); + brokerQueueMessage.MessageAttributes = new GXProperties(); + foreach (GxUserType messageAttribute in messageAttributes) + { + string messagePropKey = messageAttribute.GetPropertyValue("Propertykey"); + string messagePropValue = messageAttribute.GetPropertyValue("Propertyvalue"); + brokerQueueMessage.MessageAttributes.Add(messagePropKey, messagePropValue); + } + return brokerQueueMessage; + } + #endregion + + } + internal class ServiceFactory + { + private static IMessageBroker messageBroker; + private static readonly ILog log = log4net.LogManager.GetLogger(typeof(GeneXus.Services.ServiceFactory)); + + public static GXServices GetGXServices() + { + return GXServices.Instance; + } + + public static IMessageBroker GetMessageBroker() + { + if (messageBroker == null) + { + messageBroker = GetMessageBrokerImpl(GXServices.MESSAGEBROKER_SERVICE); + } + return messageBroker; + } + + public static IMessageBroker GetMessageBrokerImpl(string service) + { + IMessageBroker messageBrokerImpl = null; + if (GetGXServices() != null) + { + GXService providerService = GetGXServices().Get(service); + if (providerService != null) + { + try + { + string typeFullName = providerService.ClassName; + GXLogging.Debug(log, "Loading Message Broker settings:", typeFullName); + Type type = AssemblyLoader.GetType(typeFullName); + messageBrokerImpl = (IMessageBroker)Activator.CreateInstance(type); + } + catch (Exception e) + { + GXLogging.Error(log, "Couldn't connect to the Message Broker.", e.Message, e); + throw e; + } + } + } + return messageBrokerImpl; + } + } + +} + + + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs new file mode 100644 index 000000000..0234167d2 --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs @@ -0,0 +1,17 @@ +namespace GeneXus.Messaging.Common +{ + public static class PropertyConstants + { + // Azure Service Bus // + internal const string AZURE_SB_CLASSNAME = "GeneXus.Messaging.GXAzureServiceBus.AzureServiceBus"; + internal const string AZURE_SB_PROVIDER_CLASSNAME = "GeneXus.Messaging.GXAzureServiceBus.AzureServiceBus, GXAzureServiceBus, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"; + public const string AZURESERVICEBUS = "AZURESERVICEBUS"; + + + public const string MESSAGEBROKER_AZURESB_QUEUENAME = "MESSAGEBROKER_AZURESB_QUEUENAME"; + public const string MESSAGEBROKER_AZURESB_QUEUECONNECTION = "MESSAGEBROKER_AZURESB_QUEUECONNECTION"; + public const string QUEUE_NAME = "QUEUENAME"; + public const string QUEUE_CONNECTION_STRING = "QUEUECONNECTION"; + public const string MESSAGE_BROKER = "MESSAGEBROKER"; + } +} diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs new file mode 100644 index 000000000..8ed48053d --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using GeneXus.Encryption; +using GeneXus.Messaging.Common; +using GeneXus.Services; +using log4net; + +namespace GeneXus.Messaging.Common +{ + public class ServiceSettings + { + static readonly ILog logger = log4net.LogManager.GetLogger(typeof(ServiceSettings)); + + internal GXService service; + public string serviceNameResolver { get; } + public string name { get; } + + public ServiceSettings(string serviceNameResolver, string name, GXService gXService) + { + this.serviceNameResolver = serviceNameResolver; + this.name = name; + this.service = gXService; + } + + public string GetEncryptedPropertyValue(string propertyName, string alternativePropertyName = null) + { + String value = GetEncryptedPropertyValue(propertyName, alternativePropertyName, null); + if (value == null) + { + String errorMessage = String.Format($"Service configuration error - Property name {ResolvePropertyName(propertyName)} must be defined"); + logger.Fatal(errorMessage); + throw new Exception(errorMessage); + } + return value; + } + public string GetEncryptedPropertyValue(string propertyName, string alternativePropertyName, string defaultValue) + { + String value = GetPropertyValue(propertyName, alternativePropertyName, defaultValue); + if (!String.IsNullOrEmpty(value)) + { + try + { + string ret = String.Empty; + if (CryptoImpl.Decrypt(ref ret, value)) + { + value = ret; + } + } + catch (Exception) + { + logger.Warn($"Could not decrypt property name: {ResolvePropertyName(propertyName)}"); + } + } + return value; + } + + internal string GetPropertyValue(string propertyName, string alternativePropertyName = null) + { + String value = GetPropertyValue(propertyName, alternativePropertyName, null); + if (value == null) + { + String errorMessage = String.Format($"Service configuration error - Property name {ResolvePropertyName(propertyName)} must be defined"); + logger.Fatal(errorMessage); + throw new Exception(errorMessage); + } + return value; + } + + internal string GetPropertyValue(string propertyName, string alternativePropertyName, string defaultValue) + { + String value = null; + value = string.IsNullOrEmpty(value) ? GetPropertyValueImpl(ResolvePropertyName(propertyName)) : value; + value = string.IsNullOrEmpty(value) ? GetPropertyValueImpl(propertyName) : value; + value = string.IsNullOrEmpty(value) ? GetPropertyValueImpl(alternativePropertyName) : value; + value = string.IsNullOrEmpty(value) ? defaultValue : value; + return value; + } + + internal string GetPropertyValueImpl(string propertyName) + { + String value = null; + if (!string.IsNullOrEmpty(propertyName)) + { + value = Environment.GetEnvironmentVariable(propertyName); + if (service != null && value == null) + { + value = service.Properties.Get(propertyName); + } + } + return value; + } + + internal string ResolvePropertyName(string propertyName) + { + return $"{serviceNameResolver}_{name}_{propertyName}"; + } + } +} diff --git a/dotnet/src/dotnetframework/GxClasses/Services/Storage/GXServices.cs b/dotnet/src/dotnetframework/GxClasses/Services/Storage/GXServices.cs index 5da88678d..dd6c31e3c 100644 --- a/dotnet/src/dotnetframework/GxClasses/Services/Storage/GXServices.cs +++ b/dotnet/src/dotnetframework/GxClasses/Services/Storage/GXServices.cs @@ -23,6 +23,7 @@ public class GXServices public static string SESSION_SERVICE = "Session"; public static string WEBNOTIFICATIONS_SERVICE = "WebNotifications"; public static string QUEUE_SERVICE = "QueueService"; + public static string MESSAGEBROKER_SERVICE = "MessageBrokerService"; private static string[] SERVICES_FILE = new string[] { "CloudServices.dev.config", "CloudServices.config" }; [System.Diagnostics.CodeAnalysis.SuppressMessage("GxFxCopRules", "CR1000:EnforceThreadSafeType")] private Dictionary services = new Dictionary(); diff --git a/dotnet/test/DotNetCoreUnitTest/DotNetCoreUnitTest.csproj b/dotnet/test/DotNetCoreUnitTest/DotNetCoreUnitTest.csproj index 4cf8ced49..efa02aa7a 100644 --- a/dotnet/test/DotNetCoreUnitTest/DotNetCoreUnitTest.csproj +++ b/dotnet/test/DotNetCoreUnitTest/DotNetCoreUnitTest.csproj @@ -76,6 +76,7 @@ + diff --git a/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs b/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs new file mode 100644 index 000000000..5324b6976 --- /dev/null +++ b/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using GeneXus.Messaging.Common; +using Xunit; + + +#pragma warning disable CA1031 // Do not catch general exception types +namespace UnitTesting +{ + [Collection("Sequential")] + public abstract class AzureMessageBrokerTest + { + + private IMessageBroker messageBroker; + + public AzureMessageBrokerTest(string queueName, Type queueType) + { + bool testEnabled = Environment.GetEnvironmentVariable("AZURESB_TEST_ENABLED") == "true"; + //Skip.IfNot(testEnabled, "Environment variables not set"); + + if (queueName == GeneXus.Messaging.GXAzureServiceBus.AzureServiceBus.Name) + { + //Environment variables needed here + Environment.SetEnvironmentVariable("MESSAGEBROKER_AZURESB_QUEUENAME", ""); + Environment.SetEnvironmentVariable("MESSAGEBROKER_AZURESB_QUEUECONNECTION", ""); + + messageBroker = (IMessageBroker)Activator.CreateInstance(queueType); + Assert.NotNull(messageBroker); + } + } + + [SkippableFact] + public void TestSendOneMessageMethod() + { + BrokerMessage brokerMessage = new BrokerMessage(); + brokerMessage.MessageId = "TestMsgId"; + brokerMessage.MessageBody = "This is the message body"; + + bool success = messageBroker.SendMessage(brokerMessage); + + Assert.True(success); + + } + + [SkippableFact] + public void TestSendBatchMessagesMethod() + { + BrokerMessage brokerMessage1 = new BrokerMessage(); + brokerMessage1.MessageId = "TestMsgId1"; + brokerMessage1.MessageBody = "This is the message body 1"; + + BrokerMessage brokerMessage2 = new BrokerMessage(); + brokerMessage2.MessageId = "TestMsgId2"; + brokerMessage2.MessageBody = "This is the message body 2"; + + IList messages = new List(); + messages.Add(brokerMessage1); + messages.Add(brokerMessage2); + + BrokerMessageOptions options = new BrokerMessageOptions(); + + bool success = messageBroker.SendMessages(messages, options); + + Assert.True(success); + } + [SkippableFact] + public void TestGetBatchMessagesMethod() + { + BrokerMessageOptions options = new BrokerMessageOptions(); + IList messages = messageBroker.GetMessages(options, out bool success); + Assert.True(success); + } + } +} +#pragma warning restore CA1031 // Do not catch general exception types \ No newline at end of file diff --git a/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureServiceBusTest.cs b/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureServiceBusTest.cs new file mode 100644 index 000000000..fa400edaa --- /dev/null +++ b/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureServiceBusTest.cs @@ -0,0 +1,13 @@ +using GeneXus.Messaging.GXAzureServiceBus; +using UnitTesting; + +namespace DotNetUnitTest +{ + public class AzureServiceBusTest : AzureMessageBrokerTest + { + public AzureServiceBusTest() : base(AzureServiceBus.Name, typeof(AzureServiceBus)) + { + } + + } +} \ No newline at end of file From 611c7e9622f0f5287d02a26502192c4613758e7c Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Sun, 10 Jul 2022 22:03:52 -0300 Subject: [PATCH 02/13] Skip tests if variables are not set. --- .../DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs b/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs index 5324b6976..d12086cd6 100644 --- a/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs +++ b/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs @@ -16,7 +16,7 @@ public abstract class AzureMessageBrokerTest public AzureMessageBrokerTest(string queueName, Type queueType) { bool testEnabled = Environment.GetEnvironmentVariable("AZURESB_TEST_ENABLED") == "true"; - //Skip.IfNot(testEnabled, "Environment variables not set"); + Skip.IfNot(testEnabled, "Environment variables not set"); if (queueName == GeneXus.Messaging.GXAzureServiceBus.AzureServiceBus.Name) { From a0d8b90532b280b07eb6f5d1736a6da377ab3b4a Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Tue, 9 Aug 2022 12:53:51 -0300 Subject: [PATCH 03/13] Add Packege Id to the project --- .../Messaging/GXMessageBroker/GXMessageBroker.csproj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj index 0e32bdadb..a1fc0121d 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/GXMessageBroker.csproj @@ -1,7 +1,9 @@ - + net6.0 + GeneXus.Message.MessageBroker + Broker Messaging TRACE;DEBUG;NETCORE From 611f1cad7d5064d45af226f7e8ee2b91d56b853b Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Wed, 14 Sep 2022 19:59:04 -0300 Subject: [PATCH 04/13] Add PackageId to Service Bus package --- .../Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj index 472f9f52b..e7274a6f5 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj @@ -2,6 +2,8 @@ net6.0 + GeneXus.Azure.ServiceBus + Azure ServiceBus Messaging From d8d7fdbea2d059d1baffd546a85d1e6d1a13fbc5 Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Sun, 25 Sep 2022 19:08:06 -0300 Subject: [PATCH 05/13] support all options of Azure SB API --- .../GXAzureServiceBus/AzureServiceBus.cs | 746 ++++++++++++++---- .../GXAzureServiceBus.csproj | 2 +- .../ServiceBusMessageBrokerProvider.cs | 120 ++- .../GXMessageBroker/MessageBroker.cs | 51 +- .../GXMessageBroker/MessageBrokerProvider.cs | 4 +- .../Messaging/GXMessageBroker/MessageQueue.cs | 88 ++- .../GXMessageBroker/PropertyConstants.cs | 14 +- .../GXMessageBroker/ServiceSettings.cs | 5 + 8 files changed, 795 insertions(+), 235 deletions(-) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs index 863df75d1..0bbd6ffbe 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs @@ -1,6 +1,8 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection; +using System.Runtime.Serialization; using System.Threading.Tasks; using Azure.Messaging.ServiceBus; using GeneXus.Messaging.Common; @@ -12,125 +14,358 @@ namespace GeneXus.Messaging.GXAzureServiceBus { public class AzureServiceBus : MessageBrokerBase, IMessageBroker { - + private const int MAX_MESSAGES_DEFAULT = 10; + static readonly ILog logger = log4net.LogManager.GetLogger(typeof(AzureServiceBus)); public static String Name = "AZURESB"; + + private ConcurrentDictionary m_messages = new ConcurrentDictionary(); ServiceBusClient _serviceBusClient { get; set; } private string _queueOrTopicName { get; set; } private string _connectionString { get; set; } + private string _subscriptionName { get; set; } private ServiceBusSender _sender { get; set; } - - static readonly ILog logger = log4net.LogManager.GetLogger(typeof(AzureServiceBus)); + private ServiceBusReceiver _receiver { get; set; } + private ServiceBusSessionReceiver _sessionReceiver { get; set; } + private ServiceBusSessionReceiverOptions _sessionReceiverOptions { get; set; } + private bool _sessionEnabled { get; set; } + private string _sessionId { get; set; } public AzureServiceBus() : this(null) { } - public AzureServiceBus(GXService providerService) : base(providerService) { Initialize(providerService); } - - public void Dispose() - { - Task task = Task.Run(async () => await ServiceClientDisposeAsync()); - } - private async Task ServiceClientDisposeAsync() - { - await _serviceBusClient.DisposeAsync().ConfigureAwait(false); - } - - private async Task RemoveMessageAsync(ServiceBusReceivedMessage serviceBusReceivedMessage) - { - ServiceBusReceiver receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName); - await receiver.CompleteMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false); - await receiver.DisposeAsync().ConfigureAwait(false); - } - private void Initialize(GXService providerService) { ServiceSettings serviceSettings = new(PropertyConstants.MESSAGE_BROKER, Name, providerService); _queueOrTopicName = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.QUEUE_NAME); _connectionString = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.QUEUE_CONNECTION_STRING); + _subscriptionName = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.TOPIC_SUBSCRIPTION); + + _sessionEnabled = Convert.ToBoolean(serviceSettings.GetEncryptedPropertyValue(PropertyConstants.SESSION_ENABLED)); + + ServiceBusReceiverOptions serviceBusReceiverOptions = new ServiceBusReceiverOptions(); + _sessionReceiverOptions = new ServiceBusSessionReceiverOptions(); + + string receiveMode = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVE_MODE); + string prefetchCount = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.PREFETCH_COUNT); + string receiverIdentifier = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVER_IDENTIFIER); ; + _sessionId = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVER_SESSIONID); + + if (!string.IsNullOrEmpty(receiveMode)) + { + if (_sessionEnabled) + _sessionReceiverOptions.ReceiveMode = (ServiceBusReceiveMode)Convert.ToInt16(receiveMode); + else + serviceBusReceiverOptions.ReceiveMode = (ServiceBusReceiveMode)Convert.ToInt16(receiveMode); + } + if (!string.IsNullOrEmpty(prefetchCount)) + { + int prefetchcnt = Convert.ToInt32(prefetchCount); + if (prefetchcnt != 0) + { + if (_sessionEnabled) + _sessionReceiverOptions.PrefetchCount = prefetchcnt; + else + serviceBusReceiverOptions.PrefetchCount = prefetchcnt; + } + } + if (!string.IsNullOrEmpty(receiverIdentifier)) + { + if (_sessionEnabled) + _sessionReceiverOptions.Identifier = receiverIdentifier; + else + serviceBusReceiverOptions.Identifier = receiverIdentifier; + } + + string senderIdentifier = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.SENDER_IDENTIFIER); + + ServiceBusSenderOptions serviceBusSenderOptions = new ServiceBusSenderOptions(); + if (!string.IsNullOrEmpty(senderIdentifier)) + serviceBusSenderOptions.Identifier = senderIdentifier; //TO DO Consider connection options here + //https://docs.microsoft.com/en-us/javascript/api/@azure/service-bus/servicebusclientoptions?view=azure-node-latest#@azure-service-bus-servicebusclientoptions-websocketoptions + try { _serviceBusClient = new ServiceBusClient(_connectionString); if (_serviceBusClient != null) - { - _sender = _serviceBusClient.CreateSender(_queueOrTopicName); + { + _sender = _serviceBusClient.CreateSender(_queueOrTopicName, serviceBusSenderOptions); + + if (_sessionEnabled && _sender != null) + { + if (!string.IsNullOrEmpty(_sessionId)) + { + if (string.IsNullOrEmpty(_subscriptionName)) + { + Task task; + task = Task.Run(async () => await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _sessionId, _sessionReceiverOptions).ConfigureAwait(false)); + _sessionReceiver = task.Result; + } + else + { + Task task; + task = Task.Run(async () => await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _subscriptionName, _sessionId, _sessionReceiverOptions).ConfigureAwait(false)); + _sessionReceiver = task.Result; + } + } + else + { + if (string.IsNullOrEmpty(_subscriptionName)) + { + Task task; + task = Task.Run(async () => await _serviceBusClient.AcceptNextSessionAsync(_queueOrTopicName, _sessionReceiverOptions).ConfigureAwait(false)); + _sessionReceiver = task.Result; + } + else + { + Task task; + task = Task.Run(async () => await _serviceBusClient.AcceptNextSessionAsync(_queueOrTopicName, _subscriptionName, _sessionReceiverOptions).ConfigureAwait(false)); + _sessionReceiver = task.Result; + } + } + } + else + if (string.IsNullOrEmpty(_subscriptionName)) + _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, serviceBusReceiverOptions); + + else + _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, _subscriptionName, serviceBusReceiverOptions); } } catch (Exception ex) { GXLogging.Error(logger, ex.Message); - } + } + } + public override string GetName() + { + return Name; } - public bool GetMessageFromException(Exception ex, SdtMessages_Message msg) + #region Async methods + private async Task ServiceClientDisposeAsync() { - try + await _serviceBusClient.DisposeAsync().ConfigureAwait(false); + } + private async Task sendAsync(ServiceBusMessage serviceBusMessage, string options) + { + SendMessageOptions sendOptions = JSONHelper.Deserialize(options); + if ((sendOptions != null) && (!string.IsNullOrEmpty(sendOptions.ScheduledEnqueueTime))) { - Azure.RequestFailedException az_ex = (Azure.RequestFailedException)ex; - msg.gxTpr_Id = az_ex.ErrorCode; - msg.gxTpr_Description = az_ex.Message; - return true; + try + { + await _sender.ScheduleMessageAsync(serviceBusMessage, DateTimeOffset.Parse(sendOptions.ScheduledEnqueueTime)).ConfigureAwait(false); + return true; + } + catch (Exception ex) + { + throw ex; + } } - catch (Exception) + else { - return false; + try + { + await _sender.SendMessageAsync(serviceBusMessage).ConfigureAwait(false); + return true; + } + catch (Exception ex) + { + throw ex; + } } } - - public override string GetName() + private async Task SendMessagesBatchAsync(IList brokerMessages, string options) { - return Name; - } + bool success = false; + if (_sender == null) + { + throw new Exception("There was an error at the Message Broker initialization."); + } + else + { + ServiceBusMessage serviceBusMessage; + IList serviceBusMessages = new List(); + foreach (BrokerMessage brokerMessage in brokerMessages) + { + serviceBusMessage = BrokerMessageToServiceBusMessage(brokerMessage); + serviceBusMessages.Add(serviceBusMessage); + } - public bool SendMessage(BrokerMessage brokerMessage) + SendMessageOptions sendOptions = JSONHelper.Deserialize(options); + if ((sendOptions != null) && (!string.IsNullOrEmpty(sendOptions.ScheduledEnqueueTime))) + { + try + { + await _sender.ScheduleMessagesAsync(serviceBusMessages, DateTimeOffset.Parse(sendOptions.ScheduledEnqueueTime)).ConfigureAwait(false); + success = true; + } + catch (Exception ex) + { + GXLogging.Error(logger, ex.Message.ToString()); + } + } + else + { + try + { + await _sender.SendMessagesAsync(serviceBusMessages).ConfigureAwait(false); + success = true; + } + catch (Exception ex) + { + GXLogging.Error(logger, ex.Message.ToString()); + } + } + } + return success; + } + private async Task> ReceiveMessagesAsync(string options) { - bool success = false; - ServiceBusMessage serviceBusMessage = BrokerMessageToServiceBusMessage(brokerMessage); + ReceiveMessageOptions receiveOptions = JSONHelper.Deserialize(options); + + IReadOnlyList receivedMessages; try { - Task task; - if (_sender != null) + ServiceBusReceiverOptions serviceBusReceiverOptions = new ServiceBusReceiverOptions(); + + if ((receiveOptions != null) && (!string.IsNullOrEmpty(receiveOptions.SessionId)) && _sessionEnabled && (receiveOptions.SessionId != _sessionId)) { - task = Task.Run(async () => await sendAsync(serviceBusMessage)); - success = task.Result; + //Create new session receiver + + if (string.IsNullOrEmpty(_subscriptionName)) + { + _sessionReceiver = await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, receiveOptions.SessionId, _sessionReceiverOptions).ConfigureAwait(false); + _sessionId = receiveOptions.SessionId; + } + else + { + _sessionReceiver = await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _subscriptionName, receiveOptions.SessionId, _sessionReceiverOptions).ConfigureAwait(false); + _sessionId = receiveOptions.SessionId; + } + } + + int maxMessagesReceive = MAX_MESSAGES_DEFAULT; + if ((receiveOptions != null) && (receiveOptions.MaxMessages != 0)) + maxMessagesReceive = receiveOptions.MaxMessages; + + TimeSpan maxWait = TimeSpan.Zero; + if ((receiveOptions != null) && receiveOptions.MaxWaitTime != 0) + maxWait = TimeSpan.FromSeconds(receiveOptions.MaxWaitTime); + + ServiceBusReceiver receiver = _receiver; + if ((_sessionReceiver != null) && (_sessionEnabled)) + receiver = _sessionReceiver; + + if ((receiveOptions != null) && (receiveOptions.ReceiveDeferredSequenceNumbers != null) && (receiveOptions.ReceiveDeferredSequenceNumbers.Count > 0)) + { + receivedMessages = await receiver.ReceiveDeferredMessagesAsync(receiveOptions.ReceiveDeferredSequenceNumbers).ConfigureAwait(false); } else { - throw new Exception("There was an error at the Message Broker initialization."); + + if (maxWait == TimeSpan.Zero) + if ((receiveOptions != null) && (receiveOptions.PeekReceive != null) && (receiveOptions.PeekReceive.Peek)) + if (receiveOptions.PeekReceive.PeekFromSequenceNumber != 0) + receivedMessages = await receiver.PeekMessagesAsync(maxMessages: maxMessagesReceive, receiveOptions.PeekReceive.PeekFromSequenceNumber).ConfigureAwait(false); + else + receivedMessages = await receiver.PeekMessagesAsync(maxMessages: maxMessagesReceive).ConfigureAwait(false); + else + receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive).ConfigureAwait(false); + else + receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive, maxWaitTime: maxWait).ConfigureAwait(false); } + return receivedMessages; } - catch (AggregateException ae) + catch (Exception ex) { - throw ae; + GXLogging.Error(logger, ex.Message.ToString()); } - return success; + return null; } - private async Task sendAsync(ServiceBusMessage serviceBusMessage) + private async Task ReceiveMessageAsync(string options) { + ReceiveMessageOptions receiveOptions = JSONHelper.Deserialize(options); + ServiceBusReceivedMessage receivedMessage; + try - { - await _sender.SendMessageAsync(serviceBusMessage).ConfigureAwait(false); - return true; + { + ServiceBusReceiverOptions serviceBusReceiverOptions = new ServiceBusReceiverOptions(); + + if ((receiveOptions != null) && (!string.IsNullOrEmpty(receiveOptions.SessionId)) && _sessionEnabled && (receiveOptions.SessionId != _sessionId)) + { + //Create new session receiver + + if (string.IsNullOrEmpty(_subscriptionName)) + { + _sessionReceiver = await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, receiveOptions.SessionId, _sessionReceiverOptions).ConfigureAwait(false); + _sessionId = receiveOptions.SessionId; + } + else + { + _sessionReceiver = await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _subscriptionName, receiveOptions.SessionId, _sessionReceiverOptions).ConfigureAwait(false); + _sessionId = receiveOptions.SessionId; + } + } + + TimeSpan maxWait = TimeSpan.Zero; + if ((receiveOptions != null) && receiveOptions.MaxWaitTime != 0) + maxWait = TimeSpan.FromSeconds(receiveOptions.MaxWaitTime); + + ServiceBusReceiver receiver = _receiver; + if ((_sessionReceiver != null) && (_sessionEnabled)) + receiver = _sessionReceiver; + + if ((receiveOptions != null) && (receiveOptions.ReceiveDeferredSequenceNumbers != null) && (receiveOptions.ReceiveDeferredSequenceNumbers.Count > 0)) + { + receivedMessage = await receiver.ReceiveDeferredMessageAsync(receiveOptions.ReceiveDeferredSequenceNumbers[0]).ConfigureAwait(false); + } + else + { + if (maxWait != TimeSpan.Zero) + receivedMessage = await receiver.ReceiveMessageAsync(maxWaitTime: maxWait).ConfigureAwait(false); + else + if ((receiveOptions != null) && (receiveOptions.PeekReceive != null) && (receiveOptions.PeekReceive.Peek)) + if (receiveOptions.PeekReceive.PeekFromSequenceNumber != 0) + receivedMessage = await receiver.PeekMessageAsync(receiveOptions.PeekReceive.PeekFromSequenceNumber).ConfigureAwait(false); + else + receivedMessage = await receiver.PeekMessageAsync().ConfigureAwait(false); + else + receivedMessage = await receiver.ReceiveMessageAsync().ConfigureAwait(false); + } + return receivedMessage; } catch (Exception ex) { - return false; - throw ex; + GXLogging.Error(logger, ex.Message.ToString()); } + return null; } - bool IMessageBroker.SendMessages(IList brokerMessages, BrokerMessageOptions messageQueueOptions) + #endregion + + #region API Methods + public bool SendMessage(BrokerMessage brokerMessage, string options) { bool success = false; + ServiceBusMessage serviceBusMessage = BrokerMessageToServiceBusMessage(brokerMessage); try { - Task task = Task.Run(async () => await SendMessagesBatchAsync(brokerMessages)); - success = task.Result; + Task task; + if (_sender != null) + { + task = Task.Run(async () => await sendAsync(serviceBusMessage, options)); + success = task.Result; + } + else + { + throw new Exception("There was an error at the Message Broker initialization."); + } } catch (AggregateException ae) { @@ -138,47 +373,34 @@ bool IMessageBroker.SendMessages(IList brokerMessages, BrokerMess } return success; } - - private async Task SendMessagesBatchAsync(IList brokerMessages) + bool IMessageBroker.SendMessages(IList brokerMessages, string options) { bool success = false; - if (_sender == null) + try { - throw new Exception("There was an error at the Message Broker initialization."); + Task task = Task.Run(async () => await SendMessagesBatchAsync(brokerMessages, options)); + success = task.Result; } - else + catch (AggregateException ae) { - ServiceBusMessage serviceBusMessage; - IList serviceBusMessages = new List(); - foreach (BrokerMessage brokerMessage in brokerMessages) - { - serviceBusMessage = BrokerMessageToServiceBusMessage(brokerMessage); - serviceBusMessages.Add(serviceBusMessage); - } - try - { - await _sender.SendMessagesAsync(serviceBusMessages).ConfigureAwait(false); - success = true; - } - catch (Exception ex) - { - GXLogging.Error(logger, ex.Message.ToString()); - } + throw ae; } return success; } - IList IMessageBroker.GetMessages(BrokerMessageOptions messageQueueOptions, out bool success) + IList IMessageBroker.GetMessages(string options, out bool success) { IList brokerMessages = new List(); success = false; try { - Task> receivedMessages = Task>.Run(async () => await ReceiveMessagesAsync(messageQueueOptions)); + Task> receivedMessages = Task>.Run(async () => await ReceiveMessagesAsync(options)); if (receivedMessages != null && receivedMessages.Result != null) { foreach (ServiceBusReceivedMessage serviceBusReceivedMessage in receivedMessages.Result) { - brokerMessages.Add(SBReceivedMessageToBrokerMessage(serviceBusReceivedMessage)); + if (serviceBusReceivedMessage != null) + if (AddOrUpdateStoredServiceReceivedMessage(serviceBusReceivedMessage)) + brokerMessages.Add(SBReceivedMessageToBrokerMessage(serviceBusReceivedMessage)); } success = true; } @@ -190,55 +412,106 @@ IList IMessageBroker.GetMessages(BrokerMessageOptions messageQueu return brokerMessages; } - private async Task> ReceiveMessagesAsync(BrokerMessageOptions messageQueueOptions) + public bool ConsumeMessage(BrokerMessage brokerMessage, string options) { - IReadOnlyList receivedMessages; - try + ConsumeMessageOptions consumeOptions = JSONHelper.Deserialize(options); + if (consumeOptions != null) { - ServiceBusReceiverOptions serviceBusReceiverOptions = new ServiceBusReceiverOptions(); - - if (messageQueueOptions.ReceiveMode == 1) // Valid values : PeekLock (0), ReceiveAndDelete (1) - serviceBusReceiverOptions.ReceiveMode = ServiceBusReceiveMode.ReceiveAndDelete; + ServiceBusReceiver receiver = _receiver; + if ((_sessionReceiver != null) && (_sessionEnabled)) + receiver = _sessionReceiver; - if (messageQueueOptions.PrefetchCount != 0) - serviceBusReceiverOptions.PrefetchCount = messageQueueOptions.PrefetchCount; - - ServiceBusReceiver receiver; - - if (!string.IsNullOrEmpty(messageQueueOptions.SubscriptionName)) + ServiceBusReceivedMessage serviceBusReceviedMessage = GetStoredServiceBusReceivedMessage(brokerMessage); + if (serviceBusReceviedMessage != null) { - receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, messageQueueOptions.SubscriptionName, serviceBusReceiverOptions); - } - else - { - receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, serviceBusReceiverOptions); + try + { + Task task; + switch (consumeOptions.ConsumeMode) + { + case ConsumeMessageOptions.ConsumeModeOpts.Complete: + { + task = Task.Run(async () => await receiver.CompleteMessageAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + RemoveStoredServiceBusReceivedMessage(brokerMessage); + break; + } + case ConsumeMessageOptions.ConsumeModeOpts.Abandon: + { + task = Task.Run(async () => await receiver.AbandonMessageAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + break; + } + case ConsumeMessageOptions.ConsumeModeOpts.DeadLetter: + { + task = Task.Run(async () => await receiver.DeadLetterMessageAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + RemoveStoredServiceBusReceivedMessage(brokerMessage); + break; + } + case ConsumeMessageOptions.ConsumeModeOpts.Defer: + { + task = Task.Run(async () => await receiver.DeferMessageAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + break; + } + case ConsumeMessageOptions.ConsumeModeOpts.RenewMessageLock: + { + task = Task.Run(async () => await receiver.RenewMessageLockAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + break; + } + } + return true; + } + catch (AggregateException ae) + { + throw ae; + } } + } + return false; + } - int maxMessagesReceive = 1; - TimeSpan maxWaitTimeout = TimeSpan.Zero; - if (messageQueueOptions != null && messageQueueOptions.WaitTimeout != 0) - maxWaitTimeout = TimeSpan.FromSeconds(messageQueueOptions.WaitTimeout); - - if (messageQueueOptions != null && messageQueueOptions.MaxNumberOfMessages != 0) - maxMessagesReceive = messageQueueOptions.MaxNumberOfMessages; - - if (maxWaitTimeout == TimeSpan.Zero) - receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive).ConfigureAwait(false); - else - receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive, maxWaitTime: maxWaitTimeout).ConfigureAwait(false); - - await receiver.DisposeAsync().ConfigureAwait(false); - - return receivedMessages; + public BrokerMessage GetMessage(string options, out bool success) + { + BrokerMessage brokerMessage = new BrokerMessage(); + success = false; + try + { + Task receivedMessage = Task.Run(async () => await ReceiveMessageAsync(options)); + if (receivedMessage != null && receivedMessage.Result != null) + { + ServiceBusReceivedMessage serviceBusReceivedMessage = receivedMessage.Result; + if (AddOrUpdateStoredServiceReceivedMessage(serviceBusReceivedMessage)) + { + success = true; + return (SBReceivedMessageToBrokerMessage(serviceBusReceivedMessage)); + } + } } - catch (Exception ex) + catch (AggregateException ae) { - GXLogging.Error(logger, ex.Message.ToString()); + throw ae; + } + return brokerMessage; + } + public void Dispose() + { + Task task = Task.Run(async () => await ServiceClientDisposeAsync().ConfigureAwait(false)); + } + public bool GetMessageFromException(Exception ex, SdtMessages_Message msg) + { + try + { + Azure.RequestFailedException az_ex = (Azure.RequestFailedException)ex; + msg.gxTpr_Id = az_ex.ErrorCode; + msg.gxTpr_Description = az_ex.Message; + return true; + } + catch (Exception) + { + return false; } - return null; } + #endregion - #region Transform Methods + #region Transformation Methods private ServiceBusMessage BrokerMessageToServiceBusMessage(BrokerMessage brokerMessage) { ServiceBusMessage serviceBusMessage = new ServiceBusMessage(brokerMessage.MessageBody); @@ -255,92 +528,221 @@ private BrokerMessage SBReceivedMessageToBrokerMessage(ServiceBusReceivedMessage BrokerMessage brokerMessage = new BrokerMessage(); brokerMessage.MessageId = serviceBusReceivedMessage.MessageId; brokerMessage.MessageBody = serviceBusReceivedMessage.Body.ToString(); - + LoadReceivedMessageProperties(serviceBusReceivedMessage, ref brokerMessage); return brokerMessage; } - private void LoadReceivedMessageProperties(ServiceBusReceivedMessage serviceBusReceivedMessage, ref BrokerMessage brokerMessage) - { - GXProperties properties = new GXProperties(); - - if (serviceBusReceivedMessage != null) - { - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.Subject)) - properties.Add("Subject", serviceBusReceivedMessage.Subject); - - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.ReplyToSessionId)) - properties.Add("ReplyToSessionId", serviceBusReceivedMessage.ReplyToSessionId); + #endregion - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.DeadLetterSource)) - properties.Add("DeadLetterSource", serviceBusReceivedMessage.DeadLetterSource); + #region Data + [DataContract] + internal class SendMessageOptions + { + [DataMember] + internal string ScheduledEnqueueTime { get; set; } + } - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.ContentType)) - properties.Add("ContentType", serviceBusReceivedMessage.ContentType); + [DataContract()] + internal class ReceiveMessageOptions + { + int _maxmessages; + int _maxwaittime; + string _sessionid; + PeekReceiveOpts _peekreceiveopts; + IList _receivedeferredsequencenumbers; - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.CorrelationId)) - properties.Add("CorrelationId", serviceBusReceivedMessage.CorrelationId); + [DataMember()] + internal int MaxMessages { get => _maxmessages; set => _maxmessages = value; } - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.DeadLetterErrorDescription)) - properties.Add("DeadLetterErrorDescription", serviceBusReceivedMessage.DeadLetterErrorDescription); + [DataMember()] + internal int MaxWaitTime { get => _maxwaittime; set => _maxwaittime = value; } - if (string.IsNullOrEmpty(serviceBusReceivedMessage.DeadLetterReason)) - properties.Add("DeadLetterReason", serviceBusReceivedMessage.DeadLetterReason); + [DataMember()] + internal string SessionId { get => _sessionid; set => _sessionid = value ; } - if (serviceBusReceivedMessage.DeliveryCount != 0) - properties.Add("DeliveryCount", serviceBusReceivedMessage.DeliveryCount.ToString()); + [DataMember()] + internal PeekReceiveOpts PeekReceive { get => _peekreceiveopts; set => _peekreceiveopts = value; } - if (serviceBusReceivedMessage.EnqueuedSequenceNumber != 0) - properties.Add("EnqueuedSequenceNumber", serviceBusReceivedMessage.EnqueuedSequenceNumber.ToString()); + [DataMember()] + internal IList ReceiveDeferredSequenceNumbers { get => _receivedeferredsequencenumbers; set => _receivedeferredsequencenumbers = value; } + } - properties.Add("EnqueuedTime", serviceBusReceivedMessage.EnqueuedTime.UtcDateTime.ToString()); + [DataContract()] + public class PeekReceiveOpts + { + bool _peek; + long _peekfromsequencenumber; - properties.Add("ExpiresAt", serviceBusReceivedMessage.ExpiresAt.UtcDateTime.ToString()); - properties.Add("LockedUntil", serviceBusReceivedMessage.LockedUntil.UtcDateTime.ToString()); + [DataMember()] + internal bool Peek { get => _peek; set => _peek = value; } - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.LockToken)) - properties.Add("LockToken", serviceBusReceivedMessage.LockToken); + [DataMember()] + internal long PeekFromSequenceNumber { get => _peekfromsequencenumber ; set => _peekfromsequencenumber = value; } + } - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.PartitionKey)) - properties.Add("PartitionKey", serviceBusReceivedMessage.PartitionKey); + [DataContract] + internal class ConsumeMessageOptions + { + [DataMember] + internal ConsumeModeOpts ConsumeMode { get; set; } + internal enum ConsumeModeOpts + { + Complete, + Abandon, + DeadLetter, + Defer, + RenewMessageLock + } + } - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.ReplyTo)) - properties.Add("ReplyTo", serviceBusReceivedMessage.ReplyTo); + #endregion - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.SessionId)) - properties.Add("SessionId", serviceBusReceivedMessage.SessionId); + #region helper methods - properties.Add("TimeToLive", serviceBusReceivedMessage.TimeToLive.ToString()); + private ServiceBusReceivedMessage GetStoredServiceBusReceivedMessage(BrokerMessage message) + { + string messageIdentifier = GetMessageIdentifier(message); + if (m_messages.TryGetValue(messageIdentifier, out ServiceBusReceivedMessage serviceBusReceivedMessage)) + return serviceBusReceivedMessage; + else + return null; + } + private void RemoveStoredServiceBusReceivedMessage(BrokerMessage message) + { + string messageIdentifier = GetMessageIdentifier(message); + lock (m_messages) + { + if (m_messages.TryGetValue(messageIdentifier, out ServiceBusReceivedMessage serviceBusReceivedMessage)) + { + KeyValuePair keyValuePair = new KeyValuePair(messageIdentifier, serviceBusReceivedMessage); + m_messages.TryRemove(keyValuePair); + } + } + } + private bool AddOrUpdateStoredServiceReceivedMessage(ServiceBusReceivedMessage serviceBusReceivedMessage) + { + string messageIdentifier = GetMessageIdentifierFromServiceBus(serviceBusReceivedMessage); + if (!string.IsNullOrEmpty(messageIdentifier)) + lock (m_messages) + { + if (m_messages.TryGetValue(messageIdentifier, out ServiceBusReceivedMessage originalMessage)) + { + return (m_messages.TryUpdate(messageIdentifier, serviceBusReceivedMessage, originalMessage)); + } + else + return m_messages.TryAdd(messageIdentifier, serviceBusReceivedMessage); + } + return false; + } - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.ReplyToSessionId)) - properties.Add("ReplyToSessionId", serviceBusReceivedMessage.ReplyToSessionId); + private string GetMessageIdentifier(BrokerMessage message) + { + //The sequence number is a unique 64-bit integer assigned to a message as it is accepted and stored by the broker and functions as its true identifier. + //For partitioned entities, the sequence number is issued relative to the partition. + //https://learn.microsoft.com/en-us/azure/service-bus-messaging/message-sequencing + //Follow this to identify the message + //https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-partitioning#using-a-partition-key - properties.Add("ScheduledEnqueueTime", serviceBusReceivedMessage.ScheduledEnqueueTime.UtcDateTime.ToString()); - if (serviceBusReceivedMessage.SequenceNumber != 0) - properties.Add("SequenceNumber", serviceBusReceivedMessage.SequenceNumber.ToString()); + string messageSequenceNumber = GetMessageSequenceNumber(message); + string messageIdentifier = string.Empty; - properties.Add("State", serviceBusReceivedMessage.State.ToString()); + //Get SessionId of the message + string messageSessionId = GetMessageSessionId(message); + if (!string.IsNullOrEmpty(messageSessionId)) + messageIdentifier = $"{messageSequenceNumber}{messageSessionId}"; + else + { + //Get PartitionKey of the message + string messagePartitionKey = GetMessagePartitionKey(message); + if (!string.IsNullOrEmpty(messagePartitionKey)) + messageIdentifier = $"{messageSequenceNumber}{messagePartitionKey}"; + else + messageIdentifier = $"{messageSequenceNumber}{message.MessageId}"; + } + return messageIdentifier.GetHashCode().ToString(); + } - if (!string.IsNullOrEmpty(serviceBusReceivedMessage.TransactionPartitionKey)) - properties.Add("TransactionPartitionKey", serviceBusReceivedMessage.TransactionPartitionKey); + private string GetMessageIdentifierFromServiceBus(ServiceBusReceivedMessage message) + { + string messageSequenceNumber = message.SequenceNumber.ToString(); + string messageIdentifier = string.Empty; + //Get SessionId of the message + string messageSessionId = message.SessionId; + if (!string.IsNullOrEmpty(messageSessionId)) + messageIdentifier = $"{messageSequenceNumber}{messageSessionId}"; + else + { + //Get PartitionKey of the message + string messagePartitionKey = message.PartitionKey; + if (!string.IsNullOrEmpty(messagePartitionKey)) + messageIdentifier = $"{messageSequenceNumber}{messagePartitionKey}"; + else + messageIdentifier = $"{messageSequenceNumber}{message.MessageId}"; + } + return messageIdentifier.GetHashCode().ToString(); + } + private string GetMessageSequenceNumber(BrokerMessage message) + { + string sequenceNumberValue = string.Empty; + if (message != null) + { + if (message.MessageAttributes.ContainsKey("SequenceNumber")) + sequenceNumberValue = message.MessageAttributes.Get("SequenceNumber"); + } + return sequenceNumberValue; + } + private string GetMessageSessionId(BrokerMessage message) + { + string messageSessionId = string.Empty; + if (message != null) + { + if (message.MessageAttributes.ContainsKey("SessionId")) + messageSessionId = message.MessageAttributes.Get("SessionId"); + } + return messageSessionId; + } + private string GetMessagePartitionKey(BrokerMessage message) + { + string messagePartitionKey = string.Empty; + if (message != null) + { + if (message.MessageAttributes.ContainsKey("PartitionKey")) + messagePartitionKey = message.MessageAttributes.Get("PartitionKey"); + } + return messagePartitionKey; + } + private void LoadReceivedMessageProperties(ServiceBusReceivedMessage serviceBusReceivedMessage, ref BrokerMessage brokerMessage) + { + GXProperties properties = new GXProperties(); - //Application Properties + if (serviceBusReceivedMessage != null) + { brokerMessage.MessageAttributes = new GXProperties(); Type t = serviceBusReceivedMessage.GetType(); PropertyInfo[] props = t.GetProperties(); foreach (PropertyInfo prop in props) { object value; - if (prop.GetIndexParameters().Length == 0 && serviceBusReceivedMessage != null) + if (prop.Name != "ApplicationProperties") { - value = prop.GetValue(serviceBusReceivedMessage); - if (value != null) - brokerMessage.MessageAttributes.Add(prop.Name, value.ToString()); + if (prop.GetIndexParameters().Length == 0 && serviceBusReceivedMessage != null) + { + value = prop.GetValue(serviceBusReceivedMessage); + + if (value != null) + brokerMessage.MessageAttributes.Add(prop.Name, value.ToString()); + } } } + //Application Properties + foreach (KeyValuePair o in serviceBusReceivedMessage.ApplicationProperties) + { + brokerMessage.MessageAttributes.Add(o.Key, o.Value.ToString()); + } } - brokerMessage.MessageAttributes = properties; + } private void LoadMessageProperties(GXProperties properties, ref ServiceBusMessage serviceBusMessage) { @@ -393,7 +795,9 @@ private void LoadMessageProperties(GXProperties properties, ref ServiceBusMessag } } } - #endregion } } + + + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj index e7274a6f5..fded4a3b6 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj @@ -7,7 +7,7 @@ - + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs index 6fadcf7dc..401009749 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections; using GeneXus.Messaging.Common; using GeneXus.Utils; @@ -5,16 +7,128 @@ namespace GeneXus.Messaging.GXAzureServiceBus { public class ServiceBusMessageBrokerProvider { - public MessageQueue Connect(string queueName, string queueConnection, out GXBaseCollection errorMessages, out bool success) + public MessageQueue Connect(string queueName, string connectionString, out GXBaseCollection errorMessages, out bool success) { + System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); GXProperties properties = new GXProperties(); - properties.Add(PropertyConstants. MESSAGEBROKER_AZURESB_QUEUENAME, queueName); - properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUECONNECTION, queueConnection); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString); + + MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect); + errorMessages = errorMessagesConnect; + success = successConnect; + return messageQueue; + } + + public MessageQueue Connect(string topicName, string subcriptionName, string connectionString, out GXBaseCollection errorMessages, out bool success) + { + System.Diagnostics.Debugger.Launch(); + MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); + GXProperties properties = new GXProperties(); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_TOPICNAME, topicName); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME, subcriptionName); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString); + MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect); errorMessages = errorMessagesConnect; success = successConnect; return messageQueue; } + public MessageQueue Connect(string queueName, string connectionString, bool sessionEnabled, GxUserType receiverOptions, string senderIdentifier, out GXBaseCollection errorMessages, out bool success) + { + System.Diagnostics.Debugger.Launch(); + MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); + + ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions); + + GXProperties properties = new GXProperties(); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString); + properties.Add(PropertyConstants.SESSION_ENABLED, sessionEnabled.ToString()); + properties.Add(PropertyConstants.RECEIVE_MODE, options.ReceiveMode.ToString()); + properties.Add(PropertyConstants.PREFETCH_COUNT, options.PrefetchCount.ToString()); + properties.Add(PropertyConstants.RECEIVER_IDENTIFIER, options.Identifier); + properties.Add(PropertyConstants.RECEIVER_SESSIONID, options.SessionId); + properties.Add(PropertyConstants.SENDER_IDENTIFIER, senderIdentifier); + + MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect); + errorMessages = errorMessagesConnect; + success = successConnect; + return messageQueue; + } + + public MessageQueue Connect(string topicName, string subcriptionName, string connectionString, bool sessionEnabled, GxUserType receiverOptions, string senderIdentifier, out GXBaseCollection errorMessages, out bool success) + { + System.Diagnostics.Debugger.Launch(); + MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); + GXProperties properties = new GXProperties(); + ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions); + + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_TOPICNAME, topicName); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME, subcriptionName); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString); + properties.Add(PropertyConstants.SESSION_ENABLED, sessionEnabled.ToString()); + properties.Add(PropertyConstants.RECEIVE_MODE, options.ReceiveMode.ToString()); + properties.Add(PropertyConstants.PREFETCH_COUNT, options.PrefetchCount.ToString()); + properties.Add(PropertyConstants.RECEIVER_IDENTIFIER, options.Identifier); + properties.Add(PropertyConstants.RECEIVER_SESSIONID, options.SessionId); + properties.Add(PropertyConstants.SENDER_IDENTIFIER, senderIdentifier); + + MessageQueue messageQueue = messageBrokerProvider.Connect(PropertyConstants.AZURESERVICEBUS, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect); + errorMessages = errorMessagesConnect; + success = successConnect; + return messageQueue; + } + + #region Transformation methods + private ReceiverOptions TransformGXUserTypeToReceiverOptions(GxUserType options) + { + ReceiverOptions receiverOptions = new ReceiverOptions(); + if (options != null) + { + receiverOptions.ReceiveMode = options.GetPropertyValue("Receivemode"); + receiverOptions.Identifier = options.GetPropertyValue("Identifier"); + receiverOptions.PrefetchCount = options.GetPropertyValue("Prefetchcount"); + receiverOptions.SessionId = options.GetPropertyValue("Sessionid"); + } + return receiverOptions; + } + #endregion + public class ReceiverOptions : GxUserType + { + public short ReceiveMode { get; set; } + public short PrefetchCount { get; set; } + public string Identifier { get; set; } + public string SessionId { get; set; } + + #region Json + private static Hashtable mapper; + public override String JsonMap(String value) + { + if (mapper == null) + { + mapper = new Hashtable(); + } + return (String)mapper[value]; ; + } + + public override void ToJSON() + { + ToJSON(true); + return; + } + + public override void ToJSON(bool includeState) + { + AddObjectProperty("ReceiveMode", ReceiveMode, false); + AddObjectProperty("PrefetchCount", PrefetchCount, false); + AddObjectProperty("Identifier", Identifier, false); + AddObjectProperty("SessionId", Identifier, false); + return; + } + + #endregion + } } } diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs index f86bb79ca..30097724c 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs @@ -7,11 +7,13 @@ namespace GeneXus.Messaging.Common { public interface IMessageBroker { - bool SendMessage(BrokerMessage brokerMessage); - bool SendMessages(IList brokerMessages, BrokerMessageOptions messageQueueOptions); - IList GetMessages(BrokerMessageOptions messageQueueOptions, out bool success); + bool SendMessage(BrokerMessage brokerMessage, string options); + bool SendMessages(IList brokerMessages, string options); + IList GetMessages(string options, out bool success); + BrokerMessage GetMessage(string options, out bool success); void Dispose(); bool GetMessageFromException(Exception ex, SdtMessages_Message msg); + bool ConsumeMessage(BrokerMessage brokerMessage, string options); } public class BrokerMessage : GxUserType { @@ -48,45 +50,6 @@ public override void ToJSON(bool includeState) #endregion } - - public class BrokerMessageResult : GxUserType - { - public string MessageId { get; set; } - public string ServerMessageId { get; set; } - public GXProperties MessageAttributes { get; set; } - public string MessageHandleId { get; set; } - public string MessageStatus { get; set; } = "Unknown"; - - #region Json - private static Hashtable mapper; - public override String JsonMap(String value) - { - if (mapper == null) - { - mapper = new Hashtable(); - } - return (String)mapper[value]; ; - } - - public override void ToJSON() - { - ToJSON(true); - return; - } - - public override void ToJSON(bool includeState) - { - AddObjectProperty("MessageId", MessageId, false); - AddObjectProperty("ServerMessageId", ServerMessageId, false); - AddObjectProperty("MessageHandleId", MessageHandleId, false); - AddObjectProperty("MessageStatus", MessageStatus, false); - - return; - } - - #endregion - } - public class BrokerMessageOptions : GxUserType { public short MaxNumberOfMessages { get; set; } @@ -97,8 +60,8 @@ public class BrokerMessageOptions : GxUserType public int DelaySeconds { get; set; } public string ReceiveRequestAttemptId { get; set; } public bool ReceiveMessageAttributes { get; set; } - public int ReceiveMode { get; set; } - public int PrefetchCount { get; set; } + public short ReceiveMode { get; set; } + public short PrefetchCount { get; set; } public string SubscriptionName { get; set; } } diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs index e890964d0..bfc0d1e25 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs @@ -73,7 +73,9 @@ private static void Preprocess(String name, GXProperties properties) case Providers.AzureServiceBus: className = PropertyConstants.AZURE_SB_CLASSNAME; SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME); - SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_QUEUECONNECTION); + SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_TOPICNAME); + SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME); + SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING); if (string.IsNullOrEmpty(providerService.ClassName) || !providerService.ClassName.Contains(className)) { providerService.ClassName = PropertyConstants.AZURE_SB_PROVIDER_CLASSNAME; diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs index 8345212b8..580c3a3e1 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs @@ -20,7 +20,7 @@ public class MessageQueue private const string SDT_MESSAGE_CLASS_NAME = @"SdtMessage"; private const string SDT_MESSAGEPROPERTY_CLASS_NAME = @"SdtMessageProperty"; //private const string SDT_MESSAGERESULT_CLASS_NAME = @"SdtMessageResult"; - private const string NAMESPACE = @"GeneXus.Programs.genexusmessagingqueue.MessageBroker"; + private const string NAMESPACE = @"GeneXus.Programs.genexusmessagingmessagebroker"; private const string GENEXUS_COMMON_DLL = @"GeneXus.Programs.Common.dll"; public MessageQueue() @@ -73,15 +73,76 @@ public void Dispose() } } - public IList GetMessages(GxUserType messageQueueOptions, out GXBaseCollection errorMessages, out bool success) + public bool ConsumeMessage(GxUserType messageQueue, string options, out GXBaseCollection errorMessages) + { + bool success = false; + errorMessages = new GXBaseCollection(); + GxUserType result = new GxUserType(); + try + { + BrokerMessage brokerQueueMessage = TransformGXUserTypeToBrokerMessage(messageQueue); + LoadAssemblyIfRequired(); + try + { + ValidQueue(); + return (messageBroker.ConsumeMessage(brokerQueueMessage, options)); + } + catch (Exception ex) + { + QueueErrorMessagesSetup(ex, out errorMessages); + success = false; + GXLogging.Error(logger, ex); + } + } + catch (Exception ex) + { + success = false; + GXLogging.Error(logger, ex); + throw ex; + } + return success; + } + public GxUserType GetMessage(string options, out GXBaseCollection errorMessages, out bool success) + { + errorMessages = new GXBaseCollection(); + GxUserType receivedMessage = new GxUserType(); + success = false; + try + { + try + { + ValidQueue(); + BrokerMessage brokerMessage = messageBroker.GetMessage(options, out success); + LoadAssemblyIfRequired(); + + if (TransformBrokerMessage(brokerMessage) is GxUserType result) + { + success = true; + return result; + } + } + catch (Exception ex) + { + QueueErrorMessagesSetup(ex, out errorMessages); + GXLogging.Error(logger, ex); + success = false; + } + } + catch (Exception ex) + { + GXLogging.Error(logger, ex); + success = false; + throw ex; + } + return receivedMessage; + } + public IList GetMessages(string options, out GXBaseCollection errorMessages, out bool success) { errorMessages = new GXBaseCollection(); IList resultMessages = new List(); success = false; try { - BrokerMessageOptions options = TransformOptions(messageQueueOptions); - try { ValidQueue(); @@ -111,7 +172,7 @@ public IList GetMessages(GxUserType messageQueueOptions, out GXBaseC return resultMessages; } - public bool SendMessage(GxUserType messageQueue, out GXBaseCollection errorMessages) + public bool SendMessage(GxUserType messageQueue, string options, out GXBaseCollection errorMessages) { bool success = false; errorMessages = new GXBaseCollection(); @@ -123,7 +184,7 @@ public bool SendMessage(GxUserType messageQueue, out GXBaseCollection errorMessages) + public bool SendMessages(IList queueMessages, string options, out GXBaseCollection errorMessages) { errorMessages = new GXBaseCollection(); bool success = false; try { - BrokerMessageOptions options = TransformOptions(messageQueueOptions); IList brokerMessagesList = new List(); foreach (GxUserType queueMessage in queueMessages) { @@ -239,15 +299,19 @@ private GxUserType TransformBrokerMessage(BrokerMessage brokerMessage) private BrokerMessageOptions TransformOptions(GxUserType messageQueueOptions) { BrokerMessageOptions options = new BrokerMessageOptions(); - //TO DO Check the valid options, ex - //https://docs.microsoft.com/en-us/dotnet/api/azure.messaging.servicebus.createmessagebatchoptions.maxsizeinbytes?view=azure-dotnet#azure-messaging-servicebus-createmessagebatchoptions-maxsizeinbytes - + options.MaxNumberOfMessages = messageQueueOptions.GetPropertyValue("Maxnumberofmessages"); options.DeleteConsumedMessages = messageQueueOptions.GetPropertyValue("Deleteconsumedmessages"); options.WaitTimeout = messageQueueOptions.GetPropertyValue("Waittimeout"); options.VisibilityTimeout = messageQueueOptions.GetPropertyValue("Visibilitytimeout"); options.TimetoLive = messageQueueOptions.GetPropertyValue("Timetolive"); - return options; + options.DelaySeconds = messageQueueOptions.GetPropertyValue("Delayseconds"); + options.ReceiveMode = messageQueueOptions.GetPropertyValue("Receivemode"); + options.ReceiveRequestAttemptId = messageQueueOptions.GetPropertyValue("Receiverequestattemptid"); + options.ReceiveMessageAttributes = messageQueueOptions.GetPropertyValue("Receivemessageattributes"); + options.PrefetchCount = messageQueueOptions.GetPropertyValue("Prefetchcount"); + options.SubscriptionName = messageQueueOptions.GetPropertyValue("Subscriptionname"); +; return options; } private BrokerMessage TransformGXUserTypeToBrokerMessage(GxUserType queueMessage) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs index 0234167d2..9c5ed2930 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/PropertyConstants.cs @@ -2,16 +2,24 @@ namespace GeneXus.Messaging.Common { public static class PropertyConstants { - // Azure Service Bus // + //Azure Service Bus internal const string AZURE_SB_CLASSNAME = "GeneXus.Messaging.GXAzureServiceBus.AzureServiceBus"; internal const string AZURE_SB_PROVIDER_CLASSNAME = "GeneXus.Messaging.GXAzureServiceBus.AzureServiceBus, GXAzureServiceBus, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"; public const string AZURESERVICEBUS = "AZURESERVICEBUS"; - + public const string RECEIVE_MODE = "RECEIVE_MODE"; + public const string PREFETCH_COUNT = "PREFETCH_COUNT"; + public const string RECEIVER_IDENTIFIER = "RECEIVER_IDENTIFIER"; + public const string RECEIVER_SESSIONID = "RECEIVER_SESSIONID"; + public const string SENDER_IDENTIFIER = "SENDER_IDENTIFIER"; public const string MESSAGEBROKER_AZURESB_QUEUENAME = "MESSAGEBROKER_AZURESB_QUEUENAME"; - public const string MESSAGEBROKER_AZURESB_QUEUECONNECTION = "MESSAGEBROKER_AZURESB_QUEUECONNECTION"; + public const string MESSAGEBROKER_AZURESB_TOPICNAME = "MESSAGEBROKER_AZURESB_TOPICNAME"; + public const string MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME = "MESSAGEBROKER_AZURESB_SUBSCRIPTION"; + public const string MESSAGEBROKER_AZURESB_CONNECTIONSTRING = "MESSAGEBROKER_AZURESB_QUEUECONNECTION"; public const string QUEUE_NAME = "QUEUENAME"; public const string QUEUE_CONNECTION_STRING = "QUEUECONNECTION"; + public const string TOPIC_SUBSCRIPTION = "SUBSCRIPTION"; public const string MESSAGE_BROKER = "MESSAGEBROKER"; + public const string SESSION_ENABLED = "SESSION_ENABLED"; } } diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs index 8ed48053d..2d920710c 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/ServiceSettings.cs @@ -25,6 +25,11 @@ public ServiceSettings(string serviceNameResolver, string name, GXService gXServ this.service = gXService; } + public string GetEncryptedOptPropertyValue(string propertyName, string alternativePropertyName = null) + { + String value = GetEncryptedPropertyValue(propertyName, alternativePropertyName, null); + return value; + } public string GetEncryptedPropertyValue(string propertyName, string alternativePropertyName = null) { String value = GetEncryptedPropertyValue(propertyName, alternativePropertyName, null); From 7df21094093fc344474cd623e547bc6685abf87d Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Sun, 25 Sep 2022 19:15:56 -0300 Subject: [PATCH 06/13] remove debugger lines --- .../GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs index 401009749..e381c4f01 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs @@ -9,7 +9,6 @@ public class ServiceBusMessageBrokerProvider { public MessageQueue Connect(string queueName, string connectionString, out GXBaseCollection errorMessages, out bool success) { - System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); GXProperties properties = new GXProperties(); properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName); @@ -23,7 +22,6 @@ public MessageQueue Connect(string queueName, string connectionString, out GXBas public MessageQueue Connect(string topicName, string subcriptionName, string connectionString, out GXBaseCollection errorMessages, out bool success) { - System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); GXProperties properties = new GXProperties(); properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_TOPICNAME, topicName); @@ -37,7 +35,6 @@ public MessageQueue Connect(string topicName, string subcriptionName, string con } public MessageQueue Connect(string queueName, string connectionString, bool sessionEnabled, GxUserType receiverOptions, string senderIdentifier, out GXBaseCollection errorMessages, out bool success) { - System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions); @@ -60,7 +57,6 @@ public MessageQueue Connect(string queueName, string connectionString, bool sess public MessageQueue Connect(string topicName, string subcriptionName, string connectionString, bool sessionEnabled, GxUserType receiverOptions, string senderIdentifier, out GXBaseCollection errorMessages, out bool success) { - System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); GXProperties properties = new GXProperties(); ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions); From 91f38e2496d6828207f6b61a626e67fea4b37c82 Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Sun, 25 Sep 2022 19:49:50 -0300 Subject: [PATCH 07/13] Fix error in unit tests code --- .../GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs | 5 +++++ .../MessageBroker/AzureMessageBrokerTest.cs | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs index e381c4f01..f7015d2aa 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs @@ -9,6 +9,7 @@ public class ServiceBusMessageBrokerProvider { public MessageQueue Connect(string queueName, string connectionString, out GXBaseCollection errorMessages, out bool success) { + System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); GXProperties properties = new GXProperties(); properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName); @@ -22,6 +23,7 @@ public MessageQueue Connect(string queueName, string connectionString, out GXBas public MessageQueue Connect(string topicName, string subcriptionName, string connectionString, out GXBaseCollection errorMessages, out bool success) { + System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); GXProperties properties = new GXProperties(); properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_TOPICNAME, topicName); @@ -35,6 +37,8 @@ public MessageQueue Connect(string topicName, string subcriptionName, string con } public MessageQueue Connect(string queueName, string connectionString, bool sessionEnabled, GxUserType receiverOptions, string senderIdentifier, out GXBaseCollection errorMessages, out bool success) { + System.Diagnostics.Debugger.Launch(); + MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions); @@ -57,6 +61,7 @@ public MessageQueue Connect(string queueName, string connectionString, bool sess public MessageQueue Connect(string topicName, string subcriptionName, string connectionString, bool sessionEnabled, GxUserType receiverOptions, string senderIdentifier, out GXBaseCollection errorMessages, out bool success) { + System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); GXProperties properties = new GXProperties(); ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions); diff --git a/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs b/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs index d12086cd6..d18cb12be 100644 --- a/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs +++ b/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs @@ -36,7 +36,7 @@ public void TestSendOneMessageMethod() brokerMessage.MessageId = "TestMsgId"; brokerMessage.MessageBody = "This is the message body"; - bool success = messageBroker.SendMessage(brokerMessage); + bool success = messageBroker.SendMessage(brokerMessage,String.Empty); Assert.True(success); @@ -59,7 +59,7 @@ public void TestSendBatchMessagesMethod() BrokerMessageOptions options = new BrokerMessageOptions(); - bool success = messageBroker.SendMessages(messages, options); + bool success = messageBroker.SendMessages(messages, String.Empty); Assert.True(success); } @@ -67,7 +67,7 @@ public void TestSendBatchMessagesMethod() public void TestGetBatchMessagesMethod() { BrokerMessageOptions options = new BrokerMessageOptions(); - IList messages = messageBroker.GetMessages(options, out bool success); + IList messages = messageBroker.GetMessages(String.Empty, out bool success); Assert.True(success); } } From 0392509b2511a146e34513e27a8cd059a47d9e30 Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Wed, 28 Sep 2022 18:21:49 -0300 Subject: [PATCH 08/13] Added new methods and other fixes --- .../GXAzureServiceBus/AzureServiceBus.cs | 328 +++++++++++------- .../ServiceBusMessageBrokerProvider.cs | 9 +- .../GXMessageBroker/MessageBroker.cs | 27 +- .../GXMessageBroker/MessageBrokerProvider.cs | 1 - .../Messaging/GXMessageBroker/MessageQueue.cs | 89 +++-- .../MessageBroker/AzureMessageBrokerTest.cs | 3 - 6 files changed, 265 insertions(+), 192 deletions(-) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs index 0bbd6ffbe..e1259b853 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs @@ -15,10 +15,10 @@ namespace GeneXus.Messaging.GXAzureServiceBus public class AzureServiceBus : MessageBrokerBase, IMessageBroker { private const int MAX_MESSAGES_DEFAULT = 10; - static readonly ILog logger = log4net.LogManager.GetLogger(typeof(AzureServiceBus)); + private const short LOCK_DURATION = 5; public static String Name = "AZURESB"; - private ConcurrentDictionary m_messages = new ConcurrentDictionary(); + private ConcurrentDictionary> m_messages = new ConcurrentDictionary>(); ServiceBusClient _serviceBusClient { get; set; } private string _queueOrTopicName { get; set; } private string _connectionString { get; set; } @@ -29,7 +29,7 @@ public class AzureServiceBus : MessageBrokerBase, IMessageBroker private ServiceBusSessionReceiverOptions _sessionReceiverOptions { get; set; } private bool _sessionEnabled { get; set; } private string _sessionId { get; set; } - + private string receiveMode { get; set; } public AzureServiceBus() : this(null) { } @@ -49,7 +49,7 @@ private void Initialize(GXService providerService) ServiceBusReceiverOptions serviceBusReceiverOptions = new ServiceBusReceiverOptions(); _sessionReceiverOptions = new ServiceBusSessionReceiverOptions(); - string receiveMode = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVE_MODE); + receiveMode = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVE_MODE); string prefetchCount = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.PREFETCH_COUNT); string receiverIdentifier = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVER_IDENTIFIER); ; _sessionId = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVER_SESSIONID); @@ -89,57 +89,55 @@ private void Initialize(GXService providerService) //TO DO Consider connection options here //https://docs.microsoft.com/en-us/javascript/api/@azure/service-bus/servicebusclientoptions?view=azure-node-latest#@azure-service-bus-servicebusclientoptions-websocketoptions - try + _serviceBusClient = new ServiceBusClient(_connectionString); + if (_serviceBusClient != null) { - _serviceBusClient = new ServiceBusClient(_connectionString); - if (_serviceBusClient != null) - { - _sender = _serviceBusClient.CreateSender(_queueOrTopicName, serviceBusSenderOptions); + _sender = _serviceBusClient.CreateSender(_queueOrTopicName, serviceBusSenderOptions); - if (_sessionEnabled && _sender != null) + if (_sessionEnabled && _sender != null) + { + if (!string.IsNullOrEmpty(_sessionId)) { - if (!string.IsNullOrEmpty(_sessionId)) + if (string.IsNullOrEmpty(_subscriptionName)) { - if (string.IsNullOrEmpty(_subscriptionName)) - { - Task task; - task = Task.Run(async () => await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _sessionId, _sessionReceiverOptions).ConfigureAwait(false)); - _sessionReceiver = task.Result; - } - else - { - Task task; - task = Task.Run(async () => await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _subscriptionName, _sessionId, _sessionReceiverOptions).ConfigureAwait(false)); - _sessionReceiver = task.Result; - } + Task task; + task = Task.Run(async () => await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _sessionId, _sessionReceiverOptions).ConfigureAwait(false)); + _sessionReceiver = task.Result; } else { - if (string.IsNullOrEmpty(_subscriptionName)) - { - Task task; - task = Task.Run(async () => await _serviceBusClient.AcceptNextSessionAsync(_queueOrTopicName, _sessionReceiverOptions).ConfigureAwait(false)); - _sessionReceiver = task.Result; - } - else - { - Task task; - task = Task.Run(async () => await _serviceBusClient.AcceptNextSessionAsync(_queueOrTopicName, _subscriptionName, _sessionReceiverOptions).ConfigureAwait(false)); - _sessionReceiver = task.Result; - } + Task task; + task = Task.Run(async () => await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _subscriptionName, _sessionId, _sessionReceiverOptions).ConfigureAwait(false)); + _sessionReceiver = task.Result; } } else + { + //These methods throw an exception when the service bus is empty: + //ServiceBusException: The operation did not complete within the allocated time (ServiceTimeout) + //so I remove them for now + /* if (string.IsNullOrEmpty(_subscriptionName)) - _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, serviceBusReceiverOptions); - - else - _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, _subscriptionName, serviceBusReceiverOptions); + { + Task task; + task = Task.Run(async () => await _serviceBusClient.AcceptNextSessionAsync(_queueOrTopicName, _sessionReceiverOptions).ConfigureAwait(false)); + _sessionReceiver = task.Result; + } + else + { + Task task; + task = Task.Run(async () => await _serviceBusClient.AcceptNextSessionAsync(_queueOrTopicName, _subscriptionName, _sessionReceiverOptions).ConfigureAwait(false)); + _sessionReceiver = task.Result; + }*/ + throw new Exception("ServiceBus: Specify a session to establish a service bus receiver for the session-enabled queue or topic."); + } } - } - catch (Exception ex) - { - GXLogging.Error(logger, ex.Message); + else + if (string.IsNullOrEmpty(_subscriptionName)) + _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, serviceBusReceiverOptions); + + else + _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, _subscriptionName, serviceBusReceiverOptions); } } public override string GetName() @@ -153,32 +151,46 @@ private async Task ServiceClientDisposeAsync() await _serviceBusClient.DisposeAsync().ConfigureAwait(false); } private async Task sendAsync(ServiceBusMessage serviceBusMessage, string options) + { + try + { + await _sender.SendMessageAsync(serviceBusMessage).ConfigureAwait(false); + return true; + } + catch (Exception ex) + { + throw ex; + } + } + + private async Task CancelScheduleAsync(long sequenceNumber) { - SendMessageOptions sendOptions = JSONHelper.Deserialize(options); - if ((sendOptions != null) && (!string.IsNullOrEmpty(sendOptions.ScheduledEnqueueTime))) + try { - try - { - await _sender.ScheduleMessageAsync(serviceBusMessage, DateTimeOffset.Parse(sendOptions.ScheduledEnqueueTime)).ConfigureAwait(false); - return true; - } - catch (Exception ex) - { - throw ex; - } + await _sender.CancelScheduledMessageAsync(sequenceNumber).ConfigureAwait(false); + return true; } - else + catch (Exception ex) + { + throw ex; + } + } + private async Task ScheduleMessageAsync(ServiceBusMessage serviceBusMessage, string options) + { + ScheduleMessageOptions scheduleOptions = JSONHelper.Deserialize(options); + if ((serviceBusMessage != null) && (scheduleOptions != null) && (!string.IsNullOrEmpty(scheduleOptions.ScheduledEnqueueTime))) { try { - await _sender.SendMessageAsync(serviceBusMessage).ConfigureAwait(false); - return true; + return (await _sender.ScheduleMessageAsync(serviceBusMessage, DateTime.Parse(scheduleOptions.ScheduledEnqueueTime)).ConfigureAwait(false)); + } catch (Exception ex) { throw ex; } } + return 0; } private async Task SendMessagesBatchAsync(IList brokerMessages, string options) { @@ -196,32 +208,15 @@ private async Task SendMessagesBatchAsync(IList brokerMessa serviceBusMessage = BrokerMessageToServiceBusMessage(brokerMessage); serviceBusMessages.Add(serviceBusMessage); } - - SendMessageOptions sendOptions = JSONHelper.Deserialize(options); - if ((sendOptions != null) && (!string.IsNullOrEmpty(sendOptions.ScheduledEnqueueTime))) - { - try - { - await _sender.ScheduleMessagesAsync(serviceBusMessages, DateTimeOffset.Parse(sendOptions.ScheduledEnqueueTime)).ConfigureAwait(false); - success = true; - } - catch (Exception ex) - { - GXLogging.Error(logger, ex.Message.ToString()); - } + try + { + await _sender.SendMessagesAsync(serviceBusMessages).ConfigureAwait(false); + success = true; } - else + catch (Exception ex) { - try - { - await _sender.SendMessagesAsync(serviceBusMessages).ConfigureAwait(false); - success = true; - } - catch (Exception ex) - { - GXLogging.Error(logger, ex.Message.ToString()); - } - } + throw ex; + } } return success; } @@ -284,11 +279,9 @@ private async Task> ReceiveMessagesAsyn } catch (Exception ex) { - GXLogging.Error(logger, ex.Message.ToString()); + throw ex; } - return null; } - private async Task ReceiveMessageAsync(string options) { ReceiveMessageOptions receiveOptions = JSONHelper.Deserialize(options); @@ -343,9 +336,8 @@ private async Task ReceiveMessageAsync(string options } catch (Exception ex) { - GXLogging.Error(logger, ex.Message.ToString()); + throw ex; } - return null; } #endregion @@ -361,6 +353,7 @@ public bool SendMessage(BrokerMessage brokerMessage, string options) { task = Task.Run(async () => await sendAsync(serviceBusMessage, options)); success = task.Result; + ClearServiceBusAuxiliaryStorage(); } else { @@ -380,6 +373,7 @@ bool IMessageBroker.SendMessages(IList brokerMessages, string opt { Task task = Task.Run(async () => await SendMessagesBatchAsync(brokerMessages, options)); success = task.Result; + ClearServiceBusAuxiliaryStorage(); } catch (AggregateException ae) { @@ -396,11 +390,20 @@ IList IMessageBroker.GetMessages(string options, out bool success Task> receivedMessages = Task>.Run(async () => await ReceiveMessagesAsync(options)); if (receivedMessages != null && receivedMessages.Result != null) { + ClearServiceBusAuxiliaryStorage(); foreach (ServiceBusReceivedMessage serviceBusReceivedMessage in receivedMessages.Result) { if (serviceBusReceivedMessage != null) - if (AddOrUpdateStoredServiceReceivedMessage(serviceBusReceivedMessage)) - brokerMessages.Add(SBReceivedMessageToBrokerMessage(serviceBusReceivedMessage)); + brokerMessages.Add(SBReceivedMessageToBrokerMessage(serviceBusReceivedMessage)); + + //If receive Mode = Peek Lock, save the messages to be retrieved later + if (!string.IsNullOrEmpty(receiveMode) && (Convert.ToInt16(receiveMode) == 0)) + { + if (!AddOrUpdateStoredServiceReceivedMessage(serviceBusReceivedMessage)) + { + throw new Exception("Invalid operation."); + } + } } success = true; } @@ -421,6 +424,7 @@ public bool ConsumeMessage(BrokerMessage brokerMessage, string options) if ((_sessionReceiver != null) && (_sessionEnabled)) receiver = _sessionReceiver; + ClearServiceBusAuxiliaryStorage(); ServiceBusReceivedMessage serviceBusReceviedMessage = GetStoredServiceBusReceivedMessage(brokerMessage); if (serviceBusReceviedMessage != null) { @@ -438,6 +442,7 @@ public bool ConsumeMessage(BrokerMessage brokerMessage, string options) case ConsumeMessageOptions.ConsumeModeOpts.Abandon: { task = Task.Run(async () => await receiver.AbandonMessageAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + RemoveStoredServiceBusReceivedMessage(brokerMessage); break; } case ConsumeMessageOptions.ConsumeModeOpts.DeadLetter: @@ -449,11 +454,13 @@ public bool ConsumeMessage(BrokerMessage brokerMessage, string options) case ConsumeMessageOptions.ConsumeModeOpts.Defer: { task = Task.Run(async () => await receiver.DeferMessageAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + RemoveStoredServiceBusReceivedMessage(brokerMessage); break; } case ConsumeMessageOptions.ConsumeModeOpts.RenewMessageLock: { task = Task.Run(async () => await receiver.RenewMessageLockAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + RemoveStoredServiceBusReceivedMessage(brokerMessage); break; } } @@ -464,6 +471,10 @@ public bool ConsumeMessage(BrokerMessage brokerMessage, string options) throw ae; } } + else + { + throw new Exception("Invalid operation."); + } } return false; } @@ -474,6 +485,7 @@ public BrokerMessage GetMessage(string options, out bool success) success = false; try { + ClearServiceBusAuxiliaryStorage(); Task receivedMessage = Task.Run(async () => await ReceiveMessageAsync(options)); if (receivedMessage != null && receivedMessage.Result != null) { @@ -494,6 +506,54 @@ public BrokerMessage GetMessage(string options, out bool success) public void Dispose() { Task task = Task.Run(async () => await ServiceClientDisposeAsync().ConfigureAwait(false)); + m_messages.Clear(); + } + public long ScheduleMessage(BrokerMessage brokerMessage, string options) + { + long sequenceNumber = 0; + ServiceBusMessage serviceBusMessage = BrokerMessageToServiceBusMessage(brokerMessage); + try + { + Task task; + if (_sender != null) + { + task = Task.Run(async () => await ScheduleMessageAsync(serviceBusMessage, options)); + sequenceNumber = task.Result; + ClearServiceBusAuxiliaryStorage(); + } + else + { + throw new Exception("There was an error at the Message Broker initialization."); + } + } + catch (AggregateException ae) + { + throw ae; + } + return sequenceNumber; + } + public bool CancelSchedule(long sequenceNumber) + { + bool success = false; + try + { + Task task; + if (_sender != null) + { + task = Task.Run(async () => await CancelScheduleAsync(sequenceNumber)); + success = task.Result; + ClearServiceBusAuxiliaryStorage(); + } + else + { + throw new Exception("There was an error at the Message Broker initialization."); + } + } + catch (AggregateException ae) + { + throw ae; + } + return false; } public bool GetMessageFromException(Exception ex, SdtMessages_Message msg) { @@ -514,14 +574,18 @@ public bool GetMessageFromException(Exception ex, SdtMessages_Message msg) #region Transformation Methods private ServiceBusMessage BrokerMessageToServiceBusMessage(BrokerMessage brokerMessage) { - ServiceBusMessage serviceBusMessage = new ServiceBusMessage(brokerMessage.MessageBody); - serviceBusMessage.MessageId = brokerMessage.MessageId; + if (brokerMessage != null) + { + ServiceBusMessage serviceBusMessage = new ServiceBusMessage(brokerMessage.MessageBody); + serviceBusMessage.MessageId = brokerMessage.MessageId; - GXProperties messageAttributes = brokerMessage.MessageAttributes; - if (messageAttributes != null) - LoadMessageProperties(messageAttributes, ref serviceBusMessage); + GXProperties messageAttributes = brokerMessage.MessageAttributes; + if (messageAttributes != null) + LoadMessageProperties(messageAttributes, ref serviceBusMessage); - return serviceBusMessage; + return serviceBusMessage; + } + return null; } private BrokerMessage SBReceivedMessageToBrokerMessage(ServiceBusReceivedMessage serviceBusReceivedMessage) { @@ -536,11 +600,17 @@ private BrokerMessage SBReceivedMessageToBrokerMessage(ServiceBusReceivedMessage #endregion #region Data - [DataContract] - internal class SendMessageOptions + [DataContract()] + internal class ScheduleMessageOptions { - [DataMember] - internal string ScheduledEnqueueTime { get; set; } + long _cancelSequenceNumber; + string _scheduledEnqueueTime; + + [DataMember()] + internal string ScheduledEnqueueTime { get => _scheduledEnqueueTime; set => _scheduledEnqueueTime = value; } + + [DataMember()] + internal long CancelSequenceNumber { get => _cancelSequenceNumber; set => _cancelSequenceNumber = value; } } [DataContract()] @@ -598,44 +668,50 @@ internal enum ConsumeModeOpts #endregion - #region helper methods + #region Helper methods private ServiceBusReceivedMessage GetStoredServiceBusReceivedMessage(BrokerMessage message) { string messageIdentifier = GetMessageIdentifier(message); - if (m_messages.TryGetValue(messageIdentifier, out ServiceBusReceivedMessage serviceBusReceivedMessage)) - return serviceBusReceivedMessage; + if (m_messages.TryGetValue(messageIdentifier, out Tuple messageStored)) + { + return messageStored.Item2; + } else return null; } private void RemoveStoredServiceBusReceivedMessage(BrokerMessage message) { string messageIdentifier = GetMessageIdentifier(message); - lock (m_messages) - { - if (m_messages.TryGetValue(messageIdentifier, out ServiceBusReceivedMessage serviceBusReceivedMessage)) - { - KeyValuePair keyValuePair = new KeyValuePair(messageIdentifier, serviceBusReceivedMessage); - m_messages.TryRemove(keyValuePair); - } - } + m_messages.TryRemove(messageIdentifier, out _); } private bool AddOrUpdateStoredServiceReceivedMessage(ServiceBusReceivedMessage serviceBusReceivedMessage) { string messageIdentifier = GetMessageIdentifierFromServiceBus(serviceBusReceivedMessage); if (!string.IsNullOrEmpty(messageIdentifier)) - lock (m_messages) - { - if (m_messages.TryGetValue(messageIdentifier, out ServiceBusReceivedMessage originalMessage)) - { - return (m_messages.TryUpdate(messageIdentifier, serviceBusReceivedMessage, originalMessage)); - } - else - return m_messages.TryAdd(messageIdentifier, serviceBusReceivedMessage); - } + { + Tuple messageStored = new Tuple(DateTime.UtcNow, serviceBusReceivedMessage); + m_messages[messageIdentifier] = messageStored; + return true; + } return false; } + private void ClearServiceBusAuxiliaryStorage() + { + //Clear all messages older than 5 minutes + //When a consumer locks a message, the broker temporarily hides it from other consumers (LockDuration). + //However, the lock on the message has a timeout, which is 5 mins maximum + + foreach (KeyValuePair> entry in m_messages) + { + if (entry.Value.Item1.AddMinutes(LOCK_DURATION) < DateTime.UtcNow) + { + m_messages.TryRemove(entry.Key, out _); + } + } + } + private string GetMessageIdentifier(BrokerMessage message) { //The sequence number is a unique 64-bit integer assigned to a message as it is accepted and stored by the broker and functions as its true identifier. @@ -651,17 +727,17 @@ private string GetMessageIdentifier(BrokerMessage message) //Get SessionId of the message string messageSessionId = GetMessageSessionId(message); if (!string.IsNullOrEmpty(messageSessionId)) - messageIdentifier = $"{messageSequenceNumber}{messageSessionId}"; + messageIdentifier = $"{messageSequenceNumber}_{messageSessionId}"; else { //Get PartitionKey of the message string messagePartitionKey = GetMessagePartitionKey(message); if (!string.IsNullOrEmpty(messagePartitionKey)) - messageIdentifier = $"{messageSequenceNumber}{messagePartitionKey}"; + messageIdentifier = $"{messageSequenceNumber}_{messagePartitionKey}"; else - messageIdentifier = $"{messageSequenceNumber}{message.MessageId}"; + messageIdentifier = $"{messageSequenceNumber}_{message.MessageId}"; } - return messageIdentifier.GetHashCode().ToString(); + return messageIdentifier; } private string GetMessageIdentifierFromServiceBus(ServiceBusReceivedMessage message) @@ -671,17 +747,17 @@ private string GetMessageIdentifierFromServiceBus(ServiceBusReceivedMessage mess //Get SessionId of the message string messageSessionId = message.SessionId; if (!string.IsNullOrEmpty(messageSessionId)) - messageIdentifier = $"{messageSequenceNumber}{messageSessionId}"; + messageIdentifier = $"{messageSequenceNumber}_{messageSessionId}"; else { //Get PartitionKey of the message string messagePartitionKey = message.PartitionKey; if (!string.IsNullOrEmpty(messagePartitionKey)) - messageIdentifier = $"{messageSequenceNumber}{messagePartitionKey}"; + messageIdentifier = $"{messageSequenceNumber}_{messagePartitionKey}"; else - messageIdentifier = $"{messageSequenceNumber}{message.MessageId}"; + messageIdentifier = $"{messageSequenceNumber}_{message.MessageId}"; } - return messageIdentifier.GetHashCode().ToString(); + return messageIdentifier; } private string GetMessageSequenceNumber(BrokerMessage message) { diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs index f7015d2aa..036c89652 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/ServiceBusMessageBrokerProvider.cs @@ -9,7 +9,6 @@ public class ServiceBusMessageBrokerProvider { public MessageQueue Connect(string queueName, string connectionString, out GXBaseCollection errorMessages, out bool success) { - System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); GXProperties properties = new GXProperties(); properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, queueName); @@ -23,10 +22,9 @@ public MessageQueue Connect(string queueName, string connectionString, out GXBas public MessageQueue Connect(string topicName, string subcriptionName, string connectionString, out GXBaseCollection errorMessages, out bool success) { - System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); GXProperties properties = new GXProperties(); - properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_TOPICNAME, topicName); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, topicName); properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME, subcriptionName); properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString); @@ -37,10 +35,8 @@ public MessageQueue Connect(string topicName, string subcriptionName, string con } public MessageQueue Connect(string queueName, string connectionString, bool sessionEnabled, GxUserType receiverOptions, string senderIdentifier, out GXBaseCollection errorMessages, out bool success) { - System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); - ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions); GXProperties properties = new GXProperties(); @@ -61,12 +57,11 @@ public MessageQueue Connect(string queueName, string connectionString, bool sess public MessageQueue Connect(string topicName, string subcriptionName, string connectionString, bool sessionEnabled, GxUserType receiverOptions, string senderIdentifier, out GXBaseCollection errorMessages, out bool success) { - System.Diagnostics.Debugger.Launch(); MessageBrokerProvider messageBrokerProvider = new MessageBrokerProvider(); GXProperties properties = new GXProperties(); ReceiverOptions options = TransformGXUserTypeToReceiverOptions(receiverOptions); - properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_TOPICNAME, topicName); + properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME, topicName); properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME, subcriptionName); properties.Add(PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING, connectionString); properties.Add(PropertyConstants.SESSION_ENABLED, sessionEnabled.ToString()); diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs index 30097724c..c30bebbcf 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBroker.cs @@ -11,9 +11,11 @@ public interface IMessageBroker bool SendMessages(IList brokerMessages, string options); IList GetMessages(string options, out bool success); BrokerMessage GetMessage(string options, out bool success); + bool ConsumeMessage(BrokerMessage brokerMessage, string options); + long ScheduleMessage(BrokerMessage brokerMessage, string options); + bool CancelSchedule(long handleId); void Dispose(); bool GetMessageFromException(Exception ex, SdtMessages_Message msg); - bool ConsumeMessage(BrokerMessage brokerMessage, string options); } public class BrokerMessage : GxUserType { @@ -50,27 +52,4 @@ public override void ToJSON(bool includeState) #endregion } - public class BrokerMessageOptions : GxUserType - { - public short MaxNumberOfMessages { get; set; } - public bool DeleteConsumedMessages { get; set; } - public int WaitTimeout { get; set; } - public int VisibilityTimeout { get; set; } - public int TimetoLive { get; set; } - public int DelaySeconds { get; set; } - public string ReceiveRequestAttemptId { get; set; } - public bool ReceiveMessageAttributes { get; set; } - public short ReceiveMode { get; set; } - public short PrefetchCount { get; set; } - public string SubscriptionName { get; set; } - - } - - public static class BrokerMessageResultStatus - { - public const string Unknown = "Unknown"; - public const string Sent = "Sent"; - public const string Deleted = "Deleted"; - public const string Failed = "Failed"; - } } diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs index bfc0d1e25..3bc11056f 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs @@ -73,7 +73,6 @@ private static void Preprocess(String name, GXProperties properties) case Providers.AzureServiceBus: className = PropertyConstants.AZURE_SB_CLASSNAME; SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_QUEUENAME); - SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_TOPICNAME); SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_SUBSCRIPTION_NAME); SetEncryptedProperty(properties, PropertyConstants.MESSAGEBROKER_AZURESB_CONNECTIONSTRING); if (string.IsNullOrEmpty(providerService.ClassName) || !providerService.ClassName.Contains(className)) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs index 580c3a3e1..344b8983c 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs @@ -19,7 +19,6 @@ public class MessageQueue static readonly ILog logger = log4net.LogManager.GetLogger(typeof(MessageQueue)); private const string SDT_MESSAGE_CLASS_NAME = @"SdtMessage"; private const string SDT_MESSAGEPROPERTY_CLASS_NAME = @"SdtMessageProperty"; - //private const string SDT_MESSAGERESULT_CLASS_NAME = @"SdtMessageResult"; private const string NAMESPACE = @"GeneXus.Programs.genexusmessagingmessagebroker"; private const string GENEXUS_COMMON_DLL = @"GeneXus.Programs.Common.dll"; @@ -73,6 +72,48 @@ public void Dispose() } } + public long ScheduleMessage(GxUserType messageQueue, string options, out GXBaseCollection errorMessages) + { + errorMessages = new GXBaseCollection(); + GxUserType result = new GxUserType(); + try + { + BrokerMessage brokerQueueMessage = TransformGXUserTypeToBrokerMessage(messageQueue); + LoadAssemblyIfRequired(); + try + { + ValidQueue(); + return messageBroker.ScheduleMessage(brokerQueueMessage, options); + } + catch (Exception ex) + { + QueueErrorMessagesSetup(ex, out errorMessages); + GXLogging.Error(logger, ex); + } + } + catch (Exception ex) + { + GXLogging.Error(logger, ex); + throw ex; + } + return 0; + } + public bool CancelSchedule(long handleId, out GXBaseCollection errorMessages) + { + errorMessages = new GXBaseCollection(); + try + { + ValidQueue(); + return messageBroker.CancelSchedule(handleId); + } + catch (Exception ex) + { + QueueErrorMessagesSetup(ex, out errorMessages); + GXLogging.Error(logger, ex); + return false; + } + } + public bool ConsumeMessage(GxUserType messageQueue, string options, out GXBaseCollection errorMessages) { bool success = false; @@ -296,39 +337,25 @@ private GxUserType TransformBrokerMessage(BrokerMessage brokerMessage) } return null; } - private BrokerMessageOptions TransformOptions(GxUserType messageQueueOptions) - { - BrokerMessageOptions options = new BrokerMessageOptions(); - - options.MaxNumberOfMessages = messageQueueOptions.GetPropertyValue("Maxnumberofmessages"); - options.DeleteConsumedMessages = messageQueueOptions.GetPropertyValue("Deleteconsumedmessages"); - options.WaitTimeout = messageQueueOptions.GetPropertyValue("Waittimeout"); - options.VisibilityTimeout = messageQueueOptions.GetPropertyValue("Visibilitytimeout"); - options.TimetoLive = messageQueueOptions.GetPropertyValue("Timetolive"); - options.DelaySeconds = messageQueueOptions.GetPropertyValue("Delayseconds"); - options.ReceiveMode = messageQueueOptions.GetPropertyValue("Receivemode"); - options.ReceiveRequestAttemptId = messageQueueOptions.GetPropertyValue("Receiverequestattemptid"); - options.ReceiveMessageAttributes = messageQueueOptions.GetPropertyValue("Receivemessageattributes"); - options.PrefetchCount = messageQueueOptions.GetPropertyValue("Prefetchcount"); - options.SubscriptionName = messageQueueOptions.GetPropertyValue("Subscriptionname"); -; return options; - } - private BrokerMessage TransformGXUserTypeToBrokerMessage(GxUserType queueMessage) { - BrokerMessage brokerQueueMessage = new BrokerMessage(); - brokerQueueMessage.MessageId = queueMessage.GetPropertyValue("Messageid"); - brokerQueueMessage.MessageBody = queueMessage.GetPropertyValue("Messagebody"); - brokerQueueMessage.MessageHandleId = queueMessage.GetPropertyValue("Messagehandleid"); - IList messageAttributes = queueMessage.GetPropertyValue("Messageattributes_GXBaseCollection"); - brokerQueueMessage.MessageAttributes = new GXProperties(); - foreach (GxUserType messageAttribute in messageAttributes) - { - string messagePropKey = messageAttribute.GetPropertyValue("Propertykey"); - string messagePropValue = messageAttribute.GetPropertyValue("Propertyvalue"); - brokerQueueMessage.MessageAttributes.Add(messagePropKey, messagePropValue); + if (queueMessage != null) + { + BrokerMessage brokerQueueMessage = new BrokerMessage(); + brokerQueueMessage.MessageId = queueMessage.GetPropertyValue("Messageid"); + brokerQueueMessage.MessageBody = queueMessage.GetPropertyValue("Messagebody"); + brokerQueueMessage.MessageHandleId = queueMessage.GetPropertyValue("Messagehandleid"); + IList messageAttributes = queueMessage.GetPropertyValue("Messageattributes_GXBaseCollection"); + brokerQueueMessage.MessageAttributes = new GXProperties(); + foreach (GxUserType messageAttribute in messageAttributes) + { + string messagePropKey = messageAttribute.GetPropertyValue("Propertykey"); + string messagePropValue = messageAttribute.GetPropertyValue("Propertyvalue"); + brokerQueueMessage.MessageAttributes.Add(messagePropKey, messagePropValue); + } + return brokerQueueMessage; } - return brokerQueueMessage; + return null; } #endregion diff --git a/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs b/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs index d18cb12be..620ca26f7 100644 --- a/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs +++ b/dotnet/test/DotNetCoreUnitTest/MessageBroker/AzureMessageBrokerTest.cs @@ -57,8 +57,6 @@ public void TestSendBatchMessagesMethod() messages.Add(brokerMessage1); messages.Add(brokerMessage2); - BrokerMessageOptions options = new BrokerMessageOptions(); - bool success = messageBroker.SendMessages(messages, String.Empty); Assert.True(success); @@ -66,7 +64,6 @@ public void TestSendBatchMessagesMethod() [SkippableFact] public void TestGetBatchMessagesMethod() { - BrokerMessageOptions options = new BrokerMessageOptions(); IList messages = messageBroker.GetMessages(String.Empty, out bool success); Assert.True(success); } From a2d1cacda4d40506a215cb93fa5891ffc4f91c97 Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Wed, 28 Sep 2022 18:28:27 -0300 Subject: [PATCH 09/13] Fix module dll reference --- .../Providers/Messaging/GXMessageBroker/MessageQueue.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs index 344b8983c..d1c3d6287 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs @@ -20,7 +20,7 @@ public class MessageQueue private const string SDT_MESSAGE_CLASS_NAME = @"SdtMessage"; private const string SDT_MESSAGEPROPERTY_CLASS_NAME = @"SdtMessageProperty"; private const string NAMESPACE = @"GeneXus.Programs.genexusmessagingmessagebroker"; - private const string GENEXUS_COMMON_DLL = @"GeneXus.Programs.Common.dll"; + private const string MODULE_DLL = @"GeneXusMessagingMessageBroker"; public MessageQueue() { @@ -52,9 +52,7 @@ private static void LoadAssemblyIfRequired() { if (assembly == null) { - assembly = LoadAssembly(Path.Combine(GxContext.StaticPhysicalPath(), GENEXUS_COMMON_DLL)); - if (assembly == null) - assembly = LoadAssembly(Path.Combine(GxContext.StaticPhysicalPath(), "bin", GENEXUS_COMMON_DLL)); + assembly = AssemblyLoader.LoadAssembly(new AssemblyName(MODULE_DLL)); } } From dde2671279c22135c49552ddbf3204085d3078aa Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Sun, 13 Nov 2022 14:34:52 -0300 Subject: [PATCH 10/13] Fixes for session enabled queues and locks --- .../GXAzureServiceBus/AzureServiceBus.cs | 514 +++++++++++------- .../GXAzureServiceBus.csproj | 2 +- .../Messaging/GXMessageBroker/MessageQueue.cs | 82 ++- 3 files changed, 366 insertions(+), 232 deletions(-) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs index e1259b853..8e9a50493 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs @@ -8,7 +8,6 @@ using GeneXus.Messaging.Common; using GeneXus.Services; using GeneXus.Utils; -using log4net; namespace GeneXus.Messaging.GXAzureServiceBus { @@ -18,7 +17,7 @@ public class AzureServiceBus : MessageBrokerBase, IMessageBroker private const short LOCK_DURATION = 5; public static String Name = "AZURESB"; - private ConcurrentDictionary> m_messages = new ConcurrentDictionary>(); + private ConcurrentDictionary> m_messages = new ConcurrentDictionary>(); ServiceBusClient _serviceBusClient { get; set; } private string _queueOrTopicName { get; set; } private string _connectionString { get; set; } @@ -26,10 +25,9 @@ public class AzureServiceBus : MessageBrokerBase, IMessageBroker private ServiceBusSender _sender { get; set; } private ServiceBusReceiver _receiver { get; set; } private ServiceBusSessionReceiver _sessionReceiver { get; set; } - private ServiceBusSessionReceiverOptions _sessionReceiverOptions { get; set; } + private ServiceBusReceiverOptions _serviceBusReceiverOptions { get; set; } private bool _sessionEnabled { get; set; } - private string _sessionId { get; set; } - private string receiveMode { get; set; } + ServiceBusReceiveMode _sessionEnabledQueueReceiveMode { get; set; } public AzureServiceBus() : this(null) { } @@ -45,43 +43,8 @@ private void Initialize(GXService providerService) _subscriptionName = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.TOPIC_SUBSCRIPTION); _sessionEnabled = Convert.ToBoolean(serviceSettings.GetEncryptedPropertyValue(PropertyConstants.SESSION_ENABLED)); - - ServiceBusReceiverOptions serviceBusReceiverOptions = new ServiceBusReceiverOptions(); - _sessionReceiverOptions = new ServiceBusSessionReceiverOptions(); - - receiveMode = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVE_MODE); - string prefetchCount = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.PREFETCH_COUNT); - string receiverIdentifier = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVER_IDENTIFIER); ; - _sessionId = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVER_SESSIONID); - - if (!string.IsNullOrEmpty(receiveMode)) - { - if (_sessionEnabled) - _sessionReceiverOptions.ReceiveMode = (ServiceBusReceiveMode)Convert.ToInt16(receiveMode); - else - serviceBusReceiverOptions.ReceiveMode = (ServiceBusReceiveMode)Convert.ToInt16(receiveMode); - } - if (!string.IsNullOrEmpty(prefetchCount)) - { - int prefetchcnt = Convert.ToInt32(prefetchCount); - if (prefetchcnt != 0) - { - if (_sessionEnabled) - _sessionReceiverOptions.PrefetchCount = prefetchcnt; - else - serviceBusReceiverOptions.PrefetchCount = prefetchcnt; - } - } - if (!string.IsNullOrEmpty(receiverIdentifier)) - { - if (_sessionEnabled) - _sessionReceiverOptions.Identifier = receiverIdentifier; - else - serviceBusReceiverOptions.Identifier = receiverIdentifier; - } - string senderIdentifier = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.SENDER_IDENTIFIER); - + ServiceBusSenderOptions serviceBusSenderOptions = new ServiceBusSenderOptions(); if (!string.IsNullOrEmpty(senderIdentifier)) serviceBusSenderOptions.Identifier = senderIdentifier; @@ -93,51 +56,34 @@ private void Initialize(GXService providerService) if (_serviceBusClient != null) { _sender = _serviceBusClient.CreateSender(_queueOrTopicName, serviceBusSenderOptions); - - if (_sessionEnabled && _sender != null) + if (!_sessionEnabled && _sender != null) { - if (!string.IsNullOrEmpty(_sessionId)) + _serviceBusReceiverOptions = new ServiceBusReceiverOptions(); + + string receiveMode = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVE_MODE); + string prefetchCount = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.PREFETCH_COUNT); + string receiverIdentifier = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.RECEIVER_IDENTIFIER); + + if (!string.IsNullOrEmpty(receiveMode)) + _serviceBusReceiverOptions.ReceiveMode = (ServiceBusReceiveMode)Convert.ToInt16(receiveMode); + + if (!string.IsNullOrEmpty(prefetchCount)) { - if (string.IsNullOrEmpty(_subscriptionName)) - { - Task task; - task = Task.Run(async () => await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _sessionId, _sessionReceiverOptions).ConfigureAwait(false)); - _sessionReceiver = task.Result; - } - else - { - Task task; - task = Task.Run(async () => await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _subscriptionName, _sessionId, _sessionReceiverOptions).ConfigureAwait(false)); - _sessionReceiver = task.Result; - } + int prefetchcnt = Convert.ToInt32(prefetchCount); + if (prefetchcnt != 0) + _serviceBusReceiverOptions.PrefetchCount = prefetchcnt; + } + if (!string.IsNullOrEmpty(receiverIdentifier)) + _serviceBusReceiverOptions.Identifier = receiverIdentifier; else - { - //These methods throw an exception when the service bus is empty: - //ServiceBusException: The operation did not complete within the allocated time (ServiceTimeout) - //so I remove them for now - /* - if (string.IsNullOrEmpty(_subscriptionName)) - { - Task task; - task = Task.Run(async () => await _serviceBusClient.AcceptNextSessionAsync(_queueOrTopicName, _sessionReceiverOptions).ConfigureAwait(false)); - _sessionReceiver = task.Result; - } - else - { - Task task; - task = Task.Run(async () => await _serviceBusClient.AcceptNextSessionAsync(_queueOrTopicName, _subscriptionName, _sessionReceiverOptions).ConfigureAwait(false)); - _sessionReceiver = task.Result; - }*/ - throw new Exception("ServiceBus: Specify a session to establish a service bus receiver for the session-enabled queue or topic."); - } - } - else - if (string.IsNullOrEmpty(_subscriptionName)) - _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, serviceBusReceiverOptions); + _serviceBusReceiverOptions.Identifier = String.Empty; - else - _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, _subscriptionName, serviceBusReceiverOptions); + if (string.IsNullOrEmpty(_subscriptionName)) + _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, _serviceBusReceiverOptions); + else + _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, _subscriptionName, _serviceBusReceiverOptions); + } } } public override string GetName() @@ -146,14 +92,43 @@ public override string GetName() } #region Async methods + + private async Task CreateReceiverAsync() + { + //Release resources of previous receiver + if (_receiver != null) + await _receiver.CloseAsync().ConfigureAwait(false); + + if (string.IsNullOrEmpty(_subscriptionName)) + _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, _serviceBusReceiverOptions); + else + _receiver = _serviceBusClient.CreateReceiver(_queueOrTopicName, _subscriptionName, _serviceBusReceiverOptions); + } + private async Task AcceptSessionAsync(string sessionId, ServiceBusSessionReceiverOptions sessionReceiverOptions) + { + if (_sessionEnabled && (!string.IsNullOrEmpty(sessionId))) + { + //Create new session receiver + ServiceBusSessionReceiver sessionReceiver; + if (string.IsNullOrEmpty(_subscriptionName)) + sessionReceiver = await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, sessionId, sessionReceiverOptions).ConfigureAwait(false); + else + sessionReceiver = await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _subscriptionName, sessionId, sessionReceiverOptions).ConfigureAwait(false); + return sessionReceiver; + } + return null; + } private async Task ServiceClientDisposeAsync() { await _serviceBusClient.DisposeAsync().ConfigureAwait(false); + if (_receiver != null) + await _receiver.DisposeAsync().ConfigureAwait(false); + await _sender.DisposeAsync().ConfigureAwait(false); } private async Task sendAsync(ServiceBusMessage serviceBusMessage, string options) - { + { try - { + { await _sender.SendMessageAsync(serviceBusMessage).ConfigureAwait(false); return true; } @@ -162,7 +137,6 @@ private async Task sendAsync(ServiceBusMessage serviceBusMessage, string o throw ex; } } - private async Task CancelScheduleAsync(long sequenceNumber) { try @@ -183,7 +157,6 @@ private async Task ScheduleMessageAsync(ServiceBusMessage serviceBusMessag try { return (await _sender.ScheduleMessageAsync(serviceBusMessage, DateTime.Parse(scheduleOptions.ScheduledEnqueueTime)).ConfigureAwait(false)); - } catch (Exception ex) { @@ -209,72 +182,150 @@ private async Task SendMessagesBatchAsync(IList brokerMessa serviceBusMessages.Add(serviceBusMessage); } try - { + { await _sender.SendMessagesAsync(serviceBusMessages).ConfigureAwait(false); success = true; } catch (Exception ex) { throw ex; - } + } } return success; } - private async Task> ReceiveMessagesAsync(string options) + private async Task InitializeReceiversForReceiveMthAsync(BrokerReceiverOpts brokerReceiverOptions) { - ReceiveMessageOptions receiveOptions = JSONHelper.Deserialize(options); - IReadOnlyList receivedMessages; - try + if (_sessionEnabled && (brokerReceiverOptions == null)) { - ServiceBusReceiverOptions serviceBusReceiverOptions = new ServiceBusReceiverOptions(); + throw new Exception("SessionId cannot be null for session-enabled queue or topic."); + } + else if (_sessionEnabled && (brokerReceiverOptions != null)) + { + ServiceBusSessionReceiverOptions serviceBusSessionReceiverOptions = BrokerRecOptsToServiceBusSessionRecOpts(brokerReceiverOptions); - if ((receiveOptions != null) && (!string.IsNullOrEmpty(receiveOptions.SessionId)) && _sessionEnabled && (receiveOptions.SessionId != _sessionId)) + if ((serviceBusSessionReceiverOptions != null) && (!string.IsNullOrEmpty(brokerReceiverOptions.SessionId))) { - //Create new session receiver - - if (string.IsNullOrEmpty(_subscriptionName)) + _sessionEnabledQueueReceiveMode = serviceBusSessionReceiverOptions.ReceiveMode; + //Store receiver in case that the message has to be settled + if (_sessionEnabledQueueReceiveMode == ServiceBusReceiveMode.PeekLock) { - _sessionReceiver = await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, receiveOptions.SessionId, _sessionReceiverOptions).ConfigureAwait(false); - _sessionId = receiveOptions.SessionId; + if (_sessionReceiver != null) + await _sessionReceiver.CloseAsync().ConfigureAwait(false); + _sessionReceiver = await AcceptSessionAsync(brokerReceiverOptions.SessionId, serviceBusSessionReceiverOptions).ConfigureAwait(false); } else - { - _sessionReceiver = await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _subscriptionName, receiveOptions.SessionId, _sessionReceiverOptions).ConfigureAwait(false); - _sessionId = receiveOptions.SessionId; - } + _sessionReceiver = await AcceptSessionAsync(brokerReceiverOptions.SessionId, serviceBusSessionReceiverOptions).ConfigureAwait(false); } + else + { + throw new Exception("SessionId cannot be null for session-enabled queue or topic."); + } + } + else if (!_sessionEnabled && (brokerReceiverOptions != null)) + { + //Check if a new receiver must be defined using new settings + if ((_serviceBusReceiverOptions.ReceiveMode != brokerReceiverOptions.ReceiveMode) || (_serviceBusReceiverOptions.Identifier != brokerReceiverOptions.Identifier) || (_serviceBusReceiverOptions.PrefetchCount != brokerReceiverOptions.PrefetchCount)) + { + _serviceBusReceiverOptions.ReceiveMode = brokerReceiverOptions.ReceiveMode; + _serviceBusReceiverOptions.Identifier = brokerReceiverOptions.Identifier; + _serviceBusReceiverOptions.PrefetchCount = brokerReceiverOptions.PrefetchCount; - int maxMessagesReceive = MAX_MESSAGES_DEFAULT; - if ((receiveOptions != null) && (receiveOptions.MaxMessages != 0)) - maxMessagesReceive = receiveOptions.MaxMessages; - - TimeSpan maxWait = TimeSpan.Zero; - if ((receiveOptions != null) && receiveOptions.MaxWaitTime != 0) - maxWait = TimeSpan.FromSeconds(receiveOptions.MaxWaitTime); + await CreateReceiverAsync().ConfigureAwait(false); + } + } + } + private async Task> ReceiveMessagesNotSessionAsync(ReceiveMessageOptions receiveOptions) + { + IReadOnlyList receivedMessages; + int maxMessagesReceive = MAX_MESSAGES_DEFAULT; + if ((receiveOptions != null) && (receiveOptions.MaxMessages != 0)) + maxMessagesReceive = receiveOptions.MaxMessages; - ServiceBusReceiver receiver = _receiver; - if ((_sessionReceiver != null) && (_sessionEnabled)) - receiver = _sessionReceiver; + TimeSpan maxWait = TimeSpan.Zero; + if ((receiveOptions != null) && receiveOptions.MaxWaitTime != 0) + maxWait = TimeSpan.FromSeconds(receiveOptions.MaxWaitTime); + if (_receiver != null) + { if ((receiveOptions != null) && (receiveOptions.ReceiveDeferredSequenceNumbers != null) && (receiveOptions.ReceiveDeferredSequenceNumbers.Count > 0)) { - receivedMessages = await receiver.ReceiveDeferredMessagesAsync(receiveOptions.ReceiveDeferredSequenceNumbers).ConfigureAwait(false); + receivedMessages = await _receiver.ReceiveDeferredMessagesAsync(receiveOptions.ReceiveDeferredSequenceNumbers).ConfigureAwait(false); } else { - - if (maxWait == TimeSpan.Zero) - if ((receiveOptions != null) && (receiveOptions.PeekReceive != null) && (receiveOptions.PeekReceive.Peek)) - if (receiveOptions.PeekReceive.PeekFromSequenceNumber != 0) - receivedMessages = await receiver.PeekMessagesAsync(maxMessages: maxMessagesReceive, receiveOptions.PeekReceive.PeekFromSequenceNumber).ConfigureAwait(false); + if (maxWait == TimeSpan.Zero) + if ((receiveOptions != null) && (receiveOptions.PeekReceive != null) && (receiveOptions.PeekReceive.Peek)) + if (receiveOptions.PeekReceive.PeekFromSequenceNumber != 0) + receivedMessages = await _receiver.PeekMessagesAsync(maxMessages: maxMessagesReceive, receiveOptions.PeekReceive.PeekFromSequenceNumber).ConfigureAwait(false); + else + receivedMessages = await _receiver.PeekMessagesAsync(maxMessages: maxMessagesReceive).ConfigureAwait(false); else - receivedMessages = await receiver.PeekMessagesAsync(maxMessages: maxMessagesReceive).ConfigureAwait(false); + receivedMessages = await _receiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive).ConfigureAwait(false); else - receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive).ConfigureAwait(false); + receivedMessages = await _receiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive, maxWaitTime: maxWait).ConfigureAwait(false); + } + } + else + { + throw new Exception("Invalid Operation. No valid receiver defined."); + } + return receivedMessages; + } + private async Task> ReceiveMessagesSessionAsync(ReceiveMessageOptions receiveOptions) + { + IReadOnlyList receivedMessages; + int maxMessagesReceive = MAX_MESSAGES_DEFAULT; + if ((receiveOptions != null) && (receiveOptions.MaxMessages != 0)) + maxMessagesReceive = receiveOptions.MaxMessages; + + TimeSpan maxWait = TimeSpan.Zero; + if ((receiveOptions != null) && receiveOptions.MaxWaitTime != 0) + maxWait = TimeSpan.FromSeconds(receiveOptions.MaxWaitTime); + + if (_sessionReceiver != null) + { + if ((receiveOptions != null) && (receiveOptions.ReceiveDeferredSequenceNumbers != null) && (receiveOptions.ReceiveDeferredSequenceNumbers.Count > 0)) + { + receivedMessages = await _sessionReceiver.ReceiveDeferredMessagesAsync(receiveOptions.ReceiveDeferredSequenceNumbers).ConfigureAwait(false); + } else - receivedMessages = await receiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive, maxWaitTime: maxWait).ConfigureAwait(false); + { + if (maxWait == TimeSpan.Zero) + if ((receiveOptions != null) && (receiveOptions.PeekReceive != null) && (receiveOptions.PeekReceive.Peek)) + if (receiveOptions.PeekReceive.PeekFromSequenceNumber != 0) + receivedMessages = await _sessionReceiver.PeekMessagesAsync(maxMessages: maxMessagesReceive, receiveOptions.PeekReceive.PeekFromSequenceNumber).ConfigureAwait(false); + else + receivedMessages = await _sessionReceiver.PeekMessagesAsync(maxMessages: maxMessagesReceive).ConfigureAwait(false); + else + receivedMessages = await _sessionReceiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive).ConfigureAwait(false); + else + receivedMessages = await _sessionReceiver.ReceiveMessagesAsync(maxMessages: maxMessagesReceive, maxWaitTime: maxWait).ConfigureAwait(false); + + //Release session lock + if (_sessionEnabledQueueReceiveMode != ServiceBusReceiveMode.PeekLock) + await _sessionReceiver.CloseAsync().ConfigureAwait(false); } + } + else + { + throw new Exception("Invalid Operation. No valid Session receiver defined."); + } + return receivedMessages; + } + private async Task> ReceiveMessagesAsync(string options) + { + ReceiveMessageOptions receiveOptions = JSONHelper.Deserialize(options); + + IReadOnlyList receivedMessages; + try + { + await InitializeReceiversForReceiveMthAsync(receiveOptions.BrokerReceiverOptions).ConfigureAwait(false); + if (_sessionEnabled) + receivedMessages = await ReceiveMessagesSessionAsync(receiveOptions).ConfigureAwait(false); + else + receivedMessages = await ReceiveMessagesNotSessionAsync(receiveOptions).ConfigureAwait(false); + return receivedMessages; } catch (Exception ex) @@ -282,58 +333,91 @@ private async Task> ReceiveMessagesAsyn throw ex; } } - private async Task ReceiveMessageAsync(string options) + + private async Task ReceiveMessageSessionAsync(ReceiveMessageOptions receiveOptions) { - ReceiveMessageOptions receiveOptions = JSONHelper.Deserialize(options); + TimeSpan maxWait = TimeSpan.Zero; ServiceBusReceivedMessage receivedMessage; - - try + if (_sessionReceiver != null) { - ServiceBusReceiverOptions serviceBusReceiverOptions = new ServiceBusReceiverOptions(); + if ((receiveOptions != null) && receiveOptions.MaxWaitTime != 0) + maxWait = TimeSpan.FromSeconds(receiveOptions.MaxWaitTime); - if ((receiveOptions != null) && (!string.IsNullOrEmpty(receiveOptions.SessionId)) && _sessionEnabled && (receiveOptions.SessionId != _sessionId)) + if ((receiveOptions != null) && (receiveOptions.ReceiveDeferredSequenceNumbers != null) && (receiveOptions.ReceiveDeferredSequenceNumbers.Count > 0)) + receivedMessage = await _sessionReceiver.ReceiveDeferredMessageAsync(receiveOptions.ReceiveDeferredSequenceNumbers[0]).ConfigureAwait(false); + + else { - //Create new session receiver - - if (string.IsNullOrEmpty(_subscriptionName)) - { - _sessionReceiver = await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, receiveOptions.SessionId, _sessionReceiverOptions).ConfigureAwait(false); - _sessionId = receiveOptions.SessionId; - } + if (maxWait != TimeSpan.Zero) + receivedMessage = await _sessionReceiver.ReceiveMessageAsync(maxWaitTime: maxWait).ConfigureAwait(false); else - { - _sessionReceiver = await _serviceBusClient.AcceptSessionAsync(_queueOrTopicName, _subscriptionName, receiveOptions.SessionId, _sessionReceiverOptions).ConfigureAwait(false); - _sessionId = receiveOptions.SessionId; - } + if ((receiveOptions != null) && (receiveOptions.PeekReceive != null) && (receiveOptions.PeekReceive.Peek)) + if (receiveOptions.PeekReceive.PeekFromSequenceNumber != 0) + receivedMessage = await _sessionReceiver.PeekMessageAsync(receiveOptions.PeekReceive.PeekFromSequenceNumber).ConfigureAwait(false); + else + receivedMessage = await _sessionReceiver.PeekMessageAsync().ConfigureAwait(false); + else + receivedMessage = await _sessionReceiver.ReceiveMessageAsync().ConfigureAwait(false); + + //Release session lock + if (_sessionEnabledQueueReceiveMode != ServiceBusReceiveMode.PeekLock) + await _sessionReceiver.CloseAsync().ConfigureAwait(false); } + return receivedMessage; + } + else + { + throw new Exception("Invalid Operation. No valid Session receiver defined."); + } + } - TimeSpan maxWait = TimeSpan.Zero; + private async Task ReceiveMessageNotSessionAsync(ReceiveMessageOptions receiveOptions) + { + TimeSpan maxWait = TimeSpan.Zero; + ServiceBusReceivedMessage receivedMessage; + if (_receiver != null) + { if ((receiveOptions != null) && receiveOptions.MaxWaitTime != 0) maxWait = TimeSpan.FromSeconds(receiveOptions.MaxWaitTime); - ServiceBusReceiver receiver = _receiver; - if ((_sessionReceiver != null) && (_sessionEnabled)) - receiver = _sessionReceiver; - if ((receiveOptions != null) && (receiveOptions.ReceiveDeferredSequenceNumbers != null) && (receiveOptions.ReceiveDeferredSequenceNumbers.Count > 0)) { - receivedMessage = await receiver.ReceiveDeferredMessageAsync(receiveOptions.ReceiveDeferredSequenceNumbers[0]).ConfigureAwait(false); + receivedMessage = await _receiver.ReceiveDeferredMessageAsync(receiveOptions.ReceiveDeferredSequenceNumbers[0]).ConfigureAwait(false); } else - { + { if (maxWait != TimeSpan.Zero) - receivedMessage = await receiver.ReceiveMessageAsync(maxWaitTime: maxWait).ConfigureAwait(false); + receivedMessage = await _receiver.ReceiveMessageAsync(maxWaitTime: maxWait).ConfigureAwait(false); else if ((receiveOptions != null) && (receiveOptions.PeekReceive != null) && (receiveOptions.PeekReceive.Peek)) - if (receiveOptions.PeekReceive.PeekFromSequenceNumber != 0) - receivedMessage = await receiver.PeekMessageAsync(receiveOptions.PeekReceive.PeekFromSequenceNumber).ConfigureAwait(false); - else - receivedMessage = await receiver.PeekMessageAsync().ConfigureAwait(false); + if (receiveOptions.PeekReceive.PeekFromSequenceNumber != 0) + receivedMessage = await _receiver.PeekMessageAsync(receiveOptions.PeekReceive.PeekFromSequenceNumber).ConfigureAwait(false); else - receivedMessage = await receiver.ReceiveMessageAsync().ConfigureAwait(false); + receivedMessage = await _receiver.PeekMessageAsync().ConfigureAwait(false); + else + receivedMessage = await _receiver.ReceiveMessageAsync().ConfigureAwait(false); + } return receivedMessage; } + else + { + throw new Exception("Invalid Operation. No valid receiver defined."); + } + } + private async Task ReceiveMessageAsync(string options) + { + ReceiveMessageOptions receiveOptions = JSONHelper.Deserialize(options); + try + { + + await InitializeReceiversForReceiveMthAsync(receiveOptions.BrokerReceiverOptions).ConfigureAwait(false); + + if (_sessionEnabled) + return await ReceiveMessageSessionAsync(receiveOptions).ConfigureAwait(false); + else + return await ReceiveMessageNotSessionAsync(receiveOptions).ConfigureAwait(false); + } catch (Exception ex) { throw ex; @@ -351,7 +435,7 @@ public bool SendMessage(BrokerMessage brokerMessage, string options) Task task; if (_sender != null) { - task = Task.Run(async () => await sendAsync(serviceBusMessage, options)); + task = Task.Run(async () => await sendAsync(serviceBusMessage, options).ConfigureAwait(false)); success = task.Result; ClearServiceBusAuxiliaryStorage(); } @@ -371,7 +455,7 @@ bool IMessageBroker.SendMessages(IList brokerMessages, string opt bool success = false; try { - Task task = Task.Run(async () => await SendMessagesBatchAsync(brokerMessages, options)); + Task task = Task.Run(async () => await SendMessagesBatchAsync(brokerMessages, options).ConfigureAwait(false)); success = task.Result; ClearServiceBusAuxiliaryStorage(); } @@ -387,7 +471,7 @@ IList IMessageBroker.GetMessages(string options, out bool success success = false; try { - Task> receivedMessages = Task>.Run(async () => await ReceiveMessagesAsync(options)); + Task> receivedMessages = Task>.Run(async () => await ReceiveMessagesAsync(options).ConfigureAwait(false)); if (receivedMessages != null && receivedMessages.Result != null) { ClearServiceBusAuxiliaryStorage(); @@ -397,11 +481,11 @@ IList IMessageBroker.GetMessages(string options, out bool success brokerMessages.Add(SBReceivedMessageToBrokerMessage(serviceBusReceivedMessage)); //If receive Mode = Peek Lock, save the messages to be retrieved later - if (!string.IsNullOrEmpty(receiveMode) && (Convert.ToInt16(receiveMode) == 0)) + if (GetReceiveMode() != null && (GetReceiveMode() == ServiceBusReceiveMode.PeekLock)) { if (!AddOrUpdateStoredServiceReceivedMessage(serviceBusReceivedMessage)) { - throw new Exception("Invalid operation."); + throw new Exception("Invalid operation. Try retrieving the message again."); } } } @@ -415,18 +499,28 @@ IList IMessageBroker.GetMessages(string options, out bool success return brokerMessages; } + /// + /// Settling a message + /// public bool ConsumeMessage(BrokerMessage brokerMessage, string options) { ConsumeMessageOptions consumeOptions = JSONHelper.Deserialize(options); if (consumeOptions != null) - { - ServiceBusReceiver receiver = _receiver; - if ((_sessionReceiver != null) && (_sessionEnabled)) + { + ServiceBusReceiver receiver; + if (_sessionEnabled && _sessionReceiver != null) + { receiver = _sessionReceiver; - + } + else + if (!_sessionEnabled) + receiver = _receiver; + else + throw new Exception("Invalid operation. Try retrieving the message again."); + ClearServiceBusAuxiliaryStorage(); - ServiceBusReceivedMessage serviceBusReceviedMessage = GetStoredServiceBusReceivedMessage(brokerMessage); - if (serviceBusReceviedMessage != null) + ServiceBusReceivedMessage serviceBusReceivedMessage = GetStoredServiceBusReceivedMessage(brokerMessage); + if (serviceBusReceivedMessage != null) { try { @@ -435,31 +529,31 @@ public bool ConsumeMessage(BrokerMessage brokerMessage, string options) { case ConsumeMessageOptions.ConsumeModeOpts.Complete: { - task = Task.Run(async () => await receiver.CompleteMessageAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + task = Task.Run(async () => await receiver.CompleteMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false)); RemoveStoredServiceBusReceivedMessage(brokerMessage); break; } case ConsumeMessageOptions.ConsumeModeOpts.Abandon: { - task = Task.Run(async () => await receiver.AbandonMessageAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + task = Task.Run(async () => await receiver.AbandonMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false)); RemoveStoredServiceBusReceivedMessage(brokerMessage); break; } case ConsumeMessageOptions.ConsumeModeOpts.DeadLetter: { - task = Task.Run(async () => await receiver.DeadLetterMessageAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + task = Task.Run(async () => await receiver.DeadLetterMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false)); RemoveStoredServiceBusReceivedMessage(brokerMessage); break; } case ConsumeMessageOptions.ConsumeModeOpts.Defer: { - task = Task.Run(async () => await receiver.DeferMessageAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + task = Task.Run(async () => await receiver.DeferMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false)); RemoveStoredServiceBusReceivedMessage(brokerMessage); break; } case ConsumeMessageOptions.ConsumeModeOpts.RenewMessageLock: { - task = Task.Run(async () => await receiver.RenewMessageLockAsync(serviceBusReceviedMessage).ConfigureAwait(false)); + task = Task.Run(async () => await receiver.RenewMessageLockAsync(serviceBusReceivedMessage).ConfigureAwait(false)); RemoveStoredServiceBusReceivedMessage(brokerMessage); break; } @@ -473,7 +567,7 @@ public bool ConsumeMessage(BrokerMessage brokerMessage, string options) } else { - throw new Exception("Invalid operation."); + throw new Exception("Invalid operation. Try retrieving the message again."); } } return false; @@ -486,15 +580,19 @@ public BrokerMessage GetMessage(string options, out bool success) try { ClearServiceBusAuxiliaryStorage(); - Task receivedMessage = Task.Run(async () => await ReceiveMessageAsync(options)); + Task receivedMessage = Task.Run(async () => await ReceiveMessageAsync(options).ConfigureAwait(false)); if (receivedMessage != null && receivedMessage.Result != null) { ServiceBusReceivedMessage serviceBusReceivedMessage = receivedMessage.Result; - if (AddOrUpdateStoredServiceReceivedMessage(serviceBusReceivedMessage)) - { - success = true; - return (SBReceivedMessageToBrokerMessage(serviceBusReceivedMessage)); + + //If receive Mode = Peek Lock, save the message to be settled later + if (GetReceiveMode() != null && (GetReceiveMode() == ServiceBusReceiveMode.PeekLock)) + { + if (!AddOrUpdateStoredServiceReceivedMessage(serviceBusReceivedMessage)) + throw new Exception("Invalid operation. Try retrieving the message again."); } + success = true; + return (SBReceivedMessageToBrokerMessage(serviceBusReceivedMessage)); } } catch (AggregateException ae) @@ -517,7 +615,7 @@ public long ScheduleMessage(BrokerMessage brokerMessage, string options) Task task; if (_sender != null) { - task = Task.Run(async () => await ScheduleMessageAsync(serviceBusMessage, options)); + task = Task.Run(async () => await ScheduleMessageAsync(serviceBusMessage, options).ConfigureAwait(false)); sequenceNumber = task.Result; ClearServiceBusAuxiliaryStorage(); } @@ -540,7 +638,7 @@ public bool CancelSchedule(long sequenceNumber) Task task; if (_sender != null) { - task = Task.Run(async () => await CancelScheduleAsync(sequenceNumber)); + task = Task.Run(async () => await CancelScheduleAsync(sequenceNumber).ConfigureAwait(false)); success = task.Result; ClearServiceBusAuxiliaryStorage(); } @@ -559,8 +657,8 @@ public bool GetMessageFromException(Exception ex, SdtMessages_Message msg) { try { - Azure.RequestFailedException az_ex = (Azure.RequestFailedException)ex; - msg.gxTpr_Id = az_ex.ErrorCode; + ServiceBusException az_ex = (ServiceBusException)ex; + msg.gxTpr_Id = az_ex.Reason.ToString(); msg.gxTpr_Description = az_ex.Message; return true; } @@ -569,9 +667,23 @@ public bool GetMessageFromException(Exception ex, SdtMessages_Message msg) return false; } } + #endregion #region Transformation Methods + private ServiceBusSessionReceiverOptions BrokerRecOptsToServiceBusSessionRecOpts(BrokerReceiverOpts brokerReceiverOptions) + { + ServiceBusSessionReceiverOptions serviceBusSessionReceiverOptions = new ServiceBusSessionReceiverOptions(); + if (brokerReceiverOptions != null) + { + serviceBusSessionReceiverOptions.PrefetchCount = brokerReceiverOptions.PrefetchCount; + serviceBusSessionReceiverOptions.Identifier = brokerReceiverOptions.Identifier; + serviceBusSessionReceiverOptions.ReceiveMode = brokerReceiverOptions.ReceiveMode; + return serviceBusSessionReceiverOptions; + } + return null; + + } private ServiceBusMessage BrokerMessageToServiceBusMessage(BrokerMessage brokerMessage) { if (brokerMessage != null) @@ -618,9 +730,10 @@ internal class ReceiveMessageOptions { int _maxmessages; int _maxwaittime; - string _sessionid; + PeekReceiveOpts _peekreceiveopts; IList _receivedeferredsequencenumbers; + BrokerReceiverOpts _brokerreceiveroptions; [DataMember()] internal int MaxMessages { get => _maxmessages; set => _maxmessages = value; } @@ -628,14 +741,36 @@ internal class ReceiveMessageOptions [DataMember()] internal int MaxWaitTime { get => _maxwaittime; set => _maxwaittime = value; } - [DataMember()] - internal string SessionId { get => _sessionid; set => _sessionid = value ; } - [DataMember()] internal PeekReceiveOpts PeekReceive { get => _peekreceiveopts; set => _peekreceiveopts = value; } [DataMember()] internal IList ReceiveDeferredSequenceNumbers { get => _receivedeferredsequencenumbers; set => _receivedeferredsequencenumbers = value; } + + [DataMember()] + internal BrokerReceiverOpts BrokerReceiverOptions { get => _brokerreceiveroptions; set => _brokerreceiveroptions = value; } + } + + [DataContract()] + public class BrokerReceiverOpts + { + ServiceBusReceiveMode _receiveMode; + int _prefetchCount; + string _identifier; + string _sessionId; + + [DataMember()] + internal int PrefetchCount { get => _prefetchCount; set => _prefetchCount = value; } + + [DataMember()] + internal string Identifier { get => _identifier; set => _identifier = value; } + + [DataMember()] + internal string SessionId { get => _sessionId; set => _sessionId = value; } + + [DataMember()] + internal ServiceBusReceiveMode ReceiveMode { get => _receiveMode; set => _receiveMode = value; } + } [DataContract()] @@ -654,8 +789,15 @@ public class PeekReceiveOpts [DataContract] internal class ConsumeMessageOptions { + + BrokerReceiverOpts _brokerreceiveroptions; + [DataMember] internal ConsumeModeOpts ConsumeMode { get; set; } + + [DataMember()] + internal BrokerReceiverOpts BrokerReceiverOptions { get => _brokerreceiveroptions; set => _brokerreceiveroptions = value; } + internal enum ConsumeModeOpts { Complete, @@ -670,6 +812,15 @@ internal enum ConsumeModeOpts #region Helper methods + private ServiceBusReceiveMode? GetReceiveMode() + { + if (_sessionEnabled) + return _sessionEnabledQueueReceiveMode; + else + if (_serviceBusReceiverOptions != null) + return _serviceBusReceiverOptions.ReceiveMode; + return null; + } private ServiceBusReceivedMessage GetStoredServiceBusReceivedMessage(BrokerMessage message) { string messageIdentifier = GetMessageIdentifier(message); @@ -818,7 +969,6 @@ private void LoadReceivedMessageProperties(ServiceBusReceivedMessage serviceBusR brokerMessage.MessageAttributes.Add(o.Key, o.Value.ToString()); } } - } private void LoadMessageProperties(GXProperties properties, ref ServiceBusMessage serviceBusMessage) { diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj index fded4a3b6..ac8137a4a 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj @@ -7,7 +7,7 @@ - + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs index d1c3d6287..0aa749ba0 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageQueue.cs @@ -4,7 +4,6 @@ using System.IO; using System.Reflection; using System.Text; -using GeneXus.Application; using GeneXus.Services; using GeneXus.Utils; using GxClasses.Helpers; @@ -144,36 +143,26 @@ public bool ConsumeMessage(GxUserType messageQueue, string options, out GXBaseCo public GxUserType GetMessage(string options, out GXBaseCollection errorMessages, out bool success) { errorMessages = new GXBaseCollection(); - GxUserType receivedMessage = new GxUserType(); success = false; try { - try - { - ValidQueue(); - BrokerMessage brokerMessage = messageBroker.GetMessage(options, out success); - LoadAssemblyIfRequired(); + ValidQueue(); + BrokerMessage brokerMessage = messageBroker.GetMessage(options, out success); + LoadAssemblyIfRequired(); - if (TransformBrokerMessage(brokerMessage) is GxUserType result) - { - success = true; - return result; - } - } - catch (Exception ex) + if (TransformBrokerMessage(brokerMessage) is GxUserType result) { - QueueErrorMessagesSetup(ex, out errorMessages); - GXLogging.Error(logger, ex); - success = false; + success = true; + return result; } } catch (Exception ex) { + QueueErrorMessagesSetup(ex, out errorMessages); GXLogging.Error(logger, ex); success = false; - throw ex; } - return receivedMessage; + return TransformBrokerMessage(new BrokerMessage()); } public IList GetMessages(string options, out GXBaseCollection errorMessages, out bool success) { @@ -182,40 +171,28 @@ public IList GetMessages(string options, out GXBaseCollection brokerMessages = messageBroker.GetMessages(options, out success); - LoadAssemblyIfRequired(); - foreach (BrokerMessage brokerMessage in brokerMessages) - { - if (TransformBrokerMessage(brokerMessage) is GxUserType result) - resultMessages.Add(result); - } - success = true; - - } - catch (Exception ex) + ValidQueue(); + IList brokerMessages = messageBroker.GetMessages(options, out success); + LoadAssemblyIfRequired(); + foreach (BrokerMessage brokerMessage in brokerMessages) { - QueueErrorMessagesSetup(ex, out errorMessages); - GXLogging.Error(logger, ex); - success = false; + if (TransformBrokerMessage(brokerMessage) is GxUserType result) + resultMessages.Add(result); } + success = true; } catch (Exception ex) { + QueueErrorMessagesSetup(ex, out errorMessages); GXLogging.Error(logger, ex); success = false; - throw ex; } - return resultMessages; } public bool SendMessage(GxUserType messageQueue, string options, out GXBaseCollection errorMessages) { bool success = false; errorMessages = new GXBaseCollection(); - GxUserType result = new GxUserType(); try { BrokerMessage brokerQueueMessage = TransformGXUserTypeToBrokerMessage(messageQueue); @@ -223,7 +200,8 @@ public bool SendMessage(GxUserType messageQueue, string options, out GXBaseColle try { ValidQueue(); - return(messageBroker.SendMessage(brokerQueueMessage, options)); + if (messageBroker != null) + return(messageBroker.SendMessage(brokerQueueMessage, options)); } catch (Exception ex) { @@ -278,25 +256,31 @@ public bool SendMessages(IList queueMessages, string options, out GXBaseCollecti protected void QueueErrorMessagesSetup(Exception ex, out GXBaseCollection errorMessages) { errorMessages = new GXBaseCollection(); + bool foundGeneralException = false; if (errorMessages != null && ex != null) { SdtMessages_Message msg = new SdtMessages_Message(); - if (messageBroker != null && messageBroker.GetMessageFromException(ex, msg)) - { - msg.gxTpr_Type = 1; - StringBuilder str = new StringBuilder(); - str.Append(ex.Message); + if (messageBroker != null) + { while (ex.InnerException != null) { - str.Append(ex.InnerException.Message); + if (messageBroker.GetMessageFromException(ex.InnerException, msg)) + { + msg.gxTpr_Type = 1; + errorMessages.Add(msg); + } + else + { + foundGeneralException = true; + break; + } ex = ex.InnerException; } - msg.gxTpr_Description = str.ToString(); - errorMessages.Add(msg); + if (foundGeneralException) + GXUtil.ErrorToMessages("GXServiceBus1002", ex, errorMessages); } else { - GXLogging.Error(logger, "(GXServiceBus1002)Queue Error", ex); GXUtil.ErrorToMessages("GXServiceBus1002", ex, errorMessages); } } From a9f1295e26957974972ba0d2b78af282cb578125 Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Mon, 14 Nov 2022 22:24:52 -0300 Subject: [PATCH 11/13] refactoring of consume method --- .../GXAzureServiceBus/AzureServiceBus.cs | 82 ++++++++++++++++--- 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs index 8e9a50493..01f384f9d 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs @@ -423,6 +423,66 @@ private async Task ReceiveMessageAsync(string options throw ex; } } + private async Task CompleteMessageAsync(ServiceBusReceiver receiver, ServiceBusReceivedMessage serviceBusReceivedMessage) + { + try + { + await receiver.CompleteMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false); + return true; + } + catch (ServiceBusException sbex) + { + throw sbex; + } + } + private async Task AbandonMessageAsync(ServiceBusReceiver receiver, ServiceBusReceivedMessage serviceBusReceivedMessage) + { + try + { + await receiver.AbandonMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false); + return true; + } + catch (ServiceBusException sbex) + { + throw sbex; + } + } + private async Task DeadLetterMessageAsync(ServiceBusReceiver receiver, ServiceBusReceivedMessage serviceBusReceivedMessage) + { + try + { + await receiver.DeadLetterMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false); + return true; + } + catch (ServiceBusException sbex) + { + throw sbex; + } + } + private async Task DeferMessageAsync(ServiceBusReceiver receiver, ServiceBusReceivedMessage serviceBusReceivedMessage) + { + try + { + await receiver.DeferMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false); + return true; + } + catch (ServiceBusException sbex) + { + throw sbex; + } + } + private async Task RenewMessageLockAsync(ServiceBusReceiver receiver, ServiceBusReceivedMessage serviceBusReceivedMessage) + { + try + { + await receiver.RenewMessageLockAsync(serviceBusReceivedMessage).ConfigureAwait(false); + return true; + } + catch (ServiceBusException sbex) + { + throw sbex; + } + } #endregion #region API Methods @@ -524,38 +584,38 @@ public bool ConsumeMessage(BrokerMessage brokerMessage, string options) { try { - Task task; + Task taskB; switch (consumeOptions.ConsumeMode) { case ConsumeMessageOptions.ConsumeModeOpts.Complete: { - task = Task.Run(async () => await receiver.CompleteMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false)); + taskB = Task.Run(async () => await CompleteMessageAsync(receiver,serviceBusReceivedMessage).ConfigureAwait(false)); RemoveStoredServiceBusReceivedMessage(brokerMessage); - break; + return taskB.Result; } case ConsumeMessageOptions.ConsumeModeOpts.Abandon: { - task = Task.Run(async () => await receiver.AbandonMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false)); + taskB = Task.Run(async () => await AbandonMessageAsync(receiver,serviceBusReceivedMessage).ConfigureAwait(false)); RemoveStoredServiceBusReceivedMessage(brokerMessage); - break; + return taskB.Result; } case ConsumeMessageOptions.ConsumeModeOpts.DeadLetter: { - task = Task.Run(async () => await receiver.DeadLetterMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false)); + taskB = Task.Run(async () => await DeadLetterMessageAsync(receiver,serviceBusReceivedMessage).ConfigureAwait(false)); RemoveStoredServiceBusReceivedMessage(brokerMessage); - break; + return taskB.Result; } case ConsumeMessageOptions.ConsumeModeOpts.Defer: { - task = Task.Run(async () => await receiver.DeferMessageAsync(serviceBusReceivedMessage).ConfigureAwait(false)); + taskB = Task.Run(async () => await DeferMessageAsync(receiver,serviceBusReceivedMessage).ConfigureAwait(false)); RemoveStoredServiceBusReceivedMessage(brokerMessage); - break; + return taskB.Result; } case ConsumeMessageOptions.ConsumeModeOpts.RenewMessageLock: { - task = Task.Run(async () => await receiver.RenewMessageLockAsync(serviceBusReceivedMessage).ConfigureAwait(false)); + taskB = Task.Run(async () => await RenewMessageLockAsync(receiver,serviceBusReceivedMessage).ConfigureAwait(false)); RemoveStoredServiceBusReceivedMessage(brokerMessage); - break; + return taskB.Result; } } return true; From 09284000c808573077c6f82a8cc3740f59e514a9 Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Tue, 15 Nov 2022 08:33:22 -0300 Subject: [PATCH 12/13] Fix connect without additional parameters --- .../Messaging/GXAzureServiceBus/AzureServiceBus.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs index 01f384f9d..e00d3c3c4 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/AzureServiceBus.cs @@ -42,7 +42,13 @@ private void Initialize(GXService providerService) _connectionString = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.QUEUE_CONNECTION_STRING); _subscriptionName = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.TOPIC_SUBSCRIPTION); - _sessionEnabled = Convert.ToBoolean(serviceSettings.GetEncryptedPropertyValue(PropertyConstants.SESSION_ENABLED)); + string sessionEnabled = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.SESSION_ENABLED); + + if (!string.IsNullOrEmpty(sessionEnabled)) + _sessionEnabled = Convert.ToBoolean(sessionEnabled); + else + _sessionEnabled = false; + string senderIdentifier = serviceSettings.GetEncryptedOptPropertyValue(PropertyConstants.SENDER_IDENTIFIER); ServiceBusSenderOptions serviceBusSenderOptions = new ServiceBusSenderOptions(); From b937d6ac1097684fdc2735c9927d7b0fd2fca1be Mon Sep 17 00:00:00 2001 From: sjuarezgx Date: Tue, 15 Nov 2022 18:46:30 -0300 Subject: [PATCH 13/13] Change custom error codes --- .../Messaging/GXMessageBroker/MessageBrokerProvider.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs index 3bc11056f..c3acfb7d8 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXMessageBroker/MessageBrokerProvider.cs @@ -24,8 +24,8 @@ public MessageQueue Connect(string providerTypeName, GXProperties properties, ou MessageQueue messageQueue = new MessageQueue(); if (string.IsNullOrEmpty(providerTypeName)) { - GXUtil.ErrorToMessages("GXMessageBroker1000", "Message Broker provider cannot be empty", errorMessages); - GXLogging.Error(logger, "(GXMessageBroker1000)Failed to Connect to a Message Broker : Provider cannot be empty."); + GXUtil.ErrorToMessages("GXMessageBroker", "Message Broker provider cannot be empty", errorMessages); + GXLogging.Error(logger, "(GXMessageBroker)Failed to Connect to a Message Broker : Provider cannot be empty."); success = false; return messageQueue; } @@ -56,8 +56,8 @@ public MessageQueue Connect(string providerTypeName, GXProperties properties, ou } catch (Exception ex) { - GXLogging.Error(logger, "(GXMessageBroker1001)Couldn't connect to Message Broker provider: " + ExceptionExtensions.GetInnermostException(ex)); - GXUtil.ErrorToMessages("GXMessageBroker1001", ex, errorMessages); + GXLogging.Error(logger, "(GXMessageBroker)Couldn't connect to Message Broker provider: " + ExceptionExtensions.GetInnermostException(ex)); + GXUtil.ErrorToMessages("GXMessageBroker", ex, errorMessages); success = false; return messageQueue; }