Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 196 additions & 0 deletions dotnet/src/extensions/Azure/Handlers/BlobHandler/BlobTriggerHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
using System;
using System.Collections;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using GeneXus.Application;
using GeneXus.Deploy.AzureFunctions.Handlers.Helpers;
using GeneXus.Metadata;
using GeneXus.Utils;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;

namespace GeneXus.Deploy.AzureFunctions.BlobHandler
{
public class BlobTriggerHandler
{
private ICallMappings _callmappings;

public BlobTriggerHandler(ICallMappings callMappings)
{
_callmappings = callMappings;
}
public void Run(string myTriggerItem, FunctionContext context)
{
var logger = context.GetLogger("BlobTriggerHandler");
string functionName = context.FunctionDefinition.Name;
Guid messageId = new Guid(context.InvocationId);
logger.LogInformation($"GeneXus Blob trigger handler. Function processed: {functionName}. Message Id: {messageId}. Function executed at: {DateTime.Now}");

try
{
ProcessMessage(context, logger, myTriggerItem, messageId.ToString());
}
catch (Exception ex) //Catch System exception and retry
{
logger.LogError(ex.ToString());
throw;
}
}
private void ProcessMessage(FunctionContext context, ILogger log, string myTriggerItem, string messageId)
{
CallMappings callmap = (CallMappings)_callmappings;

GxAzMappings map = callmap.mappings is object ? callmap.mappings.First(m => m.FunctionName == context.FunctionDefinition.Name) : null;
string gxProcedure = (map != null && map is object) ? map.GXEntrypoint : string.Empty;
string exMessage;

if (!string.IsNullOrEmpty(gxProcedure))
{
try
{
StringBuilder sb1 = new StringBuilder(gxProcedure);
sb1.Append(".dll");
string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), sb1.ToString());
Assembly obj = Assembly.LoadFile(path);

StringBuilder sb2 = new StringBuilder("GeneXus.Programs.");
sb2.Append(gxProcedure);

Type objexec = obj.GetType(sb2.ToString());
if (objexec != null)
{

object objgxproc = Activator.CreateInstance(objexec);
var method = objexec.GetMethod("execute");
ParameterInfo[] parameters = method.GetParameters();

//Check parameters

if (parameters.Length != 2)
{
//Thrown to the Azure monitor

exMessage = string.Format("{0} Error for Message Id {1}: the number of parameters in GeneXus procedure is not correct.", FunctionExceptionType.SysRuntimeError, messageId);
throw new Exception(exMessage); //Send to retry if possible.
}
else
{
//Two valid signatures for the GX procedure:
//parm(in:&EventMessageCollection, out:&ExternalEventMessageResponse );
//parm(in:&rawData, out:&ExternalEventMessageResponse );

GxContext gxcontext = new GxContext();
Object[] parametersdata;
parametersdata = new object[] { null };

if (parameters[0].ParameterType == typeof(string))
parametersdata = new object[] { myTriggerItem, null };

else
{
//Initialization

Type eventMessagesType = parameters[0].ParameterType; //SdtEventMessages
GxUserType eventMessages = (GxUserType)Activator.CreateInstance(eventMessagesType, new object[] { gxcontext }); // instance of SdtEventMessages

IList eventMessage = (IList)ClassLoader.GetPropValue(eventMessages, "gxTpr_Eventmessage");//instance of GXBaseCollection<SdtEventMessage>
Type eventMessageItemType = eventMessage.GetType().GetGenericArguments()[0];//SdtEventMessage

GxUserType eventMessageItem = (GxUserType)Activator.CreateInstance(eventMessageItemType, new object[] { gxcontext }); // instance of SdtEventMessage

IList eventMessageProperties = (IList)ClassLoader.GetPropValue(eventMessageItem, "gxTpr_Eventmessageproperties");//instance of GXBaseCollection<GeneXus.Programs.genexusserverlessapi.SdtEventMessageProperty>
Type eventMessPropsItemType = eventMessageProperties.GetType().GetGenericArguments()[0];//SdtEventMessageProperty

if (context.BindingContext.BindingData.TryGetValue("Uri", out object urivalue))
{
GxUserType eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, "Uri", urivalue.ToString(), gxcontext);
eventMessageProperties.Add(eventMessageProperty);
}

if (context.BindingContext.BindingData.TryGetValue("name", out object namevalue))
{
GxUserType eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, "name", namevalue.ToString(), gxcontext);
eventMessageProperties.Add(eventMessageProperty);
}

if (context.BindingContext.BindingData.TryGetValue("Metadata", out object metadatavalue))
{
GxUserType eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, "Metadata", namevalue.ToString(), gxcontext);
eventMessageProperties.Add(eventMessageProperty);
}

if (context.BindingContext.BindingData.TryGetValue("Properties", out object propsvalue))
{
JToken jsonToken = JToken.Parse(propsvalue.ToString());
foreach (JProperty property in jsonToken)
{
string propertyName = property.Name;
string propertyValue = property.Value.ToString();

GxUserType eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, propertyName, propertyValue, gxcontext);
eventMessageProperties.Add(eventMessageProperty);

}
}

//Event

ClassLoader.SetPropValue(eventMessageItem, "gxTpr_Eventmessageid", messageId.ToString());
ClassLoader.SetPropValue(eventMessageItem, "gxTpr_Eventmessagesourcetype", EventSourceType.Blob);
ClassLoader.SetPropValue(eventMessageItem, "gxTpr_Eventmessagedata", myTriggerItem);
ClassLoader.SetPropValue(eventMessageItem, "gxTpr_Eventmessagedate", DateTime.UtcNow);
ClassLoader.SetPropValue(eventMessageItem, "gxTpr_Eventmessageversion", string.Empty);
ClassLoader.SetPropValue(eventMessageItem, "gxTpr_Eventmessageproperties", eventMessageProperties);

//List of Events
eventMessage.Add(eventMessageItem);
parametersdata = new object[] { eventMessages, null };
}
try
{
method.Invoke(objgxproc, parametersdata);
GxUserType EventMessageResponse = parametersdata[1] as GxUserType;//SdtEventMessageResponse
bool result = (bool)ClassLoader.GetPropValue(EventMessageResponse, "gxTpr_Handlefailure");

//Error handling

if (result == true) //Must retry
{
exMessage = string.Format("{0} {1}", FunctionExceptionType.AppError, ClassLoader.GetPropValue(EventMessageResponse, "gxTpr_Errormessage"));
throw new Exception(exMessage);
}
else
{
log.LogInformation("(GX function handler) Function finished execution.");
}
}
catch (Exception)
{
log.LogError("{0} Error invoking the GX procedure for Message Id {1}.", FunctionExceptionType.SysRuntimeError, messageId);
throw; //Throw the exception so the runtime can Retry the operation.
}
}
}
else
{
exMessage = string.Format("{0} GeneXus procedure could not be executed for Message Id {1}.", FunctionExceptionType.SysRuntimeError, messageId);
throw new Exception(exMessage);
}
}
catch (Exception)
{
log.LogError("{0} Error processing Message Id {1}.", FunctionExceptionType.SysRuntimeError, messageId);
throw; //Throw the exception so the runtime can Retry the operation.
}
}
else
{
exMessage = string.Format("{0} GeneXus procedure could not be executed while processing Message Id {1}. Reason: procedure not specified in configuration file.", FunctionExceptionType.SysRuntimeError, messageId);
throw new Exception(exMessage);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ private void ProcessEvent(FunctionContext context, ILogger log, IReadOnlyList<Di
if (key == "id")
idValue = strValue;

eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType,key, strValue, gxcontext);
eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType,key, strValue, gxcontext);
eventMessageProperties.Add(eventMessageProperty);
}
}
Expand Down Expand Up @@ -243,12 +243,5 @@ private JsonObject ConvertToJsonObject(Dictionary<string,object> jsondoc)
}
return keyValuePairs;
}
private GxUserType CreateEventMessageProperty(Type eventMessPropsItemType, string propertyId, object propertyValue, GxContext gxContext)
{
GxUserType eventMessageProperty = (GxUserType)Activator.CreateInstance(eventMessPropsItemType, new object[] { gxContext }); // instance of SdtEventMessageProperty
ClassLoader.SetPropValue(eventMessageProperty, "gxTpr_Propertyid", propertyId);
ClassLoader.SetPropValue(eventMessageProperty, "gxTpr_Propertyvalue", propertyValue);
return eventMessageProperty;
}
}
}
22 changes: 22 additions & 0 deletions dotnet/src/extensions/Azure/Handlers/Dummies/BlobTriggerDummy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;

