How to add an assembly in other assembly? - c#

I have a dll called Test.dll in which I have a class called ABC which has a method FindTYpe.
Now, I have a project called TestB and I have added the reference of Test.dll in TestB.
Now, if I am trying to find a type XYZ in TestB, from Test.ABC.FindTYpe(), it's throwing an exception, TypeNotLaoded Exception.
Please have a look at the problem and tell me how can I resolve it.

You'll need to post your code for FindType(). My guess is that you're doing something like;
System.Reflection.Assembly.GetExecutingAssembly().GetTypes()
to find a list of types to search through, and the type in TestB.dll isn't in Test.dll, so the item isn't found.
You might want to try something like this instead;
/// <summary>
/// Returns all types in the current AppDomain
/// </summary>
public static IEnumerable<Type> LoadedType()
{
return AppDomain
.CurrentDomain
.GetAssemblies()
.SelectMany(assembly => assembly.GetTypes());
}
which should give you the all types loaded into the current application domain -- which, unless you're doing anything odd with appdomains, will be the list of all types loaded into your program.
None of the code has been tested, but it should help you find the classes and methods you'll need to use.

Mos probably the type XYZ that you are trying to find is not loaded or not present in the paths your app looks for assemblies. The Test.dll and ABC should be present it you added the reference in your project to Test.dll.

What does the code look like in FindType?
Assuming you are creating the type from the type name (a string), then you must be sure to supply the "assembly qualified" type name, not just the "local" type name.
e.g. to retrieve the type you are about to create:
Type testB = Type.GetType("TestB.XYZ, TestB");
rather than
Type testB = Type.GetType("TestB");
Can you give some more specifics, like some code snippets?

Related

Type.GetInterface returning null

My issue is that I am getting different results to our older DLLs from history, when very little has changed and I don't under how the changes are relevant to the error shown.
This is part of a method, in our SecurityPluginServices.dll module, which essentially added plugins to a list so they can be utilised by the main program.
It gets all the DLLs in a set folder, then for each it runs through the code below.
private void AddPlugin(string FileName, LoggingUtilities.Source source)
{
//Create a new assembly from the plugin file we're adding..
Assembly pluginAssembly = Assembly.LoadFrom(FileName);
try
{
//Next we'll loop through all the Types found in the assembly
foreach (Type pluginType in pluginAssembly.GetTypes())
{
if (pluginType.IsPublic) //Only look at public types
{
if (!pluginType.IsAbstract) //Only look at non-abstract types
{
//Gets a type object of the interface we need the plugins to match
Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
//Make sure the interface we want to use actually exists
if (typeInterface != null)
{
// Do work here
}
typeInterface = null; //Mr. Clean
}
}
}
pluginAssembly = null; //more cleanup
}
catch (ReflectionTypeLoadException ex1)
{
Console.WriteLine(ex1.Message);
}
catch (Exception ex2)
{
Console.WriteLine(ex2.Message);
}
}
The issue I am having is that everytime it gets to Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true); it always returns null.
The plugins I need to load are for NTLM and LDAP and they have changed very little in many versions and only a couple of extra properties and methods have been added, nothing to do with interfaces that the implement.
I've opened up a copy of the newer plugin DLL and one of the older ones in ILDASM and they both seem to contain the same information regarding the SecurityInterface.ISecurityPlugin that the .GetInterface method is seeking.
Newer LdapSecurity
Older LdapSecurity
Suggestion:
Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Change this to a fully-qualified type name, i.e. one that includes the assembly containing your interface type.
(If you're now saying that you've got two different types by the same name, in two different assemblies, and therefore cannot include one definite assembly name, this may well be the likely cause of your issue.)
Explanation:
My other answer led me to a suspicion of what could cause your issue. Generally speaking, typeof(T) would force you to add an assembly reference to your project for the assembly that contains T. Otherwise, compilation will fail. On the other hand, textual mentions of type names such as Type.GetType("T") do not enforce a compile-time assembly reference... but they still have to be resolved to a type instance at run-time. So if you omit the assembly name, you need to keep in mind how .NET will map T to a specific assembly.
Back to your issue. First, let's note that you are not using a fully-qualified type name:
Type typeInterface = pluginType.GetInterface("SecurityInterface.ISecurityPlugin", true);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You specify only the namespace and the type name, but not the assembly containing your interface type. Could it be that the interface type is defined more than once, i.e. in different assemblies, and your mention of that type name is resolved to type in the wrong assembly?
Let's briefly look at the MSDN documentation for Type.GetType(string) method, which describes the string parameter as follows:
"The assembly-qualified name of the type to get. […] If the type is in the currently executing assembly or in Mscorlib.dll, it is sufficient to supply the type name qualified by its namespace."
What if the same applies to the Type.GetInterface(string, bool) method which you're using? And what if your currently executing assembly does contain a type of that name? Then that is the type that pluginType will be checked against... but it might be a different ISecurityPlugin interface type (albeit equal in name) than the one your plug-in class actually implements.
Update: Please see my other answer first, which is likely more relevant.
If you want to check whether pluginType implements the ISecurityPlugin interface, you could instead perform this check:
typeof(SecurityInterface.ISecurityPlugin).IsAssignableFrom(pluginType)
If you don't reference the assembly containing ISecurityPlugin, you can replace the first part by Type.GetType("SecurityInterface.ISecurityPlugin").

Use the "new" keyword to create an object using reflection

