Demo:
I have two class library in my project. 1) Action 2) Process.
My Action Library contains a interface IProcessor with a method Process.
In my Process Library i have 3 classes
A) ClassA :IProcessor
B) ClassB :IProcessor
C) ClassC :IProcessor
which implements the IProcessor interface.
When i tried to read Process Library's assembly I did not fine any type of ClassA , ClassB, and ClassC
I used
Assembly processorAssembly = Assembly.LoadFile(process.dll);
Type submitOfferType = processorAssembly.GetType("Namespace.ClassA");
to read type from assembly.
how do get derived type from dll?
Change this to:
Type submitOfferType =
processorAssembly.GetType("NamespaceOfProcessLibrary.ClassA");
Assembly.GetType requires the full name of the class.
You should use Assembly.Load or Assembly.LoadFrom instead of Assembly.LoadFile. Try this:
Assembly processorAssembly = Assembly.Load(AssemblyName.GetAssemblyName("[...]process.dll"));
Type submitOfferType = processorAssembly.GetType("Namespace.ClassA");
Assembly.LoadFile will not attempt to resolve dependancies relative to the file your loading with LoadFile so it won't even try to resolve your action library. Appearanly it will solve it's problem of not being able to load the types becouse of dependencies by simply ignoring them.
Assembly.GetType expects the type's full name. This means you must include the namespace.
Try to find the exact full name of "ClassA":
Assembly processorAssembly = Assembly.LoadFile(process.dll);
var types= processorAssembly.GetTypes();
Check the name of the "types" in the debugger to get the real name.
Related
I have a class (TabControlH60) that both inherits from a base class (UserControl) and implements an interface (IFrameworkClient). I instantiate the object using the .NET Activator class. With the returned instance, I can cast to the UserControl base class, but not to the interface. The exception I get is below the code snipet. How do I cast to the interface?
object obj = Activator.CreateInstance(objType);
Type[] interfaces = obj.GetType().GetInterfaces(); // contains IFrameworkClient
m_Client = (UserControl)obj; // base class cast works
IFrameworkClient fc = (IFrameworkClient)obj; // interface cast fails
// Note: The (IFrameworkClient)obj cast works fine in the debugger Watch window.
{"Unable to cast object of type 'FPG.H60.AFF.TabControlH60' to type
'FPG.AFF.Interfaces.IFrameworkClient'."}
I hat the same problems with a library of mine providing "plugin"-functionality... I got it finally working...
Here was my problem: I had one main assembly using plugins, one assembly with the plugin (Plugin.dll) AND (important) another assembly providing the plugin-functionality (Library.dll).
The Plugin.dll referenced the main assembly (in order to be able to extend it) and the Library.dll with the plugin-func. - it's binaries got to a directory "./Plugins" relative to the main assembly.
The main assembly also referenced the plugin-func. assembly in order to use the "PluginManager" is wrote. This "PluginManager" gets a path and loads all *.dll files via reflection in order to analyze if there is a "IPlugin"-interface (which comes from Library.dll too).
Everytime I called the PluginManager to load the plugins it could not cast them to "IPlugin" although they implemented it.
I nearly got mad - but then I found out the whole problem. By compiling the plugin there was not only the "Plugin.dll" but the "Library.dll" written to the "./Plugins" directory. By accidentally loading the "Library.dll" every time with my PluginManager I now had two types of "IPlugin" - one in the actual "Library.dll" that is used from the main assembly and one that was loaded through my PluginManager - and those were incompatible!
Attention - if you just do not load "./Plugins/Library.dll" you nevertheless encounter the problem - because if you load "Plugin.dll" which references "Library.dll" then it just uses the one in the same directory... TILT...!! My PluginManager now just deletes "Library.dll" where it find it.
The clue is: Be sure that you do not access two assemblies in different contexts!
The most likely cause here is that IFrameworkClient is from a different assembly in the two cases, and is thus a different .NET type. Even if it is the same code, it can be a different type.
Check the AssemblyQualifiedName. Note also that if you are loading this assembly with reflection you can get a different type even with the same AssemblyQualifiedName, thanks to the load-context.
Define IFrameworkClient Interface in independent namespace (must be have namespace) of independent project (class library).Then add refrence of the class library to Control project and main project
When the Interface is in a different assembly and i get my class dynamically at run-time in a different assembly, interface casting will be failed like your sample (C# knows our interface as a different type than which one the class inherited from that).
This is my simple and useful technique in this cases:
When I'm sure my Class has inherited from the mentioned Interface (eq. IFrameworkClient), so i write one magic line of code like this:
dynamic fc = obj as IFrameworkClient ?? (dynamic) obj;
By this technique you can:
Write your codes after this line of code for fc at design time base on Interface members info and vs editor intelligences system.
Prevent any interface casting error at run-time
Notes:
You need C# v4 to use dynamic type
Usually i don't like to use dynamic types in my codes but it can help us in some cases like this
Something tells me your sample code is leaving some stuff out...
class Program
{
static void Main(string[] args)
{
var type = typeof(MyClass);
object obj = Activator.CreateInstance(type);
Type[] interfaces = obj.GetType().GetInterfaces();
var m_Client = (UserControl)obj;
IFrameworkClient fc = (IFrameworkClient)obj;
}
}
public interface IFrameworkClient { }
public class UserControl { }
public class MyClass : UserControl, IFrameworkClient { }
This compiles and runs.
I'm betting that the DLL containing the definition of IFrameworkClient hasn't yet been loaded before you try to cast. This can happen when you're using Activator.CreateInstance.
Try inserting var forceLoad = typeof(IFrameworkClient); before the cast.
If the class FPG.H60.AFF.TabControlH60 actually does implement IFrameworkClient there should be no reason this would fail. The only thing I can think of that causes this exception is if the assembly that contains IFrameworkClient is strongly named and the Tab Control object happens to reference a different version of the containing assembly or your are using a different interface with the name IFrameworkClient.
In my case I had to add a build event to copy the needed DLL since I was creating instances and assigning to interface types at run time. Otherwise the DLL loaded might not be the most up-to-date DLL, and therefore may not cast to the interface.
The reason I used build events in this case (instead of adding the DLL as a reference) is that the architecture is such that the main application should only reference the interface types, and everything else should be loaded dynamically.
TLDR;
In the case of loading types dynamically from another DLL, make sure you copy the most recent version of that DLL to the bin directory using build events, otherwise casting may not work when it appears that it should.
I ran into same issue and I just added the following code
private void LoadAssemblyPlugins(string dll)
Assembly ass = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => new Uri(a.CodeBase).Equals(new Uri(dll)));
if (ass == null)
// Load it here
// use activator here
Although, in production it will never be a problem, in unit test it was but now I don't need to load it again and create a "different type"
The cast isn't working because you're trying to cast from type object to the interface. If you replace the interface cast line with:
IFrameworkClient fc = (IFrameworkClient)m_Client;
It will work.
Alternately, I'm mildly certain that you could do the cast from the object to the interface with the as operator.
See this article for more information:
http://blogs.msdn.com/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx
One more piece of the puzzle. Interfaces do not derive from object:
http://blogs.msdn.com/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx
When I try to use the string parameter for ComSourceInterfaces instead of typeof I cannot register the assembly as a COM object. I'm implementing multiple interfaces because that is what is required by the SDK.
When I use
[ComVisible(true),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces("IAccessControl"),
Guid("738CFFEF-37DC-4C61-957E-C5A78FE20223")]
public class EventGeneratorV2 : IAccessControl
I get the error
error MSB3217: Cannot register assembly "...\Event Generator v2.dll". Could not load type 'IAccessControl' from assembly 'Event
Generator v2, Version=1.1.0.0, Culture=neutral,
PublicKeyToken=bffdb712704a75b7'.
However if I change my code to use
[ComVisible(true),
ClassInterface(ClassInterfaceType.None),
ComSourceInterfaces(typeof(IAccessControl)),
Guid("738CFFEF-37DC-4C61-957E-C5A78FE20223")]
public class EventGeneratorV2 : IAccessControl
It does work correctly. I also tried the full qualified name for the IAccessControl interface, Lib.Interfaces.IAcccessControl as the string but it still fails. The best resolution would be to use multiple ComSourceInterfaces but you can only use that once and it takes at most 4 interfaces using typeof. I have 9 interfaces I need to implement in order for it to be compatible with this other software. Is there a way to get the string to work?
Okay I figured it out. The string is actually "Lib.Interfaces.IAcccessControl, Lib" for each Interface. Where the first part is the fully qualified name for the interface and the lib is the Reference that that the Interface is coming from.
Then when I add the other interfaces I have to add the \0 between each. So my final ComSourceInterfaces is the rather lengthy
ComSourceInterfaces("Lib.Interfaces.IAccessControl, Lib\0Lib.Interfaces.IAccessControl2, Lib\0Lib.Interfaces.ITranslate, Lib\0Lib.Interfaces.ITranslate2, Lib\0Lib.Interfaces.IComConfig, Lib\0Lib.Interfaces.IComConfig2, Lib\0Lib.Interfaces.IInput, Lib\0Lib.Interfaces.IInput2, Lib\0Lib.Interfaces.IAsset, Lib\0Lib.Interfaces.IAsset2, Lib\0Lib.Interfaces.IFakeName, Lib\0Lib.Interfaces.IComManager, Lib\0Lib.Interfaces.IDistributeEvent, Lib")
After that the DLL compiles and registers correctly.
I have different class libraries that each implement an interface IImportCharacter. In my main app, the user selects a DLL and the app needs to check if the library implements the interface and then instantiate the class in the library which implements it. I'm trying to use reflection to do this but I keep getting:
Unable to cast object of type 'CustomCharacter.Ogre' to type
'MainGame.IImportCharacter'.
Assembly assembly = assemblyPath;
foreach (Type type in assembly.GetTypes())
{
IImportCharacter instance = null;
if (type.GetInterface("IImportCharacter") != null)
{
//exception thrown at this line
instance = (IImportCharacter)Activator.CreateInstance(type);
}
}
I've copied the same IImportCharacter file into the main project, otherwise the compiler complains it doesn't know what IImportCharacter is. I think this might be causing the problem since it's not the same one being dynamically loaded. How can I fix this?
Yes, I think the interface you're casting to is a different type with the same name. Why don't you move IImportCharacter to a shared assembly that you can reference both from your code and the one you're loading, since it's your interface?
Otherwise, try using Convert.ChangeType() with the dynamically loaded interface on your dynamically loaded type.
I am loading two assemblies using AssembliyDefinition.ReadAssembly
In AssemblyA I define ClassA.
In AssemblyB I define ClassB : ClassA.
When I inspect the TypeDefinition.BaseType of ClassB I get that its Module is AssemblyB.
I wouldbe expected that the its module would be AssemblyA, since the base type of ClassB is ClassA and it is defined in AssemblyA.
This shows up as an error for me because when i try to do classB.BaseType.Resolve() i get an error, which probably happens since it searches for ClassA in the wrong assembly.
Any ideas anyone?
Thanks
Your expectation is incorrect.
Cecil, unlike System.Reflection, and for a module, makes the distinction between a type defined in this module: a TypeDefinition, and a type defined in another module: a TypeReference.
That's the reason why BaseType is a TypeReference instance, and in your case, the reference to ClassA is inside AssemblyB. If you want to see where the BaseType is defined, and not where it's used, you have to use the Scope property of TypeReference.
If you have an error in Resolve, that's a completely different issue. But then you don't show anything about what this error is, so we'll have to guess that the assembly resolver doesn't know where to look for AssemblyA. And according to your comment, that's the case. Here's what you can do:
var resolver = new DefaultAssemblyResolver ();
resolver.AddSearchDirectory ("path/to/AssemblyA");
resolver.AddSearchDirectory ("path/to/AssemblyB");
var a = AssemblyDefinition.ReadAssembly (
"path/to/AssemblyA/AssemblyA.dll",
new ReaderParameters { AssemblyResolver = resolver });
var b = AssemblyDefinition.ReadAssembly (
"path/to/AssemblyB/AssemblyB.dll",
new ReaderParameters { AssemblyResolver = resolver });
This way you make sure that all your assembly share a common resolver, which knows where to find your assemblies. And Resolve will work just fine.
I'm a bit new to reflection in c#. I'm trying to generate a list of all controllers in order to test whether or not they are decorated with a specific actionfilter. When writing unit tests, how do you access the tested assembly?
This does not seem to work:
var myAssembly = System.Reflection.Assembly.GetExecutingAssembly();
If you know a type in your main assembly, you can use:
private IEnumerable<Type> GetControllers()
{
return from t in typeof(MyType).Assembly.GetTypes()
where t.IsAbstract == false
where typeof(Controller).IsAssignableFrom(t)
where t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)
select t;
}
Replace MyType with the known type.
I use this in a base class with this.GetType() instead of typeof(MyType), so that I can reference the assembly in which the derrived type is defined.
You will know the name of the assembly at the time that you write your tests. Using Assembly.ReflectionOnlyLoad() is an appropriate choice for this scenario.
As an alternative, you can draw from the Assembly property of any single known type from the assembly.
Assembly.GetAssemblyByName() is probably the ticket to look for an assembly other than yours. It'll look in your application's assembly bindings, then in the current application directory, then in the GAC. You can also get the Assembly class given an object instance or a statically-referenced type by calling GetType().Assembly.
From this Assembly class, you can iterate through the types contained in it as Type objects using GetExportedTypes(). This will return public types only; the ones you could access if you referenced the assembly statically. You can filter these by anything you can reflectively analyze; name, parent types, member names, attributes decorating the class or any member, etc.