namespace GeneXus.Deploy.AzureFunctions.Handlers.Dummies
{
public static class BlobTriggerDummy
{
[Function("BlobTrigger1")]
public static void Run(
[BlobTrigger("mycontainer/{name}", Connection = "AzureWebJobsStorage")] Stream myTriggerItem,
FunctionContext context)
{

}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<PackageReference Include="log4net" Version="2.0.15" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.13" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.ServiceBus" Version="4.2.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage" Version="5.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Storage" Version="5.0.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Timer" Version="4.0.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.9.0" OutputItemType="Analyzer" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.5.2" />
Expand Down
16 changes: 16 additions & 0 deletions dotnet/src/extensions/Azure/Handlers/Helpers/EventSourceType.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
using GeneXus.Application;
using GeneXus.Metadata;
using GeneXus.Utils;
using System;

namespace GeneXus.Deploy.AzureFunctions.Handlers.Helpers
{
public class EventSourceType
Expand All @@ -6,5 +11,16 @@ public class EventSourceType
public const string ServiceBusMessage = "ServiceBusMessage";
public const string Timer = "Timer";
public const string CosmosDB = "CosmosDB";
public const string Blob = "Blob";
}
public class EventMessagePropertyMapping
{
public static GxUserType CreateEventMessageProperty(Type eventMessPropsItemType, string propertyId, object propertyValue, GxContext gxContext)
{
GxUserType eventMessageProperty = (GxUserType)Activator.CreateInstance(eventMessPropsItemType, new object[] { gxContext }); // instance of SdtEventMessageProperty
ClassLoader.SetPropValue(eventMessageProperty, "gxTpr_Propertyid", propertyId);
ClassLoader.SetPropValue(eventMessageProperty, "gxTpr_Propertyvalue", propertyValue);
return eventMessageProperty;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,13 @@ private void ProcessMessage(FunctionContext context, ILogger log, QueueMessage q

foreach (var messageProp in queueMessage.MessageProperties)
{
eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType, messageProp.key, messageProp.value, gxcontext);
eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, messageProp.key, messageProp.value, gxcontext);
eventMessageProperties.Add(eventMessageProperty);
}

//Body

eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType, "Body", queueMessage.Body, gxcontext);
eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, "Body", queueMessage.Body, gxcontext);
eventMessageProperties.Add(eventMessageProperty);

//Event
Expand Down Expand Up @@ -220,14 +220,6 @@ private void ProcessMessage(FunctionContext context, ILogger log, QueueMessage q
throw new Exception(exMessage);
}
}

