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
1 change: 1 addition & 0 deletions dotnet/src/dotnetcore/GxClasses.Web/GxClasses.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

<ItemGroup>
<Compile Include="..\..\dotnetframework\GxClasses\Domain\GXGeolocation.cs" Link="Domain\GXGeolocation.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Helpers\GxDynamicCall.cs" Link="Helpers\GxDynamicCall.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Middleware\GXHttp.cs" Link="Middleware\GXHttp.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Middleware\GXHttpServices.cs" Link="Middleware\GXHttpServices.cs" />
<Compile Include="..\..\dotnetframework\GxClasses\Domain\GXRuntime.cs" Link="Domain\GXRuntime.cs" />
Expand Down
193 changes: 193 additions & 0 deletions dotnet/src/dotnetframework/GxClasses/Helpers/GxDynamicCall.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
using GeneXus.Application;
using GeneXus.Metadata;
using GeneXus.Utils;
using System;
using System.Collections.Generic;
using System.Reflection;

namespace GeneXus.DynamicCall
{
public class GxDynamicCall
{
private const string defaultMethod = "execute";
private Assembly _assembly;
private GxDynCallProperties _properties;
private object _object;
public string ObjectName { get; set; }
public GxDynCallProperties Properties
{
get => _properties;
set
{
_properties = Properties;
}
}

public GxDynamicCall()
{
_assembly= null;
_properties = new GxDynCallProperties();
_object = null;
}

private void VerifyDefaultProperties() {
_properties.NameSpace = string.IsNullOrEmpty(_properties.NameSpace) ? "GeneXus.Programs" : _properties.NameSpace;

if (_assembly is null)
{
if (string.IsNullOrEmpty(_properties.AssemblyName))
{
_assembly = Assembly.GetCallingAssembly();
}
else
{
try
{
_assembly = Assembly.LoadFrom(_properties.AssemblyName);
}
catch
{
throw;
}
}
}
}

public void Execute(ref IList<object> parameters, out IList<SdtMessages_Message> errors)
{
Create(null, out errors);
if (errors.Count == 0)
{
GxDynCallMethodConf methodConf = new GxDynCallMethodConf();
Execute(ref parameters, methodConf, out errors);
}
}

public void Create( IList<object> constructParms, out IList<SdtMessages_Message> errors)
{
errors = new GXBaseCollection<SdtMessages_Message>();
string objectNameToInvoke;
try
{
VerifyDefaultProperties();
if (constructParms is null)
{
objectNameToInvoke = ObjectName;
}
else
{
objectNameToInvoke = _properties.ExternalName;
}
try
{
Type objType = ClassLoader.FindType(objectNameToInvoke, _properties.NameSpace, objectNameToInvoke.ToLower().Trim(), _assembly);
object[] constructorParameters;
if (constructParms != null && constructParms.Count > 0)
{
constructorParameters = new object[constructParms.Count];
constructParms.CopyTo(constructorParameters, 0);
}
else
{
constructorParameters = new object[] { new GxContext() };
}
_object = Activator.CreateInstance(objType, constructorParameters);
}
catch (Exception e)
{
GXUtil.ErrorToMessages("CreateInstance Error", e.Message, (GXBaseCollection<SdtMessages_Message>) errors);
}
}
catch (Exception e)
{
GXUtil.ErrorToMessages("VerifyProperties Error", e.Message, (GXBaseCollection<SdtMessages_Message>)errors);
}
}
public object Execute(ref IList<object> parameters, GxDynCallMethodConf methodconfiguration , out IList<SdtMessages_Message> errors)
{
object result;
errors = new GXBaseCollection<SdtMessages_Message>();
IList<object> outParms= new List<object>();

string methodName = methodconfiguration.MethodName;
bool isStatic = methodconfiguration.IsStatic;

if (!isStatic)
{
if (_object != null)
{
try
{
outParms = ReflectionHelper.CallMethod(_object, (string.IsNullOrEmpty(methodName) ? defaultMethod : methodName), parameters);
}
catch (Exception e)
{
GXUtil.ErrorToMessages("CallMethod Error", e.Message, (GXBaseCollection<SdtMessages_Message>)errors);
}
}
else
{
GXUtil.ErrorToMessages("NullInstance Error", "You must invoke create method before executing a non-static one", (GXBaseCollection<SdtMessages_Message>)errors);
}
}
else
{
VerifyDefaultProperties();
Type objType = ClassLoader.FindType(_properties.ExternalName, _properties.NameSpace, _properties.ExternalName.ToLower().Trim(), _assembly);
outParms = ReflectionHelper.CallMethod(objType, (string.IsNullOrEmpty(methodName) ? defaultMethod : methodName), parameters, isStatic);
}
if (outParms.Count > parameters.Count)
{
result = outParms[parameters.Count];
outParms.RemoveAt(parameters.Count);

}
else
{
result = null;
}
parameters = outParms;
return result;
}

}
public class GxDynCallMethodConf
{
public bool IsStatic
{
get; set;
}
public string MethodName
{
get; set;
}

public GxDynCallMethodConf()
{
IsStatic = false;
MethodName = "execute";
}

}

public class GxDynCallProperties
{
public string ExternalName
{
get;
set;
}
public string AssemblyName
{
get;
set;
}
public string NameSpace
{
get;
set;
}

}
}

