diff --git a/dotnet/src/dotnetcore/GxClasses.Web/GxClasses.Web.csproj b/dotnet/src/dotnetcore/GxClasses.Web/GxClasses.Web.csproj index e8479db8c..ff9c157b1 100644 --- a/dotnet/src/dotnetcore/GxClasses.Web/GxClasses.Web.csproj +++ b/dotnet/src/dotnetcore/GxClasses.Web/GxClasses.Web.csproj @@ -11,6 +11,7 @@ + diff --git a/dotnet/src/dotnetframework/GxClasses/Helpers/GxDynamicCall.cs b/dotnet/src/dotnetframework/GxClasses/Helpers/GxDynamicCall.cs new file mode 100644 index 000000000..d6af1f832 --- /dev/null +++ b/dotnet/src/dotnetframework/GxClasses/Helpers/GxDynamicCall.cs @@ -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 parameters, out IList errors) + { + Create(null, out errors); + if (errors.Count == 0) + { + GxDynCallMethodConf methodConf = new GxDynCallMethodConf(); + Execute(ref parameters, methodConf, out errors); + } + } + + public void Create( IList constructParms, out IList errors) + { + errors = new GXBaseCollection(); + 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) errors); + } + } + catch (Exception e) + { + GXUtil.ErrorToMessages("VerifyProperties Error", e.Message, (GXBaseCollection)errors); + } + } + public object Execute(ref IList parameters, GxDynCallMethodConf methodconfiguration , out IList errors) + { + object result; + errors = new GXBaseCollection(); + IList outParms= new List(); + + 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)errors); + } + } + else + { + GXUtil.ErrorToMessages("NullInstance Error", "You must invoke create method before executing a non-static one", (GXBaseCollection)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; + } + + } +} + diff --git a/dotnet/src/dotnetframework/GxClasses/Services/ReflectionHelper.cs b/dotnet/src/dotnetframework/GxClasses/Services/ReflectionHelper.cs index 8cd27f4b5..85e02c6b7 100644 --- a/dotnet/src/dotnetframework/GxClasses/Services/ReflectionHelper.cs +++ b/dotnet/src/dotnetframework/GxClasses/Services/ReflectionHelper.cs @@ -49,12 +49,36 @@ public static Dictionary 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 CallMethod(object instanceOrType, String methodName, IList 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 CallMethodImpl(object instance, MethodInfo methodInfo, IDictionary parameters, IGxContext context) { object[] parametersForInvocation = ProcessParametersForInvoke(methodInfo, parameters, context); object returnParm = methodInfo.Invoke(instance, parametersForInvocation); return ProcessParametersAfterInvoke(methodInfo, parametersForInvocation, returnParm); } + static IList CallMethodImpl(object instance, MethodInfo methodInfo, IList parameters, IGxContext context) + { + object[] parametersForInvocation = ProcessParametersForInvoke(methodInfo, parameters, context); + object returnParm = methodInfo.Invoke(instance, parametersForInvocation); + IList parametersAfterInvoke = parametersForInvocation.ToList(); + parametersAfterInvoke.Add(returnParm); + return parametersAfterInvoke; + } public static bool MethodHasInputParameters(object instance, String methodName) { MethodInfo methodInfo = instance.GetType().GetMethod(methodName); @@ -107,16 +131,16 @@ public static Dictionary 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 { @@ -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 @@ -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<>))) @@ -191,9 +215,9 @@ internal static object ConvertStringToNewType(object value, Type newType, IGxCon public static Dictionary ParametersFormat(object instance, string methodName) { MethodInfo methodInfo = instance.GetType().GetMethod(methodName); - + Dictionary formatList = new Dictionary(); - var methodParameters = methodInfo.GetParameters(); + var methodParameters = methodInfo.GetParameters(); foreach (var methodParameter in methodParameters) { var gxParameterName = GxParameterName(methodParameter.Name); @@ -210,6 +234,7 @@ public static Dictionary ParametersFormat(object instance, strin return formatList; } + private static Dictionary ProcessParametersAfterInvoke(MethodInfo methodInfo, object[] parametersForInvocation, object returnParm) { Dictionary outputParameters = new Dictionary(); @@ -230,7 +255,7 @@ private static Dictionary ProcessParametersAfterInvoke(MethodInf } - internal static object[] ProcessParametersForInvoke(MethodInfo methodInfo, IDictionary parameters, IGxContext context=null) + internal static object[] ProcessParametersForInvoke(MethodInfo methodInfo, IDictionary parameters, IGxContext context = null) { var methodParameters = methodInfo.GetParameters(); object[] parametersForInvocation = new object[methodParameters.Length]; @@ -238,14 +263,14 @@ internal static object[] ProcessParametersForInvoke(MethodInfo methodInfo, IDict 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)) { @@ -266,6 +291,41 @@ internal static object[] ProcessParametersForInvoke(MethodInfo methodInfo, IDict } return parametersForInvocation; } + + internal static object[] ProcessParametersForInvoke(MethodInfo methodInfo, IList 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) {