private GxUserType CreateEventMessageProperty(Type eventMessPropsItemType, string propertyId, object propertyValue, GxContext gxContext)
{
GxUserType eventMessageProperty = (GxUserType)Activator.CreateInstance(eventMessPropsItemType, new object[] { gxContext }); // instance of SdtEventMessageProperty
ClassLoader.SetPropValue(eventMessageProperty, "gxTpr_Propertyid", propertyId);
ClassLoader.SetPropValue(eventMessageProperty, "gxTpr_Propertyvalue", propertyValue);
return eventMessageProperty;
}

[DataContract]
internal class QueueMessage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,6 @@ public void Run(string myQueueItem, FunctionContext context)
throw;
}
}
private GxUserType CreateEventMessageProperty(Type eventMessPropsItemType, string propertyId, object propertyValue, GxContext gxContext)
{
GxUserType eventMessageProperty = (GxUserType)Activator.CreateInstance(eventMessPropsItemType, new object[] { gxContext }); // instance of SdtEventMessageProperty
ClassLoader.SetPropValue(eventMessageProperty, "gxTpr_Propertyid", propertyId);
ClassLoader.SetPropValue(eventMessageProperty, "gxTpr_Propertyvalue", propertyValue);
return eventMessageProperty;
}
private Message SetupMessage(FunctionContext context, string item)
{
Message message = new Message();
Expand Down Expand Up @@ -172,22 +165,22 @@ private void ProcessMessage(FunctionContext context, ILogger log, Message messag
{
if ((messageProp.key != "UserProperties") & (messageProp.key != "SystemProperties"))
{
eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType, messageProp.key, Convert.ToString(messageProp.value), gxcontext);
eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, messageProp.key, Convert.ToString(messageProp.value), gxcontext);
eventMessageProperties.Add(eventMessageProperty);
}
}

