MVC3 and MEF

ASP.NET MVC has been steadily maturing into a first rate web application framework. New features have been progressively enhancing the framework, changing how we how build more robust, flexible and effective applications. With the third iteration of the framework (currently in Beta), the MVC team have changed the underlying architecture to support service location, a much desired addition, allowing us to greatly decouple our implementations away from the framework.

MVC3 with the Managed Extensiblity Framework

Previously I’ve explored how to integrate the Managed Extensibility Framework (MEF) with MVC (version 2), and to some success, although this was mostly limited to Controllers and a rethink of the routing registration system. There was still a little too much wire up for my liking too.

So now with a fresh look at how MVC3 is changing the framework, we can see that MEF can’t completely be the center of our IoC/SL universe in this project. This revised project simplifies a lot of the wire up of our component parts, thanks to MEF’s composition engine, and allows use to handle the resolution of automatically discovered controllers, filters, etc., essentially any of the extension points in MVC3 can be used with exports via MEF.

So, how do we do this? The key is MVC3′s new IDependencyResolver interface. Much like its ancestral root, the Common Service Locator (http://commonservicelocator.codeplex.com), the IDependencyResolver interface is simply an abstraction over service location. The important part here, is that in MVC3, the IDependencyResolver is used to attempt to resolve parts before using the configured defaults. What the team has provided though, is single extension point that makes it all possible, plus they haven’t forced us to use any particular IoC Container, or Service Locator, we are free to use our own.

What we need to do first, is create an IDependencyResolver that uses our MEF container.

The interface (contract) expects us to implement a GetService method, for resolving a single instance of a type, and a GetServices method, which resolves all instances of a type. We can easily use our CompositionContainer to resolve these instances, we just have to make a quick call to AttributedModelServices to get our contract name, and then get the container to do the rest.

Minimising the wire-up

With our IDependencyResolver ready to go, I wanted to look at how we can minimise the wire-up. In other systems that I’ve designed, I’ve relied on a bootstrapping process which performs a set of startup tasks required to get the application in a ready state. We can do the same thing with our web application. Firstly, lets have a look at a task:

This custom export attribute implements a metadata contract, INamedDependencyMetadata which allows us to export additional metadata out with the task itself. The attribute supports a Name and Dependencies property, Name being quite self-explanatory, whereas the Dependencies property is an array of names, representing tasks that the target task is dependent on running. We resolve these dependencies with a special kind of list, the DependencyList.

The DependencyList is an implementation of a topological sort (based on Patrick Dewane’s article online shopping viagra in india). It allows us to sort an arbitrary set of elements into their dependent order, so in our case, we are sorting our tasks to ensure they are run in the correct order. The DependencyList really deserves a blog post to itself, but I’ll include the code in this project for your feedback.

Now we have a design for our tasks, we can look at our Bootstrapper, and how it manages our tasks.

The bootstrapper is designed to take an instance of ICompositionContainerFactory, this allows us to create our CompositionContainer outside of the bootstrapper, and makes it much easier to test. The bootstrapper creates an instance of the container using this factory, and then starts running the tasks. Oh, the bootstrapper also takes care of wiring up our IDependencyResolver.

With our bootstrapper in place, out startup code is reduced significantly:

Example Tasks: Route Registration

Much like the previous project, I’ve taken the route registration out of the global class, but this time I’ve made it a bootstrapper task. What this means is that, we don’t have to worry about explicity calling any route registration, the bootstrapper task will fire automatically, and any instances of our IRouteRegistrar contract will be used to register the specific routes. This is quite key, as when we move onto modelling a modular system, we don’t have to specifically run anything, we just label up an IRouteRegistrar for export, and it is automatically handled for us.

With that all done, we are in a good position for a fuller MVC3+MEF architecture. Thanks to MEF, adding a custom filter, controller, etc. is as simple as [Export]ing. I’ll flesh this out in the future. The project is attached, let me know what you think.

just a tiny point, i would shift the hard coded:
“string path = HostingEnvironment.MapPath(“~/bin”); ”

out to a config setting …might be more flexible…:-)

http://www.fidelitydesign.net Matthew Abbott

Hey,

For sure, in fact in the Mvc2 version that’s exactly what it was doing, this version isn’t as developed as the previous version. I’ve got a few more ideas up my sleeve

John

idea…i’m sure the Dynamic Data routing could also benefit from a slight adaption of this as well.

Jokie

Great article. Thanks for putting the time and effort. Do you intend to develop this further? What is your licensing.

http://www.fidelitydesign.net Matthew Abbott

Hi,

I’m planning to expand on this soon and develop some sort of extensible application framework on top of mvc. Well, if there is enough interest. I haven’t considered licensing yet, but essentially you can go ahead and use it freely. I’ll think about licensing when its developed further.

D

Nice work Matt. I’ve been working on something similar to your previous posts about MEF and MVC. Does the DependencyResolver remove the need for something like VirtualPathProvider?

http://www.fidelitydesign.net Matthew Abbott

Hi D,

Thanks for the comments

The DependencyResolver doesn’t remove the need for a VirtualPathProvider. The VPP is specifically used for resolving files through virtual paths, you may still need this if you are loading resources from external assemblies, databases etc. What might be worth a look into is how we can inject a VirtualPathProvider into the ASP.NET framework through an IoC container or a service locator (DependencyResolver).

