5

At the moment, I have this code :

var shellViewLibrary = Assembly.LoadFrom(Path.Combine(_DllsPath, _DllShellView));
IEnumerable<Type> types = shellViewLibrary.GetTypes();

foreach (Type type in types)
{
    var typeIShellViewInterface = type.GetInterface(_NamespaceIShellView, false);
    if (typeIShellViewInterface != null)
    {
        //here
    }
}

The thing is that where I got //here I want to use Activator.CreateInstance to create an object whose type is type in a specific folder (that is outside the build folder) I tried about 20 different things, most of them with this : http://msdn.microsoft.com/en-us/library/d133hta4.aspx but none works... The typical thing I tried is :

object MyObj = Activator.CreateInstance(shellViewLibrary.FullName, type.FullName);

or

object MyObj = Activator.CreateInstance(Path.Combine(_DllsPath, _DllShellView), type.FullName);

I always got different exception, the most common being :

XamlParseException

I feel like that I'm not using Activator.CreateInstance in the right way with 2 parameters. What should I do ?

Jens Björnhager
  • 5,632
  • 3
  • 27
  • 47
Guillaume Slashy
  • 3,554
  • 8
  • 43
  • 68
  • `XamlParseException` occurs when there has been an error with the parsing of XAML. There should be an inner exception, so if you debug around that line you should be able to delve into the `XamlParseException` and see the source of it. It sounds like you may be missing something that the `Assembly` your trying to load requires. – Samuel Slade Jan 19 '12 at 15:21
  • When I switch my arguments for "Activator.CreateInstance", I got the same error so I really feel like something is completely wrong :/ – Guillaume Slashy Jan 19 '12 at 15:23
  • @GuillaumeSlashy I would recommend wrapping your Activator.CreateInstance in a try catch and debugging - at the point of caught exception look at the inner exceptions as I and Samuel Slade have said. Pending further code in your Q it doesnt seem that the use of Activator or Assembly.Load is the problem, but rather an error in a Xaml file used by a control being instantiated by Activator.CreateInstance – Dr. Andrew Burnett-Thompson Jan 19 '12 at 15:34

5 Answers5

12

This is an example of "Dynamically Loading a .dll from a Specific Folder" at runtime.

// Check if user has access to requested .dll.
string strDllPath = Path.GetFullPath(strSomePath);
if (File.Exists(strDllPath))
{
    // Execute the method from the requested .dll using reflection (System.Reflection).
    Assembly DLL = Assembly.LoadFrom(strDllPath);
    Type classType = DLL.GetType(String.Format("{0}.{1}", strNmSpaceNm, strClassNm));
    if (classType != null)
    {
        // Create class instance.
        classInst = Activator.CreateInstance(classType);

        // Invoke required method.
        MethodInfo methodInfo = classType.GetMethod(strMethodName);
        if (methodInfo != null)
        {
            object result = null;
            result = methodInfo.Invoke(classInst, new object[] { dllParams });
            return result.ToString();
        }
    }
}

This took me a while to work out so I hope it is of some use...

MoonKnight
  • 23,214
  • 40
  • 145
  • 277
  • Thats' the code I did in the 1st time and it fails at classInst = Activator.CreateInstance(classType); for me :/ Maybe something's wrong with the dll... – Guillaume Slashy Jan 19 '12 at 15:34
  • It should give you a good indication of what is going wrong if you step through the code in debug mode. You also need to know the Namespace name and Class name you are invoking using this method. Additionally, the above code is passing parameters to the .dll. If you do not know what parameters to pass the called function this can also be an issue... – MoonKnight Jan 19 '12 at 15:40
8

Once you call this line

var shellViewLibrary = Assembly.LoadFrom(Path.Combine(_DllsPath, _DllShellView)); 

The assembly has been loaded in to memory. So long as you specify types correctly from this then you will be able to use Activator.CreateInstance to create the types. ie: It is not necessary to further specify where the type is.

