WPF call a method that takes parameters from another dll - c#

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.

Related

Attach Generic method event handler with unknow type

I need to attach this handler to a RadListView Column creation, by adding a DataSource to the control.
public void GenericColumnCreatingHandler<T>(object sender, ListViewColumnCreatingEventArgs e)
{
e.Column.Visible = BaseEntity<int>.MemberVisibility<T>
(e.Column.FieldName, TelerikPropertyVisibilityAttribute.VisibilityTypeEnum.BaseDetails);
e.Column.HeaderText = CaricaTestoLocale(e.Column.HeaderText, "Col_" + e.Column.HeaderText);
e.Column.BestFit();
e.Column.AutoSizeMode = ListViewBestFitColumnMode.AllCells;
}
My problem is that I need to perform the handler attach from this other generic method:
private void PopulateRecord(TipoTabellaBase tipo)
{
Type generic = typeof(CommonTableService<>);
Type[] typeArgs = { tipo.Tipo };
var constructed = generic.MakeGenericType(typeArgs);
var instance = Activator.CreateInstance(constructed);
if (instance == null)
return;
MethodInfo getEntities = constructed.GetMethod("GetEntitiesWithNoParameters");
//getEntities = getEntities.MakeGenericMethod(typeArgs);
var result = (IEnumerable<BaseEntity<int>>)getEntities.Invoke(instance, null);
lvRecords.ColumnCreating += base.GenericColumnCreatingHandler<BaseEntity<int>>;
lvRecords.DataSource = result;
BestFit(lvRecords);
generic = null;
typeArgs = null;
constructed = null;
getEntities = null;
instance = null;
}
The problematic row is this one:
lvRecords.ColumnCreating += base.GenericColumnCreatingHandler<BaseEntity<int>>
because BaseEntity is EF base type for all Entities, but this is not enought for the BaseEntity.MemberVisibility method; this method need to know the exact entity type to set the visible properties (and, of course, grid column) based on specific custom attribute on that.
Question is: how I can call base.GenericColumnCreatingHandler where T is TipoTabellaBase tipo.Tipo (type) without knowing type at design time?
Any help would be very appreciated!
Thanks is advance.
Daniel
Please note that this solution is untested.
You will have to instantiate the strongly-typed version of base.GenericColumnCreatingHandler<T> at runtime.
From your code, I figure you already know how to obtain a MethodInfo instance for a given method. You will need to get the MethodInfo for base.GenericColumnCreatingHandler<T> (let's call it genericMethodInfo).
Then, you can create a strongly-typed version of that method with MakeGenericMethod:
MethodInfo typedMethodInfo = genericMethodInfo.MakeGenericMethod(new[] {
typeof(BaseEntity<int>)
});
Once that is done, you need to invoke CreateDelegate to obtain something that you can assign to the ColumnCreating event, as described here or here:
lvRecords.ColumnCreating +=
(ListViewColumnCreatingEventHandler)typedMethodInfo.CreateDelegate(
typeof(ListViewColumnCreatingEventHandler), this);
EDIT: Replaced base with this in the last code sample. In case an inherited method is specifically required, this has to be taken care of while retrieving genericMethodInfo.

Convert Reflection.Emit to Roslyn

I need to convert an existing code that uses Reflection.Emit to Roslyn.
The code I have currently is basically this:
var assemblyName = new AssemblyName("AssemblyName");
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
var builder = assemblyBuilder.DefineDynamicModule("test", "test.dll");
var type = builder.DefineType("Entry", TypeAttributes.Public, typeof(object), null);
var method = type.DefineMethod("###Start_v1.4.3.0", MethodAttributes.Public | MethodAttributes.HideBySig);
method.SetReturnType(typeof(void));
var generator = method.GetILGenerator();
generator.Emit(OpCodes.Nop);
generator.Emit(OpCodes.Ret);
type.CreateType();
assemblyBuilder.Save(#"test.dll");
As you can see, there is a class named Entry with a method called ###Start_v1.4.3.0.
We're using this for more than 7 years now but evereytime we need to change anything, it's a pain because we need to use those Emits and it's not trivial.
It would be great if we could just have Roslyn to compile the code:
public class Entry
{
public void ###Start_v1.4.3.0()
{
}
}
But it doesn't work due to the method name being invalid.
The compiled dll is used by a third party component and it looks for this class and method name to execute. We tried to reach the developers to have a new version but no luck.
I think Roslyn won't compile this at all, but I believe there might be a way to rename the method name later from let's say just Start() to ###Start_v1.4.3.0()... I just don't know how to do this.
Any help will be very welcome.
If the only problem is the illegal method name, you can easily resolve that issue.
Compile the dll with a legal name, and then you have several ways to change the method name.
With mono.cecil its pretty simple.
public void ChangeMethodName()
{
//Before changing the method name
var assem = Assembly.LoadFile(#"C:\temp\ClassLibrary1.dll");
Console.WriteLine(
assem.GetType("ClassLibrary1.Class1").
GetMethod("Start", BindingFlags.Static | BindingFlags.Public).
Invoke(null, null));
// Change the name
var module = ModuleDefinition.ReadModule(#"C:\temp\ClassLibrary1.dll");
TypeDefinition myType =
module.Types.First(type => type.Name == "Class1");
var method = myType.Methods.First(m => m.Name == "Start");
method.Name = "###Start_v1.4.3.0";
module.Write(#"C:\temp\ClassLibrary1_new.dll");
//After changing the method name
assem = Assembly.LoadFile(#"C:\temp\ClassLibrary1_new.dll");
Console.WriteLine(
assem.GetType("ClassLibrary1.Class1").
GetMethod("###Start_v1.4.3.0",
BindingFlags.Static|BindingFlags.Public).
Invoke(null, null));
}
public class Class1
{
public static string Start()
{
return $"my name is {MethodBase.GetCurrentMethod().Name}";
}
}

Ambiguous match found when accessing dll

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.

Getting class variable value using reflection

In my business logic I have created classes for database operations like insert, update etc.
For this purpose I have created a class CDatabase which sets has some methods define in it like openconnection and closeconnection transation etc.
Now my logic class inherit that class
CAnswerLogic : CDatabase
{
OpenConnection();
BeginTrans();
Command.CommandText = "PKG_ANSWER.PROC_ADD_ANSWERS";
}
Can I get the value of Command.CommandText using reflection. Command is a property inside CDatabse class.
I have written a method to return all the method of a class
private IEnumerable<string> GetAllMethod(string pstrClassName)
{
const BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
var llistMethod = new List<string>();
var assembly = Assembly.LoadFile(Server.MapPath(#"bin/InfoDomeBLL.dll"));
try
{
foreach (Type type in assembly.GetTypes())
{
if (type.IsClass && type.Name == pstrClassName)
{
var method = type.GetMethods(flags);
foreach (var methodInfo in method)
{
llistMethod.Add(methodInfo.Name);
//var mb = methodInfo.GetMethodBody();
//foreach (LocalVariableInfo lvi in mb.LocalVariables)
//{
// Response.Write("Local variable: " + lvi);
//}
}
var basetype= type.BaseType;
}
}
}
catch (Exception)
{
}
return llistMethod;
}
In the web project i have added the reference of the bll project.
Kindly help me out.
If you use type.GetProperties(flags); instead of type.GetMethods(flags); you will find the property you are looking for. Then, do propertyInfo.GetValue( Command, null ); to get the value.

Trying to use Reflection to Invoke Method within same class

I have a WCF service that accepts an object as a parameter that has a URI and Method Name.
What I am trying to do is have a method that will look # the URI, if it contains the words "localhost" it will use reflection and call a method, of the name that is passed in as a parameter, within the the same class, return a value and continue on.
public class Test
{
public GetStatResponse GetStat(GetStatRequest request)
{
GetStatResponse returnValue = new GetStatResponse();
if(Helpers.Contains(request.ServiceURI,"localhost", StringComparison.OrdinalIgnoreCase))
{
MethodInfo mi = this.GetType().GetMethod(request.ServiceMethod /*, BindingFlags.Public | BindingFlags.IgnoreCase*/);
returnValue = (GetStatResponse)mi.Invoke(this,null);
}
The above is the code segment pertaining to this question. I pull the MethodInfo no problem but I am running into issues on the mi.Invoke. The exception that I receive is "Exception has been thrown by the target of an invocation." With an Inner Exception "Object reference not set to an instance of an object". I have tried changing the code to (GetStatResponse)mi.Invoke(new Test(), null), with no luck. Test being the class.
I'm open to other suggestions as to how to resolve this, I just thought reflection might be the easiest.
The Method that I am calling with my testing is defined as
public GetStatResponse TestMethod()
{
GetStatResponse returnValue = new GetStatResponse();
Stat stat = new Stat();
Stat.Label = "This is my label";
Stat.ToolTip = "This is my tooltip";
Stat.Value = "this is my value";
returnValue.Stat = stat;
return returnValue;
}
Because you are not specifying BindingFlags in your GetMethod() call, you are only going to be returned methods matching the name containing request.ServiceMethod that are PUBLIC.
Check whether the method you are trying to invoke is public, otherwise MethodInfo will return null.
If it is not public, either make the method public or include the BindingFlags.NonPublic flag.
Also, you should always make sure that mi != null before calling mi.Invoke
Before calling the method you might want to make sure that the MethodInfo you are pulling through reflection is not null:
MethodInfo mi = this.GetType().GetMethod(
request.ServiceMethod,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase
);
// Make sure that the method exists before trying to call it
if (mi != null)
{
returnValue = (GetStatResponse)mi.Invoke(this, null);
}
After your update it seems that the exception is thrown inside the method you are calling:
GetStatResponse returnValue = new GetStatResponse();
// Don't forget to initialize returnValue.Stat before using it:
returnValue.Stat = new WhateverTheTypeIs();
returnValue.Stat.Label = "This is my label";

Categories