Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azure Event Grid API implementation #848

Merged
merged 10 commits into from
Jul 26, 2023
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);
ggallotti marked this conversation as resolved.
Show resolved Hide resolved

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