//Body

eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType, "Body", message.Body, gxcontext);
eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, "Body", message.Body, gxcontext);
eventMessageProperties.Add(eventMessageProperty);

//user Properties
if (message.UserProperties.Count > 0)
{
foreach (string key in message.UserProperties.Keys)
{
eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType, key, JSONHelper.Serialize(message.UserProperties[key]), gxcontext);
eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, key, JSONHelper.Serialize(message.UserProperties[key]), gxcontext);
eventMessageProperties.Add(eventMessageProperty);
}
}
Expand All @@ -201,7 +194,7 @@ private void ProcessMessage(FunctionContext context, ILogger log, Message messag
foreach (var prop in sysProps)
if (prop.GetIndexParameters().Length == 0)
{
eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType, prop.Name, Convert.ToString(prop.GetValue(message.SystemProperties)), gxcontext);
eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, prop.Name, Convert.ToString(prop.GetValue(message.SystemProperties)), gxcontext);
eventMessageProperties.Add(eventMessageProperty);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,16 @@ private void ProcessMessage(FunctionContext context, ILogger log, MyInfo TimerIn

//Payload

GxUserType eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType, "ScheduleStatusNext", TimerInfo.ScheduleStatus.Next.ToUniversalTime().ToString(), gxcontext);
GxUserType eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, "ScheduleStatusNext", TimerInfo.ScheduleStatus.Next.ToUniversalTime().ToString(), gxcontext);
eventMessageProperties.Add(eventMessageProperty);

eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType, "ScheduleStatusLast", TimerInfo.ScheduleStatus.Last.ToUniversalTime().ToString(), gxcontext);
eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, "ScheduleStatusLast", TimerInfo.ScheduleStatus.Last.ToUniversalTime().ToString(), gxcontext);
eventMessageProperties.Add(eventMessageProperty);

eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType, "ScheduleStatusLastUpdated", TimerInfo.ScheduleStatus.LastUpdated.ToUniversalTime().ToString(), gxcontext);
eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, "ScheduleStatusLastUpdated", TimerInfo.ScheduleStatus.LastUpdated.ToUniversalTime().ToString(), gxcontext);
eventMessageProperties.Add(eventMessageProperty);

eventMessageProperty = CreateEventMessageProperty(eventMessPropsItemType, "IsPastDue", TimerInfo.IsPastDue.ToString(), gxcontext);
eventMessageProperty = EventMessagePropertyMapping.CreateEventMessageProperty(eventMessPropsItemType, "IsPastDue", TimerInfo.IsPastDue.ToString(), gxcontext);
eventMessageProperties.Add(eventMessageProperty);

//Event
Expand Down Expand Up @@ -175,13 +175,6 @@ private void ProcessMessage(FunctionContext context, ILogger log, MyInfo TimerIn
throw new Exception(exMessage);
}
}
private GxUserType CreateEventMessageProperty(Type eventMessPropsItemType, string propertyId, object propertyValue, GxContext gxContext)
{
GxUserType eventMessageProperty = (GxUserType)Activator.CreateInstance(eventMessPropsItemType, new object[] { gxContext }); // instance of SdtEventMessageProperty
ClassLoader.SetPropValue(eventMessageProperty, "gxTpr_Propertyid", propertyId);
ClassLoader.SetPropValue(eventMessageProperty, "gxTpr_Propertyvalue", propertyValue);
return eventMessageProperty;
}
}
public class MyInfo
{
Expand Down