diff --git a/dotnet/DotNetStandardClasses.sln b/dotnet/DotNetStandardClasses.sln index 8650b334f..4822f78c0 100644 --- a/dotnet/DotNetStandardClasses.sln +++ b/dotnet/DotNetStandardClasses.sln @@ -243,6 +243,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GxOffice", "src\dotnetcore\ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "excel", "excel", "{B521FF6D-E081-4DE6-AC00-A9BE3B6439D1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GXEventRouter", "src\dotnetcore\Providers\Messaging\GXEventRouter\GXEventRouter.csproj", "{5BBC75F0-E51A-4EBD-A628-92498D319B1D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GXAzureEventGrid", "src\dotnetcore\Providers\Messaging\GXAzureEventGrid\GXAzureEventGrid.csproj", "{7250CDB1-95C4-4822-B01B-3CBD73324CC9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -585,6 +589,14 @@ Global {E1CD114A-F8A5-4246-B5E3-FD27EDEC7C82}.Debug|Any CPU.Build.0 = Debug|Any CPU {E1CD114A-F8A5-4246-B5E3-FD27EDEC7C82}.Release|Any CPU.ActiveCfg = Release|Any CPU {E1CD114A-F8A5-4246-B5E3-FD27EDEC7C82}.Release|Any CPU.Build.0 = Release|Any CPU + {5BBC75F0-E51A-4EBD-A628-92498D319B1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5BBC75F0-E51A-4EBD-A628-92498D319B1D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5BBC75F0-E51A-4EBD-A628-92498D319B1D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5BBC75F0-E51A-4EBD-A628-92498D319B1D}.Release|Any CPU.Build.0 = Release|Any CPU + {7250CDB1-95C4-4822-B01B-3CBD73324CC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7250CDB1-95C4-4822-B01B-3CBD73324CC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7250CDB1-95C4-4822-B01B-3CBD73324CC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7250CDB1-95C4-4822-B01B-3CBD73324CC9}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -701,6 +713,8 @@ Global {BE108BE8-805D-4FCF-86BA-B2EAF581FFB2} = {F900A4AD-7249-41B4-B918-CB9E8C73747C} {E1CD114A-F8A5-4246-B5E3-FD27EDEC7C82} = {B521FF6D-E081-4DE6-AC00-A9BE3B6439D1} {B521FF6D-E081-4DE6-AC00-A9BE3B6439D1} = {2261B65E-3757-4E5B-9DCD-EAE8D1E236A3} + {5BBC75F0-E51A-4EBD-A628-92498D319B1D} = {4C43F2DA-59E5-46F5-B691-195449498555} + {7250CDB1-95C4-4822-B01B-3CBD73324CC9} = {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 2109ab09c..80e2eff77 100644 --- a/dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs +++ b/dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs @@ -7,6 +7,7 @@ [assembly: InternalsVisibleTo("AzureFunctionsTest")] [assembly: InternalsVisibleTo("GXQueue")] [assembly: InternalsVisibleTo("GXMessageBroker")] +[assembly: InternalsVisibleTo("GXEventRouter")] [assembly: InternalsVisibleTo("DotNetCoreUnitTest")] [assembly: InternalsVisibleTo("DotNetCoreWebUnitTest")] [assembly: InternalsVisibleTo("GeneXus.Deploy.AzureFunctions.Handlers")] diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/AzureEventGrid.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/AzureEventGrid.cs new file mode 100644 index 000000000..584464ee4 --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/AzureEventGrid.cs @@ -0,0 +1,297 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Runtime.Serialization; +using System.Text.Json; +using System.Threading.Tasks; +using Azure; +using Azure.Messaging; +using Azure.Messaging.EventGrid; +using GeneXus.Messaging.Common; +using GeneXus.Services; +using GeneXus.Utils; + +namespace GeneXus.Messaging.GXAzureEventGrid +{ + public class AzureEventGrid : EventRouterBase, IEventRouter + { + public static string Name = "AZUREEVENTGRID"; + private EventGridPublisherClient _client; + private string _endpoint; + private string _accessKey; + public AzureEventGrid() : this(null) + { + } + public AzureEventGrid(GXService providerService) : base(providerService) + { + Initialize(providerService); + } + private void Initialize(GXService providerService) + { + ServiceSettings serviceSettings = new(PropertyConstants.EVENT_ROUTER, Name, providerService); + _endpoint = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.URI_ENDPOINT); + _accessKey = serviceSettings.GetEncryptedPropertyValue(PropertyConstants.ACCESS_KEY); + + if (!string.IsNullOrEmpty(_endpoint)) { + + _client = new EventGridPublisherClient( + new Uri(_endpoint), + new AzureKeyCredential(_accessKey)); + } + else + throw new Exception("Endpoint URI must be set."); + } + public override string GetName() + { + return Name; + } + + public bool SendEvent(GXCloudEvent gxCloudEvent, bool binaryData) + { + CloudEvent evt = ToCloudEvent(gxCloudEvent, binaryData); + bool success = false; + try + { + Task task; + if (_client != null) + { + task = Task.Run(async () => await sendEvtAsync(evt).ConfigureAwait(false)); + success = true; + } + else + { + throw new Exception("There was an error at the Event Grid initialization."); + } + } + catch (AggregateException ae) + { + throw ae; + } + return success; + } + public bool SendEvents(IList gxCloudEvents, bool binaryData) + { + List evts = new List(); + foreach (GXCloudEvent e in gxCloudEvents) + evts.Add(ToCloudEvent(e, binaryData)); + + bool success = false; + try + { + Task task; + if (_client != null) + { + task = Task.Run(async () => await sendEvtsAsync(evts).ConfigureAwait(false)); + success = true; + } + else + { + throw new Exception("There was an error at the Event Grid initialization."); + } + } + catch (AggregateException ae) + { + throw ae; + } + return success; + } + public bool SendCustomEvents(string jsonString, bool isBinary) + { + if (string.IsNullOrEmpty(jsonString)) + { + throw new Exception("Events cannot be empty."); + } + try + { + List evts = JsonSerializer.Deserialize>(jsonString); + + IList eventGridEvents = new List(); + foreach (GXEventGridSchema e in evts) + eventGridEvents.Add(ToEventGridSchema(e,isBinary)); + + bool success = false; + try + { + Task task; + if (_client != null) + { + task = Task.Run(async () => await sendEventGridSchemaEventsAsync(eventGridEvents).ConfigureAwait(false)); + success = true; + } + else + { + throw new Exception("There was an error at the Event Grid initialization."); + } + } + catch (AggregateException ae) + { + throw ae; + } + return success; + } + catch (JsonException) + { + try + { + GXEventGridSchema evt = JsonSerializer.Deserialize(jsonString); + bool success = false; + try + { + Task task; + if (_client != null) + { + task = Task.Run(async () => await sendEventGridSchemaEventAsync(ToEventGridSchema(evt, isBinary)).ConfigureAwait(false)); + success = true; + } + else + { + throw new Exception("There was an error at the Event Grid initialization."); + } + } + catch (AggregateException ae) + { + throw ae; + } + return success; + } + catch (JsonException) + { + throw new Exception("jsonEvents parameter format is no correct. Valid format is AzureEventGrid.EventGridSchema SDT."); + } + } + } + + #region Async methods + /// + /// Send asynchronously an event formatted as Azure EventGrid Schema. + /// + /// + /// + private async Task sendEventGridSchemaEventAsync(EventGridEvent evt) + { + await _client.SendEventAsync(evt).ConfigureAwait(false); + + } + /// + /// Send asynchronously a list of events formatted as Azure EventGrid Schema. + /// + /// + /// + private async Task sendEventGridSchemaEventsAsync(IEnumerable evts) + { + await _client.SendEventsAsync(evts).ConfigureAwait(false); + } + /// + /// Send asynchronously an event formatted as CloudEvent Schema. + /// + /// + /// + private async Task sendEvtAsync(CloudEvent cloudEvent) + { + await _client.SendEventAsync(cloudEvent).ConfigureAwait(false); + + } + /// + /// Send asynchronously a list of CloudEvent Schema formatted events. + /// + /// + /// + private async Task sendEvtsAsync(IEnumerable cloudEvents) + { + await _client.SendEventsAsync(cloudEvents).ConfigureAwait(false); + } + + #endregion + + #region TransformMethods + public bool GetMessageFromException(Exception ex, SdtMessages_Message msg) + { + try + { + RequestFailedException az_ex = (RequestFailedException)ex; + msg.gxTpr_Id = az_ex.ErrorCode.ToString(); + msg.gxTpr_Description = az_ex.Message; + return true; + } + catch (Exception) + { + return false; + } + } + private EventGridEvent ToEventGridSchema(GXEventGridSchema gxEventGridSchema, bool isBinary) + { + EventGridEvent evt; + if (isBinary && !string.IsNullOrEmpty(gxEventGridSchema.data)) + { + BinaryData binaryData = new BinaryData(gxEventGridSchema.data); + evt = new EventGridEvent(gxEventGridSchema.subject, gxEventGridSchema.eventtype, gxEventGridSchema.dataversion, binaryData);} + else + evt = new EventGridEvent(gxEventGridSchema.subject, gxEventGridSchema.eventtype, gxEventGridSchema.dataversion, gxEventGridSchema.data, null); + if (!string.IsNullOrEmpty(gxEventGridSchema.id)) + evt.Id = gxEventGridSchema.id; + if (!string.IsNullOrEmpty(gxEventGridSchema.topic)) + evt.Topic = gxEventGridSchema.topic; + if (gxEventGridSchema.eventtime != DateTime.MinValue) + evt.EventTime = gxEventGridSchema.eventtime; + + return evt; + } + private CloudEvent ToCloudEvent(GXCloudEvent gxCloudEvent, bool isBinaryData) + { + CloudEvent evt; + Dictionary emptyData = new Dictionary(); + if (string.IsNullOrEmpty(gxCloudEvent.data)) + evt = new CloudEvent(source:gxCloudEvent.source, type:gxCloudEvent.type, emptyData); + else + { + if (!isBinaryData) + { + if (string.IsNullOrEmpty(gxCloudEvent.datacontenttype)) + gxCloudEvent.datacontenttype = "application/json"; + evt = new CloudEvent(gxCloudEvent.source, gxCloudEvent.type, BinaryData.FromString(gxCloudEvent.data),gxCloudEvent.datacontenttype,CloudEventDataFormat.Json); + } + else + { + if (string.IsNullOrEmpty(gxCloudEvent.datacontenttype)) + gxCloudEvent.datacontenttype = "application/octet-stream"; + evt = new CloudEvent(gxCloudEvent.source, gxCloudEvent.type, BinaryData.FromString(gxCloudEvent.data), gxCloudEvent.datacontenttype,CloudEventDataFormat.Binary); + } + } + if (!string.IsNullOrEmpty(gxCloudEvent.id)) + evt.Id = gxCloudEvent.id; + if (!string.IsNullOrEmpty(gxCloudEvent.dataschema)) + evt.DataSchema = gxCloudEvent.dataschema; + if (!string.IsNullOrEmpty(gxCloudEvent.subject)) + evt.Subject = gxCloudEvent.subject; + if (gxCloudEvent.time != DateTime.MinValue) + evt.Time = gxCloudEvent.time; + return evt; + } + #endregion + } + + [DataContract] + public class GXEventGridSchema + { + [DataMember] + public string topic { get; set; } + [DataMember] + public string eventtype { get; set; } + [DataMember] + public string id { get; set; } + [DataMember] + public string subject { get; set; } + [DataMember] + public string data { get; set; } + [DataMember] + public string dataversion { get; set; } + + [DataMember] + public DateTime eventtime { get; set; } + + [DataMember] + public string metadataversion { get; set; } + + + } +} \ No newline at end of file diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/EventGridRouterProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/EventGridRouterProvider.cs new file mode 100644 index 000000000..f8c9e20ae --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/EventGridRouterProvider.cs @@ -0,0 +1,26 @@ +using GeneXus.Messaging.Common; +using GeneXus.Utils; + +namespace GeneXus.Messaging.GXAzureEventGrid +{ + /// + /// Implementation of EventGridRouterProvider External Object. + /// + public class EventGridRouterProvider + { + public EventRouterProviderBase Connect(string endpoint, string accesskey, out GXBaseCollection errorMessages, out bool success) + { + EventRouterProvider eventRouterProvider = new EventRouterProvider(); + GXProperties properties = new GXProperties + { + { PropertyConstants.EVENTROUTER_AZUREEG_ENDPOINT, endpoint }, + { PropertyConstants.EVENTROUTER_AZUREEG_ACCESS_KEY, accesskey } + }; + + EventRouterProviderBase evtRouterProvider = eventRouterProvider.Connect(PropertyConstants.AZUREEVENTGRID, properties, out GXBaseCollection errorMessagesConnect, out bool successConnect); + errorMessages = errorMessagesConnect; + success = successConnect; + return evtRouterProvider; + } + } +} diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/GXAzureEventGrid.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/GXAzureEventGrid.csproj new file mode 100644 index 000000000..0dd71f20c --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureEventGrid/GXAzureEventGrid.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + GeneXus.Azure.EventGrid + Azure EventGrid Messaging + + + + + + + + + + + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/GXAzureQueue.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/GXAzureQueue.csproj index a9fc132d3..491be781c 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/GXAzureQueue.csproj +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureQueue/GXAzureQueue.csproj @@ -7,7 +7,7 @@ - + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXAzureServiceBus/GXAzureServiceBus.csproj index ac8137a4a..2de414bc5 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/GXEventRouter/EventRouter.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouter.cs new file mode 100644 index 000000000..56fa53a2a --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouter.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using GeneXus.Utils; + +namespace GeneXus.Messaging.Common +{ + public interface IEventRouter + { + bool SendEvent(GXCloudEvent gxCloudEvent, bool binaryData); + bool SendEvents(IList gxCloudEvents, bool binaryData); + bool SendCustomEvents(string jsonString, bool isBinary); + bool GetMessageFromException(Exception ex, SdtMessages_Message msg); + } + public class GXCloudEvent : GxUserType + { + public string type { get; set; } + public string source { get; set; } + public string data { get; set; } + public string datacontenttype { get; set; } + public string id { get; set; } + public string dataschema { get; set; } + public string subject { get; set; } + public string data_base64 { get; set; } + public DateTime time { get; set; } + } + +} \ No newline at end of file diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterBase.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterBase.cs new file mode 100644 index 000000000..d8db3aeb0 --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterBase.cs @@ -0,0 +1,33 @@ +using System; +using GeneXus.Services; +using log4net; + +namespace GeneXus.Messaging.Common +{ + public abstract class EventRouterBase + { + static readonly ILog logger = LogManager.GetLogger(typeof(EventRouterBase)); + internal GXService service; + public EventRouterBase() + { + } + + public EventRouterBase(GXService s) + { + if (s == null) + { + try + { + s = ServiceFactory.GetGXServices()?.Get(GXServices.EVENTROUTER_SERVICE); + } + catch (Exception) + { + GXLogging.Warn(logger, "EVENTROUTER_SERVICE is not activated"); + } + } + + service = s; + } + public abstract string GetName(); + } +} diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProvider.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProvider.cs new file mode 100644 index 000000000..410543865 --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProvider.cs @@ -0,0 +1,113 @@ +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 EventRouterProvider : EventRouterProviderBase + { + static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private static GXService providerService; + public EventRouterProvider() { + } + public EventRouterProviderBase Connect(string providerTypeName, GXProperties properties, out GXBaseCollection errorMessages, out bool success) + { + errorMessages = new GXBaseCollection(); + EventRouterProviderBase eventRouter = new EventRouterProviderBase(); + if (string.IsNullOrEmpty(providerTypeName)) + { + GXUtil.ErrorToMessages("GXEventRouter", "Event Router provider cannot be empty", errorMessages); + GXLogging.Error(logger, "(GXEventRouter)Failed to Connect to a Event Router : Provider cannot be empty."); + success = false; + return eventRouter; + } + try + { + if (providerService == null || !string.Equals(providerService.Name, providerTypeName, StringComparison.OrdinalIgnoreCase)) + { + providerService = new GXService(); + providerService.Type = GXServices.EVENTROUTER_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 Event Router provider: " + typeFullName); + Type type = AssemblyLoader.GetType(typeFullName); + eventRouter.eventRouter = (IEventRouter)Activator.CreateInstance(type, new object[] { providerService }); + + } + catch (Exception ex) + { + GXLogging.Error(logger, "(GXEventRouter)Couldn't connect to Event Router provider: " + ExceptionExtensions.GetInnermostException(ex)); + GXUtil.ErrorToMessages("GXEventRouter", ex, errorMessages); + success = false; + return eventRouter; + } + success = true; + return (eventRouter); + } + private static void Preprocess(string name, GXProperties properties) + { + string className; + + switch (name) + { + case Providers.AzureEventGrid: + className = PropertyConstants.AZURE_EG_CLASSNAME; + SetEncryptedProperty(properties, PropertyConstants.EVENTROUTER_AZUREEG_ENDPOINT); + SetEncryptedProperty(properties, PropertyConstants.EVENTROUTER_AZUREEG_ACCESS_KEY); + if (string.IsNullOrEmpty(providerService.ClassName) || !providerService.ClassName.Contains(className)) + { + providerService.ClassName = PropertyConstants.AZURE_EG_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 AzureEventGrid = "AZUREEVENTGRID"; + } +} diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProviderBase.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProviderBase.cs new file mode 100644 index 000000000..2ab0a67c8 --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/EventRouterProviderBase.cs @@ -0,0 +1,226 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using GeneXus.Services; +using GeneXus.Utils; +using GxClasses.Helpers; +using log4net; + +namespace GeneXus.Messaging.Common +{ + public class EventRouterProviderBase + { + internal IEventRouter eventRouter = null; + public static Assembly assembly; + static readonly ILog logger = LogManager.GetLogger(typeof(EventRouterProviderBase)); + private const string MODULE_DLL = @"GeneXusEventMessaging"; + + public EventRouterProviderBase() + { + } + public EventRouterProviderBase(EventRouterProviderBase other) + { + eventRouter = other.eventRouter; + } + void ValidQueue() + { + if (eventRouter == null) + { + GXLogging.Error(logger, "Event Router was not instantiated."); + throw new Exception("Event Router was not instantiated."); + } + } + private static void LoadAssemblyIfRequired() + { + if (assembly == null) + { + assembly = AssemblyLoader.LoadAssembly(new AssemblyName(MODULE_DLL)); + } + } + + public bool SendEvent(GxUserType evt, bool binaryData, out GXBaseCollection errorMessages) + { + bool success = false; + errorMessages = new GXBaseCollection(); + try + { + GXCloudEvent gxCloudEvent = ToGXCloudEvent(evt); + LoadAssemblyIfRequired(); + try + { + ValidQueue(); + if (eventRouter != null) + return(eventRouter.SendEvent(gxCloudEvent, binaryData)); + } + catch (Exception ex) + { + EventRouterErrorMessagesSetup(ex, out errorMessages); + success = false; + GXLogging.Error(logger, ex); + } + } + catch (Exception ex) + { + success = false; + GXLogging.Error(logger,ex); + throw ex; + } + return success; + } + + public bool SendCustomEvents(string evts, bool isBinary, out GXBaseCollection errorMessages) + { + errorMessages = new GXBaseCollection(); + bool success; + try + { + ValidQueue(); + success = eventRouter.SendCustomEvents(evts, isBinary); + } + catch (Exception ex) + { + EventRouterErrorMessagesSetup(ex, out errorMessages); + success = false; + GXLogging.Error(logger, ex); + } + return success; + } + + public bool SendEvents(IList evts, bool binaryData, out GXBaseCollection errorMessages) + { + errorMessages = new GXBaseCollection(); + bool success = false; + LoadAssemblyIfRequired(); + try + { + IList gxCloudEvents = new List(); + foreach (GxUserType e in evts) + { + if (ToGXCloudEvent(e) is GXCloudEvent gxCloudEvent) + gxCloudEvents.Add(gxCloudEvent); + } + try + { + ValidQueue(); + success = eventRouter.SendEvents(gxCloudEvents, binaryData); + } + catch (Exception ex) + { + EventRouterErrorMessagesSetup(ex, out errorMessages); + success = false; + GXLogging.Error(logger, ex); + } + } + catch (Exception ex) + { + GXLogging.Error(logger, ex); + throw ex; + } + return success; + } + + #region Transform operations + protected void EventRouterErrorMessagesSetup(Exception ex, out GXBaseCollection errorMessages) + { + errorMessages = new GXBaseCollection(); + bool foundGeneralException = false; + if (ex != null) + { + SdtMessages_Message msg = new SdtMessages_Message(); + if (eventRouter != null && ex.InnerException != null) + { + do + { + if (eventRouter.GetMessageFromException(ex.InnerException, msg)) + { + msg.gxTpr_Type = 1; + errorMessages.Add(msg); + } + else + { + foundGeneralException = true; + break; + } + ex = ex.InnerException; + } + while (ex.InnerException != null); + if (foundGeneralException) + GXUtil.ErrorToMessages("GXEventRouter", ex, errorMessages); + } + else + { + GXUtil.ErrorToMessages("GXEventRouter", ex, errorMessages); + } + } + } + private GXCloudEvent ToGXCloudEvent(GxUserType evt) + { + if (evt != null) + { + GXCloudEvent gxCloudEvent = new GXCloudEvent(); + gxCloudEvent.type = evt.GetPropertyValue("Type"); + gxCloudEvent.source = evt.GetPropertyValue("Source"); + gxCloudEvent.data = evt.GetPropertyValue("Data"); + gxCloudEvent.datacontenttype = evt.GetPropertyValue("Datacontenttype"); + gxCloudEvent.id = evt.GetPropertyValue("Id"); + gxCloudEvent.subject = evt.GetPropertyValue("Subject"); + gxCloudEvent.dataschema = evt.GetPropertyValue("Dataschema"); + gxCloudEvent.data_base64 = evt.GetPropertyValue("Data_base64"); + gxCloudEvent.time = evt.GetPropertyValue("Time"); + return gxCloudEvent; + } + return null; + } + #endregion + + } + internal class ServiceFactory + { + private static IEventRouter eventRouter; + private static readonly ILog log = LogManager.GetLogger(typeof(Services.ServiceFactory)); + + public static GXServices GetGXServices() + { + return GXServices.Instance; + } + + public static IEventRouter GetEventRouter() + { + if (eventRouter == null) + { + eventRouter = GetRouterImpl(GXServices.EVENTROUTER_SERVICE); + } + return eventRouter; + } + + public static IEventRouter GetRouterImpl(string service) + { + IEventRouter eventRouterImpl = null; + if (GetGXServices() != null) + { + GXService providerService = GetGXServices()?.Get(service); + if (providerService != null) + { + try + { + string typeFullName = providerService.ClassName; + GXLogging.Debug(log, "Loading Event Router settings:", typeFullName); + Type type = AssemblyLoader.GetType(typeFullName); + eventRouterImpl = (IEventRouter)Activator.CreateInstance(type); + } + catch (Exception e) + { + GXLogging.Error(log, "Couldn't connect to the Event Router.", e.Message, e); + throw e; + } + } + } + return eventRouterImpl; + } + } +} + + + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/GXEventRouter.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/GXEventRouter.csproj new file mode 100644 index 000000000..d1e59a220 --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/GXEventRouter.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + GeneXus.Message.EventRouter + Event Bus Messaging Router + TRACE;DEBUG;NETCORE + + + + + + + + + + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/PropertyConstants.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/PropertyConstants.cs new file mode 100644 index 000000000..2aed7d804 --- /dev/null +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXEventRouter/PropertyConstants.cs @@ -0,0 +1,17 @@ +namespace GeneXus.Messaging.Common +{ + public static class PropertyConstants + { + //Azure Event Grid + + internal const string AZURE_EG_CLASSNAME = "GeneXus.Messaging.GXAzureEventGrid.AzureEventGrid"; + internal const string AZURE_EG_PROVIDER_CLASSNAME = "GeneXus.Messaging.GXAzureEventGrid.AzureEventGrid, GXAzureEventGrid, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"; + public const string EVENT_ROUTER = "EVENTROUTER"; + public const string URI_ENDPOINT = "ENDPOINT"; + public const string ACCESS_KEY = "ACCESS_KEY"; + public const string AZUREEVENTGRID = "AZUREEVENTGRID"; + public const string EVENTROUTER_AZUREEG_ENDPOINT = "EVENTROUTER_AZUREEVENTGRID_ENDPOINT"; + public const string EVENTROUTER_AZUREEG_ACCESS_KEY = "EVENTROUTER_AZUREEVENTGRID_ACCESS_KEY"; + + } +} diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/GXQueue.csproj b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/GXQueue.csproj index b41e066ac..771581f34 100644 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/GXQueue.csproj +++ b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/GXQueue.csproj @@ -6,6 +6,10 @@ GeneXus.Message.Queue + + + + diff --git a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/ServiceSettings.cs b/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/ServiceSettings.cs deleted file mode 100644 index 443f5223e..000000000 --- a/dotnet/src/dotnetcore/Providers/Messaging/GXQueue/ServiceSettings.cs +++ /dev/null @@ -1,101 +0,0 @@ -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.Queue -{ - 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 5d0879298..0c652ecf7 100644 --- a/dotnet/src/dotnetframework/GxClasses/Services/Storage/GXServices.cs +++ b/dotnet/src/dotnetframework/GxClasses/Services/Storage/GXServices.cs @@ -24,6 +24,7 @@ public class GXServices public static string WEBNOTIFICATIONS_SERVICE = "WebNotifications"; public static string QUEUE_SERVICE = "QueueService"; public static string MESSAGEBROKER_SERVICE = "MessageBrokerService"; + public static string EVENTROUTER_SERVICE = "EventRouterService"; private static string[] SERVICES_FILE = new string[] { "CloudServices.dev.config", "CloudServices.config" }; [System.Diagnostics.CodeAnalysis.SuppressMessage("GxFxCopRules", "CR1000:EnforceThreadSafeType")] private Dictionary services = new Dictionary();