Regarding Activator, from MSDN the CreateInstance method can accept a System.Type. I would just use this method inside your if-statement:

Activator.CreateInstance(Type type);

What I would try to do to debug this is first create the type and then pass it in to CreateInstance. You may find that the Type creation itself is failing (due to unresolved assembly) or the instantiation of that type (due to exception in the constructor). At first glance your code here appears to be correct:

foreach (Type type in types)      
{          
    var typeIShellViewInterface = type.GetInterface(_NamespaceIShellView, false);          
    if (typeIShellViewInterface != null)          
    {              
        try
        {
            // I assume you are calling this line at the point marked 'here'. 
            // To debug the creation wrap in a try-catch and view the inner exceptions
            var result = Activator.CreateInstance(type);          
        }
        catch(Exception caught)
        {
            // When you hit this line, look at caught inner exceptions
            // I suspect you have a broken Xaml file inside WPF usercontrol
            // or Xaml resource dictionary used by type
            Debugger.Break();
        }
    }      
}  

In your question you specify that you are getting a XamlParseException. It sounds to me like the type in question is a UserControl (or otherwise refers to a WPF Xaml resource file) and there is an error in that Xaml file, i.e. nothing to do with your usage of Assembly.Load or Activator.CreateInstance.

Could you try posting the inner exception(s) to get a better idea on what the problem is?

Dr. Andrew Burnett-Thompson
  • 20,980
  • 8
  • 88
  • 178
2

Check out MEF and Prism. MEF is a dependency injection library that helps with this. You can load all of your dependencies from a specific folder and make dynamically load them.

Prism is a pattern that leverages dependency injection and works great with MEF to load libraries dynamically

joe_coolish
  • 7,201
  • 13
  • 64
  • 111
0

if you're trying to create a type with the Activator class from a DLL that's outside your application, you need to first load this DLL inside your application domain. The easiest and quickest way to do this is by using the Assembly.LoadFile method.

more information about that method can be found here : http://msdn.microsoft.com/en-us/library/system.reflection.assembly.loadfile.aspx

When the assembly is properly loaded you can use the Activator to create an instance from the type inside the DLL. We use this mechanic to run custom code in our application.

codingbunny
  • 3,989
  • 6
  • 29
  • 54
  • When I do var lib = Assembly.LoadFile("D:\\CebisSample\\Runtime\\myDLL.dll"); I got the same XAML error, what's wrong ? When I do LoadFrom from the exact same dll, it works oO – Guillaume Slashy Jan 19 '12 at 15:29
  • LoadFile examines the 'identity' of the DLL and validates the versions of the assemblies whereas LoadFrom doesn't do this and just grabs the matching version. LoadFile allows you to load different versions of assemblies. – codingbunny Jan 19 '12 at 15:32
  • If you read the q. carefully you'll see he's already got the type and assembly loaded – Dr. Andrew Burnett-Thompson Jan 19 '12 at 15:33
  • 1
    He added that, it wasn't there originally. So thank you, but I've read the question – codingbunny Jan 19 '12 at 15:33
0

I'm not sure what you mean by this:

create an object whose type is type in a specific folder (that is outside the build folder)

A type only exists in an assembly. Path is entirely irrelevant to types in .NET

I assume that by "path" you really mean "namespace", meaning that you don't know in which namespace the type exists. You have already loaded the assembly in your code. Inspect the assembly using reflection to find the type you're looking for. Then pass the Type object that represents the type you're looking for to Activator.CreateInstance

Randolpho
  • 55,384
  • 17
  • 145
  • 179
  • If my assembly is on a USB-key for example, Activator.CreateInstance won't work if I don't specify something, no ? – Guillaume Slashy Jan 19 '12 at 15:31
  • 1
    Once you load the assembly, it's in memory. There are rules .NET has about loading assemblies from remote drives (I misremember them at the moment, but I will look them up), but once the assembly is loaded, Activator.CreateInstance will instantiate types for you, **provided you tell it what type you want to instantiate**. – Randolpho Jan 19 '12 at 15:35