Richie Scott

Hi Matt, great blog once again!!!!

I currently have a MVC2 application hosted on premise that allows the user to add custom extensions (controllers, filters, views, validators) so that they can extend the application to suit their needs. I’m using MEF as my composition container, but MVC2 relies on the extensions (assemblies, views and scripts) to be located in a particular directory or found at runtime based on a configuration setting. The MEF catalog is instantiated at startup meaning if any new extensions are required to be added or updated then the application needs to be restarted. This is all fine in a single-tenant world but now I want to make it multi-tenant hosted in the azure cloud.

The problem I forsee is the location of the custom extensions and how they are deployed. My initial thought is to use azure blob storage (one per tenant) to store the custom extensions and then download per-session (rather than Application Startup), however in the past the way MVC has worked is it tries to resolve assemblies and find views within the current AppDomain whereas my assemblies and their embedded resources will be in memory. (I’m not even sure your VPP would work)

Can MVC3 help me with this problem?

Any comments or redirects would be greatly appreciated.

http://www.fidelitydesign.net Matthew Abbott

Hi Richie,

Sorry for the (very) late reply! In this sense I don’t believe there is much architectural difference between MVC 2 and MVC3. Both are still dependent on the ASP.NET platform which enforces certain rules around how assemblies are deployed and the lifetime of web AppDomain instances.

How are you planning to manage the lifetime of your catalogs? This may hold the key, as catalogs can be expensive to create, whereas new instances of CompositionContainer are quite cheap to spin up…

Hello
Thanks for your great work
One question, how would we go about making this modular like the one for mvc 2. Also would it be possible (without much gutting) to use ninject for the IOC

http://www.fidelitydesign.net Matthew Abbott

Hi,

I’m hoping to continue the development of this MVC3 + MEF project to bring it inline with the MVC2 project I had built earlier. There isn’t actually too much to do, it’s just finding the time.

You could consider either building an IDependencyResolver implementation that uses your Ninject container, or you could easilly wire up your Ninject container to an ExportProvider that MEF can utilise to automatically start composing your Ninject-powered parts.

foobar

Dude, what’s the purpose of a DependencyList?

http://YourWebsite barry schulz

hey Matthew,

Great post.

Can you clarify if you meant to say “MEF *can* completely be the center of our IoC/SL universe”?

thanks

http://YourWebsite Maxim

Good article Matthew, thanks!

But what about Models? I’d add once simple class to folder Models and use it in Controller. But Main Web Application fail because it not see/found [My_namespace].Models from View.
Did you try work with Model in controller?

http://www.fidelitydesign.net Matthew Abbott

Hi,

Razor uses a different build provider than WebForms. I’ll be posting an updated article detailing how to use Razor with MVC + MEF soon. Stay tuned

http://YourWebsite Jesse

I am so looking forward to you finishing this up, you have my interest for sure.

Charandeep Singh

Very good article.

Charandeep Singh

Watching your stuff running kinda makes me jump from chair

Greg Bacchus

Did you ever get MEF + Razor working?

http://www.fidelitydesign.net Matthew Abbott

Hi,

Sorry I missed this comment as it didn’t go through the Disqus commenting system I now use. I haven’t had much time to work on this these last few months, but essentially the last piece of the puzzle is subclassing the RazorBuildProvider to ensure the plugin assemblies are referenced by your dynamic views. Check out this answer on Stack Overflow:

@google-42ef280ca4b4496c4ff86f8bb74df2f9:disqusu00a0Sorry I haven’t had a chance to finish this up, got lots of little projects going on at the moment. I’m hoping to get some time in the new year to sit down and work on this some more

eth0

Hi Greg, there’s nothing special required to get Razor working in this context. Just make sure you have your Web.Config and _ViewStart.cshtml in the view directory and it works perfectly for me.

Adeyts

u00a0Hi guys,nI’m almost done with implementing MEF with MVC3, but having a problem with the Model namespace.nnHere’s the error: The type or namespace name ‘LexSys’ could not be found (are you missing a using directive or an assembly reference?)Any thought on this? I’ve used AppDomainSetup to register the path of the dll of the separate class library that has the model. Similar implementation used for MVC 2.Thanks for your help guys.Alex

Nate

Any update of MEF+Razor? I need to create a modular solution for MVC3 asp.net

sanosay

Hello Mat!

Again thank you very mutch for your wonderful articles!
Have you manage to bring it inline with the MVC2 project?

http://www.fidelitydesign.net Matthew Abbott

I an hoping to come back to this project with MVC4 and WebAPI shortly.

Martin

I read all of your posts about MEF and MVC and would like to here if you have come any closer to a working solution with MVC 4

http://coloradobeach.yolasite.com/ FritzHester

I was doing some searching late last night and could not believe that I actually found a amazon article rewriter.

http://winmain.vn/gioi-thieu-phan-mem-vtiger-crm.html Phan Mem CRM

I would like to use MEF and MVC in a multi-tenant scenario with each tenant having their own catalog. I’m planning on using a separate Blob (Azure) storage to store a tenants catalog assemblies. Ideally I would like a new container per tenant per session. Do you have any thoughts? My main problem is where to reference a the per-session container, I could put it in the session context but that would mean the application would not be very scalable.