I'm completely new to reflection and I'm trying to call a class name from a db record and then load the class and run it but I'm pulling my hair out on where I'm going wrong, its probably something really silly I'm missing.
As an example I have my class in a different project and scripts folder, then call the name of it from the db record.
className = String.Format("Utilities.Scripts.{0}", script.ScriptClass);
Then in my main program I have
// Get a type from the string
Type type = Type.GetType(className);
// Create an instance of that type
Object obj = Activator.CreateInstance(type);
// Retrieve the method you are looking for
MethodInfo methodInfo = type.GetMethod("start");
// Invoke the method on the instance we created above
methodInfo.Invoke(obj, null);
But I am getting the error as when debugging I can see my details passed into the GetType(className) but nothing goes through to the type and as such into the obj where it is erroring.
You need to supply the Assembly Qualified Name of the type (as mentioned here) since the class is in a different project. Also, make sure that the assembly you are trying to load the type from is either in the same folder as the assembly trying to load it, or in the GAC.
For a class defined as below:
namespace Foo.Bar
{
public class Class1
{
}
}
The full class name is Foo.Bar.Class1. The assembly qualified name also specifies the full name of the assembly, as in Foo.Bar.Class1, Foo.Bar, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35. You can find the Assembly Qualified Name of your type with somthing like:
Console.WriteLine(typeof(Foo.Bar.Class1).AssemblyQualifiedName)
The problem is in this line:
Type type = Type.GetType(className);
In that this particular overload of the method will not throw an exception when the type cannot be resolved. Instead use this overload which takes 2 booleans, one of which being throwOnError. Pass true for this parameter and you will get an exception which should help you debug why your type cannnot be resolved from the string you pass in.
I suspect you need a class name and assembly name
Utilities.Scripts.SomeClass, SomeAssemblyName

Dynamically Loading a DLL

I am trying to simply load a dll written in C# at run time and create an instance of a class in that dll.
Assembly a = Assembly.LoadFrom(#"C:\Development\DaDll.dll");
Type type = a.GetType("FileReleaseHandler", true);
TestInterface.INeeedHelp handler = Activator.CreateInstance(type) as TestInterface.INeeedHelp;
No errors are thrown, and if I step through the code I can walk though the FileReleaseHandler Class as it executes the constructor but the value of handler is always null.
What am I missing here? or even is there a better way I should be going about this?
Where is TestInterface.INeedHelp defined? One common problem is if you've got the same interface in multiple assemblies. If both the caller and the dynamically loaded assembly reference the same interface in the same assembly, it should be okay.
One subtlety is that if the assembly is in a different directory to the calling assembly, it may end up loading a different copy of the same assembly, which can be very irritating :(
Try setting the result of Activator.CreateInstance to an object directly, and not casting.
It's possible FileReleaseHandler does not implement TestInterface.INeeedHelp, in which case, this will be set to null via the "as TestInterface.INeeedHelp".
Check the assemblies that are loaded into the application domain. Are there two assemblies with the TestInterface.INeedHelp interface in it? My suspicion is that the LoadFrom is binding this created object to a different TestInterface.INeedHelp than the one to which you are trying to cast. Try doing a normal downcast rather than a so-called "safe" cast and see what error you get.
The problem is that the LoadFrom method loads the dll into "LoadFrom" context which is different from the default context. The rules of type resolution for the types in this context differ from the ones you are used to. It is possible that the INeedHelp interface as defined in your main module from the standpoint of the runtime is different from the interface with the same name as coming from the LoadFrom context. This will cause the cast (as TestINterface) return null.
To see if this is the case try to assign the result to an object.
I would do something like :
Assembly a = Assembly.LoadFrom(#"C:\Development\DaDll.dll");
object obj = a.CreateInstance("fullClassName",other params) as IMyType
//(if it implements an interface you referenced)

Get Instance from StructureMap by Type Name

Is there any way to request an instance from the StructureMap ObjectFactory by the string name of the type? For example, it would be nice to do something like this:
var thing = ObjectFactory.GetInstance("Thing");
The use case here is a messaging scenario in which the message is very generic and contains only the name of a task. A handler receives the message, gets the task name from the message and retrieves the type name of the associated task runner from a configuration database. StructureMap scans all the assemblies in a directory and one of them will (presumably) contain the type returned from the config database which then needs to be instantiated.
The other possibility is to grab a Type instance by doing the following:
var type = Type.GetType("Thing");
But the problem there is the assembly may or may/not be loaded in the AppDomain so that reflection call isn't always possible.
I recently had the exact same issue of GetType not returning a type event though StructureMap had correctly loaded it from a scanned assembly.
My problem was I was not using the assembly qualified name and I presume without this the GetType method simply looks in the current assembly.
Anyway adding the full name sorted my problem.
Hope this helps.
Ian

Mono.Cecil - How to get custom attributes

I am trying to use Cecil to inspect the attributes associated with a given method. It seems to find it, but I cannot get its name using the following code:
AssemblyDefinition assembly = AssemblyFactory.GetAssembly(pathBin);
assembly.MainModule.Types[0].Methods[1].CustomAttributes[0].ToString()
I know this must be the attribute I've set my function to, because when I remove it from the dll, the second line of code will turn out to null. What I'd like to do is be able to get the attribute's name. Currently the second line of code will return just a "Mono.Cecil.CustomAttribute". I'd guess there should be a way of getting an attribute's name(class type) name, right?
Thanks!
I had trouble with this when writing MoMA as well. Here is the code it uses:
AssemblyDefinition assembly = AssemblyFactory.GetAssembly(pathBin);
assembly.MainModule.Types[0].Methods[1].CustomAttributes[0].Constructor.DeclaringType.ToString()
A CustomAttribute is an instance of a System.Attribute derived Type, so ToString() will do whatever the author decided.
If you want to know about attribute types you should ask for their type:
typeInfo.GetCustomAttributes(false)[0].GetType().ToString() ;
I haven't seen this property CustomAttributes you are using, so I rather used the method MemberInfo.GetCustomAttributes(bool) which I always use.

Categories

Resources