Reputation: 55502
I'm currently using MEF for a project to import plugins, as the plugins are written in WPF they each have a view and a viewmodel. The plugins know about the viewmodel but the main shell UI will construct the view and bind the viewmodel using a convention over configuration type pattern.
I have used some code from the Build-your-own-MVVM-framework sample to do the auto view discovery:
[ImportMany(typeof(IPlugin))]
public IEnumerable<IPlugin> Plugins { get; set; }
var viewTypeName = this.Plugins.First().ViewModel.GetType().AssemblyQualifiedName.Replace("Model", string.Empty);
var viewType = Type.GetType(viewTypeName,true);
The code at the moment just gets the first plugin and takes out Model
from the name, returns the view name and gets the view type so that I can construct it. So an example of what viewType would be is:
PluginTest.TestView, PluginTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
However when I call Type.GetType(viewType)
I get back null, if I add the true
to throw an exception I get the exception:
Could not load file or assembly 'PluginTest, Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null' or one of its dependencies.
The system cannot find the file specified.
Even though it is already loaded using MEF.
If I do:
var types = Assembly.GetAssembly(this.Plugins.First().ViewModel.GetType()).GetTypes();
I get back a list of all the types in the assembly of the plugin, so far there is just PluginTest.TestView
and PluginTest.TestViewModel
Can anyone help me with this one?
EDIT: Sorry didn't mention before, the plugins are in different assemblies to my main shell app.
Upvotes: 3
Views: 1616
Reputation: 16744
The assembly was probably loaded in the Load-From context, and Type.GetType() doesn't work with assemblies loaded in that context. MEF tries to load assemblies in the default context, but if that doesn't work it loads them in the Load-From context.
More about assembly load contexts in .NET
Upvotes: 1
Reputation: 1791
This question has long been answered, but just in case someone stumbles upon this, here is my solution.
As the other answers have noted, the problem is that though the assembly has been loaded through MEF, it gets loaded again once you use GetType()
. Unfortunately, I had no control over the code calling GetType()
, so Jon Skeet's solution wouldn't work in my case.
In my case, the problem could be solved by adding the location of the plugin assembly to the probing path of the application.
An alternative solution (which is what I eventually did) is to implement the AssemblyResolve
event, and to load the assembly manually. This solution is very flexible, contrary to the probing path solution it also works if you don't know the installation directory of the plugin in advance.
Also: if your plugin has any dependent assemblies, you have to use one of these two solutions, for otherwise you get a FileNotFound exception on your first use of these dependencies.
Upvotes: 0
Reputation: 1502825
It's probably easiest to do something like this:
var modelType = this.Plugins.First().ViewModel.GetType();
var viewTypeName = modelType.FullName.Replace("Model", string.Empty);
var viewType = modelType.Assembly.GetType(viewTypeName);
I'm not sure why Type.GetType
isn't working for you - assembly resolution is a tricky beast - but if you know the assembly the type should be defined in anyway, I'd definitely go via Assembly.GetType
instead.
Upvotes: 4