Why use MEF or Unity to load the Shell?

Topics: Prism v4 - WPF 4
Dec 30, 2010 at 5:19 AM

I've been playing around with Prism,  there is a lot of really cool stuff in there.

But there are a few details that bug me a bit.  The above question being one of them.

Since there can only be one shell... what's the advantage or the beauty of loading it using MEF or Unity?

Or... are you just doing that to be consistent with how you are handling things?

Sorry if it seems like a silly question, but since this is patterns & practices, understanding why something is implemented in a certain way can help me a lot with understanding it.

When I look at it, it auto discovery and loading for somethings is great.  But for some things like this, it just seems like excess overhead.  Am I missing something?

 

Dec 30, 2010 at 11:18 AM

A couple of things come to mind:

  1. The shell can have dependencies that need to be resolved, just like any part of the system.  Things like loggers, the event aggregator, Region Managers, or any services set up at the app level that need to be used by the shell, so using DI to load the shell allows for the same abstractions to be used with it that you would use anywhere else in the application.
  2. The shell itself could be different depending some criteria of the logged in user.  The configuration could use different shells based upon the users login.  This config could be managed through DI. 

Does that help?

Paul

 

Dec 30, 2010 at 5:21 PM

Yes, very helpful, thanks!

Dec 30, 2010 at 7:03 PM

OK... So lets say I do have multiple shells defined.

Let's say, I export an IShell from my base class library.  This would be a default Shell that would be used if no other shell is found.

I then create an IShell in my main project.  This is meant to override the default.

Is there any built in mechanism to allow one export to override another export?

Obviously I can work around this by exporting ShellBase and Shell instead of IShell.  But I was curious if there was any built in mechanism to allow for overrides.

 

Dec 30, 2010 at 8:19 PM
Edited Dec 30, 2010 at 8:20 PM

And probably to your surprise, there are several approaches to this too.  <grin>

Take a look at the unity documentation for Resolving Objects in the Unity documentation.

http://unity.codeplex.com/releases/view/31277

All of those are available to you.

You will need to add code to your bootstrapper to provide the disciminator you will need to use in the resolve, or resolution because the Container is created within the bootstrapper. 

Particularly look at the Resolve options in "Resolving an Object by Type and Registration Name"

Dec 31, 2010 at 12:39 AM
Edited Dec 31, 2010 at 6:06 AM

Interesting, thanks.

Took me forever to find something equivalent to Resolve in MEF. 

Edit:  It looks like I could do something using ExportMetaData

Edit2: Found a few ways to go on this... Container.GetExports(Type, Type, String) looks the most promising at the moment.

Edit3: GetExports worked for Injection and is probably the simplest solution.  For auto discovery I think you would have to create a filtered catalog.

Dec 31, 2010 at 11:43 AM

Good,

Then all you need to do is to figure out which mechanism you want to use, which will drive what kind of data you will need to provide on the "Resolve", to get the appropriate shell.

You could have preconfigured unity with several shells that resolve using different names.  I.E. a manager shell and an employee shell.  The app.cs then passes the appropriate value to the bootstrapper, where you do your resolve using that data to get the appropriate shell.

MEF would work in a similar fashion, I would assume. Not being a MEFHead, I cant say without some research.

Paul

Dec 31, 2010 at 3:20 PM

As long as the class has been exported and satisfied into the container it will work.  If it can't find the contract it will simply error out and you have to hunt down where the error exists.  So in theory you could have multiple shells to work with in a single project it all depends how you construct everything to make it work.

Jan 1, 2011 at 11:22 PM

Enjoying this discussion, learning a lot!

I did get a demo of multiple shells working, if I was going to use it in production, I would probably write my own resolver class for it.

In case someone happens across this thread, here's a hint (very quick and dirty) on how to do it:

[Export(typeof(Window))]
[ExportMetadata("Priority",5)]
public partial class Shell : Window

public interface IPriorityMetadata
{
int Priority { get; }
}

protected override DependencyObject CreateShell()
{
var shells = this.Container.GetExports<Window, IPriorityMetadata>();
Window shl = shells.FirstOrDefault(w => w.Metadata.Priority == shells.Max(m => m.Metadata.Priority)).Value;
return shl;
}

I also played with creating a new service, I wrote one for persisting the UI using an attached behavior.  Works well, and was easy to write. :-)

Now I'm on to playing with the region manager and figuring out how to do hierarchical view models.  So far that looks the same as how I have been doing it in MVVM (Using data templates)

I'll let you know if I end up with more questions.  Thanks!