I am trying load a function in a dll. The dll is loaded but just at the place of invoking the function, I am getting an exception
Ambiguous match found
Here is the code snippet.
Assembly dll = Assembly.LoadFrom(DLLPATH);
if (dll != null)
{
Type Tp = dll.GetType("ABCD.FooClass");
if (Tp != null)
{
Object obj = Activator.CreateInstance(Tp);
if (obj != null)
{
List = (List<String>)obj.GetType().GetMethod("Foo").Invoke(obj, null);
}
else
{
Console.WriteLine("obj is null");
}
}
Console.WriteLine("Type is null");
}
else
Console.WriteLine("Dll is not loaded");
Console.ReadKey();
The method which I am calling (i.e Foo), does not accept any parameters and it is an overloaded method. Is that the place where I am going wrong or is it some other place?
Is there another way to invoke such methods which does not accept any parameters? I tried the solution posted here but it is not working.
If there is an overload and you want to invoke the method with no parameters this is the correct solution:
MethodInfo mi = obj.GetType().GetMethod("Foo", new Type[] { });
The method Type.GetMethod(string methodName) throws the exception you mentioned if there is more than one method with the specified name ( see this MSDN topic ). As Foo is an overload as you say I suspect that there are multiple Foo methods in the same DLL. If you have for example the methods :
IList<string> Foo()
IList<string> Foo(object someParameter)
The method GetMethod(string methodName) can not determine which one you want to have. In this case you should use the method GetMethods and determine the correct method on your own.
Thanks guys for your help.!!
As I told you, the method (i.e FOO) which I was calling, is overloaded. I did not used GetMethod() properly I suppose. Now, I found a solution using GetMethods() function.
I changed my code in following way and it worked.!!
Assembly dll = Assembly.LoadFrom(DLLPATH);
if (dll != null)
{
Type Tp = dll.GetType("ABCD.FooClass");
if (Tp != null)
{
Object obj = Activator.CreateInstance(Tp);
if (obj != null)
{
MethodInfo[] AllMethods = obj.GetType().GetMethods();
MethodInfo Found = AllMethods.FirstOrDefault(mi => mi.Name == "Foo" && mi.GetParameters().Count() == 0);
if (Found != null)
List = (List<String>)Found.Invoke(obj, null);
}
else
Console.WriteLine("obj is null");
}
else
Console.WriteLine("Type is null");
}
else
Console.WriteLine("Dll is not loaded");
Thanks.
My "Ambiguous match found" was I had a textbox in the ASCX(frontend) named Bio, a data element named Bio in a listview <%# DataBinder.Eval(Container.DataItem, "Bio")%> and I named a string variable Bio in .CS.
No build errors or "redlines" but generated an error at runtime. I renamed the variables differently and the error went away. The prgrammer who wrote the code didn't follow naming conventions such as BioTxt. This would of eliminated the error.
Related
I have these lines of code in my .NET 4.7.2 server application:
object saveObject = proxyDef.GetEntityAsNativeObject(entity, DynamicProxyAssembly); // this works
((AxdSalesOrder)saveObject).SalesTable[0].TableDlvAddr = null; // this throws error
I can execute the null-set (2nd line above) in the VS2019 Watch Window and it works perfectly and achieves the desired effect. But when I allow it to run in normal execution (whether in debug mode or not), I get an unhandled exception on that 2nd line:
Unable to cast object of type 'AxdSalesOrder' to type
'Elogix.MSAx.Core.Ax2012ElogixServices.AxdSalesOrder'
There is dynamic stuff going in in relation to that type:
public override object GetEntityAsNativeObject(MSAxEntity entity, Assembly dynamicProxyAssembly) {
var salesOrderObject = Activator.CreateInstance(dynamicProxyAssembly.GetType("AxdSalesOrder"));
var salesOrderTable = DynamicEntityUtil.CreateObjectFromDynamicEntity(entity, dynamicProxyAssembly, "AxdEntity_SalesTable");
Array tableLines =
Array.CreateInstance(
salesOrderObject.GetType().GetProperty("SalesTable").PropertyType.GetElementType(), 1);
tableLines.SetValue(salesOrderTable, 0);
salesOrderObject.SetPropertyValue("SalesTable", tableLines);
return salesOrderObject;
}
public static object CreateObjectFromDynamicEntity(DynamicEntity entity, Assembly dynamicProxyAssembly, string objectTypeName) {
return CreateObjectFromDynamicEntity(entity, dynamicProxyAssembly.GetType(objectTypeName));
}
public static object CreateObjectFromDynamicEntity(DynamicEntity entity, Type type) {
if (type == null) {
throw new ArgumentException("Cannot create object from dynamic entity because \"Type\" is null.");
}
if (type.IsArray) {
return CreateArrayFromDynamicEntity(entity, type);
}
return CreateClassFromDynamicEntity(entity, type);
}
private static object CreateClassFromDynamicEntity(DynamicEntity entity, Type type) {
var nativeObject = Activator.CreateInstance(type);
// this will recursively convert the dynamic values to the native type values on the object.
updateValuesFromDynamicValues(entity);
var modifiedProperties = from property in entity.Properties
//where property.State != DynamicPropertyState.Unchanged
select property;
foreach(var property in modifiedProperties) {
Type valueUnderlyingType = Nullable.GetUnderlyingType(property.Type);
if (valueUnderlyingType != null && valueUnderlyingType.IsEnum) {
PropertyInfo info = nativeObject.GetType().GetProperty(property.Name);
Type targetUnderlyingType = Nullable.GetUnderlyingType(info.PropertyType);
if (property.Value == null) {
info.SetValue(nativeObject, null, null);
} else {
object correctedValue = property.Value.CorrectedEnumValue(targetUnderlyingType);
info.SetValue(nativeObject, correctedValue, null);
}
} else if (property.Type.IsEnum) {
if (property.Value == null) {
continue;
}
object correctedValue = property.Value.CorrectedEnumValue(property.Type);
nativeObject.SetPropertyValue(property.Name, correctedValue);
} else {
try {
nativeObject.SetPropertyValue(property.Name, property.Value);
} catch (Exception ex) {
Log.Write(ex.Message);
}
}
}
return nativeObject;
}
Here is how it looks in the VS2019 Watch Window:
Did this in Immediate Window:
var t = saveObject.GetType();
t.FullName
"AxdSalesOrder"
As you can see, the type's FullName is not very full, not qualified by anything, due to the dynamic nature of the type.
I can try it this way:
(saveObject as AxdSalesOrder).SalesTable[0].TableDlvAddr = null;
Again, that works in Watch, but throws this exception when run in normal execution:
Object reference not set to an instance of an object.
Clearly, VS/Watch knows the type, which is why it can execute without errors inside Watch. But the .net runtime apparently doesn't know the type at run time. How can I get this object cast to work in normal code execution like it does when run in Watch?
The answer here is to take advantage of dynamic typing since the static type is not available here:
dynamic saveObject = proxyDef.GetEntityAsNativeObject(entity, DynamicProxyAssembly);
saveObject.SalesTable[0].TableDlvAddr = null;
Another possible approach would be to use reflection, however since the expression applied to the object involves two properties and an index lookup (.SalesTable[0].TableDlvAddr) this would look much less readable.
The GetEntityAsNativeObject could also benefit from this style, you could consider rewriting it to using dynamic binding rather than reflection.
There is an issue with a new project, that uses the same Microsoft.AspNet.Mvc etc version as another project that does the exact same thing, but doesn't cause a cast issue.
This is an example of the project that doesn't work
And this an example of the expected behaviour from a working service
The route exists, but it is invoking HandleUnknownAction because the required parameters weren't supplied, in this case the required parameter is "counterName"
If feel as if there is a simple explanation to this.
Here is the block of code that the cast is in:
if (Policy == VerbPolicy.AfterChecks)
{
var descriptor = (TaskAsyncActionDescriptor)filterContext.ActionDescriptor;
if (descriptor != null)
{
var parameters = descriptor.MethodInfo.GetParameters();
foreach (var parameter in parameters)
{
var argument = filterContext.ActionParameters[parameter.Name];
if (!EvaluateValidationAttributes(parameter, argument, filterContext))
{
filterContext.Result = new EmptyResult();
return;
}
}
}
}
Any more information required, please ask.
How can I run a method that takes parameters from another dll?
I import a UserControl from another dll as below but I now either need to call a method within that UserContol or have the ability to set a variable that's contained in that class.
Load UserControl
UserControl ucSupportButton =
new Bootstrapper().LoadUserControl("SC.Support.dll", "Button");
Code used in Bootstrapper
public UserControl LoadUserControl(string dllName, string loadType)
{
if (File.Exists(Path.Combine(applicationRoot, dllName)))
{
Assembly asm = Assembly.LoadFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), dllName));
Type[] types = asm.GetTypes();
Type type = types.Where(t => t.Name.Equals(loadType)).FirstOrDefault();
if (type != null)
{
return Activator.CreateInstance(type) as UserControl;
}
}
return null;
}
#HighCore comment seems like the best way to go. Depending on your design, reflection is another option. You can use reflection to get a method or field in that type and then call or set it.
var method = paymentObjectInstance.GetType().GetMethod("MethodNameHere",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
if (method == null)
{
return null;
}
var result = method.Invoke(paymentObjectInstance, null);
Here's a little overview of reflection courtesy of MSDN.
I have a dll which has some classes, these classes have some methods.
And some of those methods has another method call inside it.
How can I check whether a method inside a class has a specific method or not.
I have done some googling on this and I was able to find the classes inside the dll as follows:
public List < string > GetClassFromDlLstring(string dllName)
{
Assembly assemblies = null;
try
{
assemblies = Assembly.LoadFrom(dllName);
}
catch (Exception ex)
{
}
var allTypes = assemblies.GetTypes();
return (from allType in allTypes where allType.IsClass select allType.ToString()).ToList();
}
And similarly a method to find all the methods inside a class as follows:
public List <string> GetAllTMethodClass(string dllName, string className)
{
var assemblies = Assembly.LoadFrom(dllName);
Type type = assemblies.GetType(className);
var temp = new List <string> ();
try
{
MethodInfo[] methods = type.GetMethods();
//MethodInfo[] methods = type.GetMethods(BindingFlags.Instance);
foreach(MethodInfo meth in methods)
{
if (meth.MemberType == MemberTypes.Method && meth.MemberType != MemberTypes.Property)
temp.Add(meth.Name);
}
}
catch (Exception ex)
{
}
return temp;
}
I have a problem now the function above return property name also.
Further I want to go through the function list and check weather the function contain a particular function or not. How can I achieve this?
Edit 1:
I found the similar post whose link is below
- Look if a method is called inside a method using reflection
- Get types used inside a C# method body
You have to look into method's IL. IMO, Mono.Cecil is the best way to do this.
I'm trying to learn reflection in C# and need some help with my code. I've had trouble finding good code examples/guides, so I apologize if my code is poorly done.
Essentially I'm just trying to check out a given assembly dll for a particular method name (path and method name have been redacted).
The problem occurs on the line object lateBoundObj = asm.CreateInstance(typeName); and it reads An object reference is required for the non-static field, method, or property...
I understand this has to do with static vs non-static and creating a new Assembly or something along those lines, but need some help understanding the issue and how to fix it.
Thank you!
public const string assemblyPath = #"<my file path>";
Assembly asm;
static void Main(string[] args)
{
//asm = new Assembly();
Console.Read();
MethodInfo mi;
object result = null;
object[] arguments = new object[] { "ABC123" };
try
{
Assembly assemblyInstance = Assembly.LoadFrom(assemblyPath);
Type[] types = assemblyInstance.GetTypes();
foreach (Type t in types)
{
mi = t.GetMethod("<my method name>");
if (mi != null)
{
string typeName = t.FullName;
object lateBoundObj = asm.CreateInstance(typeName);
result = t.InvokeMember("GetWeb", BindingFlags.Public | BindingFlags.InvokeMethod | BindingFlags.Instance, null, lateBoundObj, arguments);
break;
}
}
//set return for find method
}
catch (Exception ex) { }
}
The problem is that you're never assigning a value to asm, so it's got the default value of null. Perhaps you meant to use assemblyInstance instead?
In fact, I wouldn't use Assembly.CreateInstance or Type.FullName at all there - I'd use:
object lateBoundObj = Activator.CreateInstance(t);
Also note, you should always avoid code like this:
catch (Exception ex) { }
Always at least log the exception. Ideally, don't catch an exception you can't really "handle" at all.
asm variable is never assigned. You should call CreateInstance on assemblyInstance instead.