82 changes: 71 additions & 11 deletions dotnet/src/dotnetframework/GxClasses/Services/ReflectionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,36 @@ public static Dictionary<string, object> CallMethod(object instance, String meth
MethodInfo methodInfo = instance.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
return CallMethodImpl(instance, methodInfo, parameters, context);
}
public static IList<object> CallMethod(object instanceOrType, String methodName, IList<object> parameters, bool isStatic = false, IGxContext context = null)
{
MethodInfo methodInfo;
object instance = null;
if (isStatic)
{
methodInfo = ((Type)instanceOrType).GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase);
}
else
{

methodInfo = instanceOrType.GetType().GetMethod(methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
instance = instanceOrType;
}
return CallMethodImpl(instance, methodInfo, parameters, context);
}
static Dictionary<string, object> CallMethodImpl(object instance, MethodInfo methodInfo, IDictionary<string, object> parameters, IGxContext context)
{
object[] parametersForInvocation = ProcessParametersForInvoke(methodInfo, parameters, context);
object returnParm = methodInfo.Invoke(instance, parametersForInvocation);
return ProcessParametersAfterInvoke(methodInfo, parametersForInvocation, returnParm);
}
static IList<object> CallMethodImpl(object instance, MethodInfo methodInfo, IList<object> parameters, IGxContext context)
{
object[] parametersForInvocation = ProcessParametersForInvoke(methodInfo, parameters, context);
object returnParm = methodInfo.Invoke(instance, parametersForInvocation);
IList<object> parametersAfterInvoke = parametersForInvocation.ToList<object>();
parametersAfterInvoke.Add(returnParm);
return parametersAfterInvoke;
}
public static bool MethodHasInputParameters(object instance, String methodName)
{
MethodInfo methodInfo = instance.GetType().GetMethod(methodName);
Expand Down Expand Up @@ -107,16 +131,16 @@ public static Dictionary<string, object> GetWrappedParameter(object instance, St

private static object ConvertSingleJsonItem(object value, Type newType, IGxContext context)
{
if (value!= null && value.GetType() == newType)
if (value != null && value.GetType() == newType)
{
return value;
}
else if (typeof(IGxJSONAble).IsAssignableFrom(newType))
{
object TObject;
if (typeof(GxSilentTrnSdt).IsAssignableFrom(newType) && context!=null)
if (typeof(GxSilentTrnSdt).IsAssignableFrom(newType) && context != null)
{
TObject = Activator.CreateInstance(newType, new object[] { context});
TObject = Activator.CreateInstance(newType, new object[] { context });
}
else
{
Expand Down Expand Up @@ -155,9 +179,9 @@ private static object ConvertSingleJsonItem(object value, Type newType, IGxConte
}
}

private static object ConvertStringToNewNonNullableType(object value, Type newType, IGxContext context=null)
private static object ConvertStringToNewNonNullableType(object value, Type newType, IGxContext context = null)
{

if (newType.IsArray)
{
// For comma separated list
Expand All @@ -174,7 +198,7 @@ private static object ConvertStringToNewNonNullableType(object value, Type newTy
return ConvertSingleJsonItem(value, newType, context);
}

internal static object ConvertStringToNewType(object value, Type newType, IGxContext context=null)
internal static object ConvertStringToNewType(object value, Type newType, IGxContext context = null)
{
// If it's not a nullable type, just pass through the parameters to Convert.ChangeType
if (newType.GetTypeInfo().IsGenericType && newType.GetGenericTypeDefinition() != null && newType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
Expand All @@ -191,9 +215,9 @@ internal static object ConvertStringToNewType(object value, Type newType, IGxCon
public static Dictionary<string, string> ParametersFormat(object instance, string methodName)
{
MethodInfo methodInfo = instance.GetType().GetMethod(methodName);

Dictionary<string, string> formatList = new Dictionary<string, string>();
var methodParameters = methodInfo.GetParameters();
var methodParameters = methodInfo.GetParameters();
foreach (var methodParameter in methodParameters)
{
var gxParameterName = GxParameterName(methodParameter.Name);
Expand All @@ -210,6 +234,7 @@ public static Dictionary<string, string> ParametersFormat(object instance, strin
return formatList;
}


private static Dictionary<string, object> ProcessParametersAfterInvoke(MethodInfo methodInfo, object[] parametersForInvocation, object returnParm)
{
Dictionary<string, object> outputParameters = new Dictionary<string, object>();
Expand All @@ -230,22 +255,22 @@ private static Dictionary<string, object> ProcessParametersAfterInvoke(MethodInf
}


internal static object[] ProcessParametersForInvoke(MethodInfo methodInfo, IDictionary<string, object> parameters, IGxContext context=null)
internal static object[] ProcessParametersForInvoke(MethodInfo methodInfo, IDictionary<string, object> parameters, IGxContext context = null)
{
var methodParameters = methodInfo.GetParameters();
object[] parametersForInvocation = new object[methodParameters.Length];
var idx = 0;
foreach (var methodParameter in methodParameters)
{
object value;

var gxParameterName = GxParameterName(methodParameter.Name).ToLower();
Type parmType = methodParameter.ParameterType;
if (IsByRefParameter(methodParameter))
{
parmType = parmType.GetElementType();
}
if (parameters!=null && parameters.TryGetValue(gxParameterName, out value))
if (parameters != null && parameters.TryGetValue(gxParameterName, out value))
{
if (value == null || JSONHelper.IsJsonNull(value))
{
Expand All @@ -266,6 +291,41 @@ internal static object[] ProcessParametersForInvoke(MethodInfo methodInfo, IDict
}
return parametersForInvocation;
}

internal static object[] ProcessParametersForInvoke(MethodInfo methodInfo, IList<object> parameters, IGxContext context = null)
{
var methodParameters = methodInfo.GetParameters();
object[] parametersForInvocation = new object[methodParameters.Length];
var idx = 0;
foreach (var methodParameter in methodParameters)
{
Type parmType = methodParameter.ParameterType;
if (IsByRefParameter(methodParameter))
{
parmType = parmType.GetElementType();
}
object value = parameters.ElementAt(idx);
if (!value.GetType().Equals(parmType))
{
//To avoid convertion from string type
if (value.GetType() != typeof(string))
{
var convertedValue = ConvertStringToNewType(value, parmType, context);
parametersForInvocation[idx] = convertedValue;
}
else
{
throw new ArgumentException("Type does not match", methodParameter.Name);
}
}
else
{
parametersForInvocation[idx] = value;
}
idx++;
}
return parametersForInvocation;
}
private static Regex attVar = new Regex(@"^AV?\d{1,}", RegexOptions.Compiled);
private static string GxParameterName(string methodParameterName)
{
Expand Down