Skip to content

Commit

Permalink
Azure Event Grid API implementation (#848)
Browse files Browse the repository at this point in the history
  • Loading branch information
sjuarezgx authored Jul 26, 2023
1 parent 681d468 commit a9c0a9d
Show file tree
Hide file tree
Showing 16 changed files with 795 additions and 103 deletions.
14 changes: 14 additions & 0 deletions dotnet/DotNetStandardClasses.sln
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down
1 change: 1 addition & 0 deletions dotnet/src/dotnetcore/GxClasses/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
Original file line number Diff line number Diff line change
@@ -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<GXCloudEvent> gxCloudEvents, bool binaryData)
{
List<CloudEvent> evts = new List<CloudEvent>();
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<GXEventGridSchema> evts = JsonSerializer.Deserialize<List<GXEventGridSchema>>(jsonString);

IList<EventGridEvent> eventGridEvents = new List<EventGridEvent>();
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<GXEventGridSchema>(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
/// <summary>
/// Send asynchronously an event formatted as Azure EventGrid Schema.
/// </summary>
/// <param name="evt"></param>
/// <returns></returns>
private async Task sendEventGridSchemaEventAsync(EventGridEvent evt)
{
await _client.SendEventAsync(evt).ConfigureAwait(false);

}
/// <summary>
/// Send asynchronously a list of events formatted as Azure EventGrid Schema.
/// </summary>
/// <param name="evts"></param>
/// <returns></returns>
private async Task sendEventGridSchemaEventsAsync(IEnumerable<EventGridEvent> evts)
{
await _client.SendEventsAsync(evts).ConfigureAwait(false);
}
/// <summary>
/// Send asynchronously an event formatted as CloudEvent Schema.
/// </summary>
/// <param name="cloudEvent"></param>
/// <returns></returns>
private async Task sendEvtAsync(CloudEvent cloudEvent)
{
await _client.SendEventAsync(cloudEvent).ConfigureAwait(false);

}
/// <summary>
/// Send asynchronously a list of CloudEvent Schema formatted events.
/// </summary>
/// <param name="cloudEvents"></param>
/// <returns></returns>
private async Task sendEvtsAsync(IEnumerable<CloudEvent> 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<string, object> emptyData = new Dictionary<string, object>();
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; }


}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using GeneXus.Messaging.Common;
using GeneXus.Utils;

namespace GeneXus.Messaging.GXAzureEventGrid
{
/// <summary>
/// Implementation of EventGridRouterProvider External Object.
/// </summary>
public class EventGridRouterProvider
{
public EventRouterProviderBase Connect(string endpoint, string accesskey, out GXBaseCollection<SdtMessages_Message> 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<SdtMessages_Message> errorMessagesConnect, out bool successConnect);
errorMessages = errorMessagesConnect;
success = successConnect;
return evtRouterProvider;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<PackageId>GeneXus.Azure.EventGrid</PackageId>
<PackageTags>Azure EventGrid Messaging</PackageTags>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.Messaging.EventGrid" Version="4.17.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\GXEventRouter\GXEventRouter.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Azure.Storage.Queues" Version="12.11.0" />
<PackageReference Include="Azure.Storage.Queues" Version="12.15.0" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit a9c0a9d

Please sign in to comment.