Modular ASP.NET MVC using the Managed Extensibility Framework (MEF), Part Two

See also: Modular ASP.NET MVC using the Managed Extensibility Framework (MEF), Part One
Currently reading: Modular ASP.NET MVC using the Managed Extensibility Framework (MEF), Part Two
See also: Modular ASP.NET MVC using the Managed Extensibility Framework (MEF), Part Three
In my previous post I presented an MVC Framework that uses the Managed Extensibility Framework (MEF) to allow for powerful extensibility of ASP.NET MVC, not just for controllers, but also for views. You can find my original article here.

There are a couple of small issues I want to iron out before it becomes a project-quality framework. These issues are:

Strongly-typed Models from imported libraries
Managing referenced libraries in built modules
Strongly-typed Models from imported libraries
In the previous version of the framework, one thing which I had neglected to highlight and test is using a strongly-typed view model from an external module. This action turned out to be a bigger issue than simply trying to find a reference. The first exception that was thrown at me was this:

This is quite a common occurence, and is due to the MVC framework not being able to instantiate the types required to process the views. Because our views sit outside the the /Views folder, the /Views specific configuration items were missing from the config. We can easily add these in to our main web.config file:


Ok, thats done, what next:

This one was a little more confusing, it can’t find my type? How comes my Controller can but my View can’t? In current WebForms technology (including ASP.NET WebForms) our pages are compiled into a seperate assembly, referenced to the main website. Because we’ve imported our types using MEF, we haven’t created a reference to the specific assemblies, so no reference is created to the page assemblies which are generated. There is another issue here also, our imported assemblies don’t sit in the /bin folder of the application, so discovering the correct assemblies requires a little work. Firstly, we need to modify our Application class, changing it’s CreateCompositionContainer method to fire a call to another method which registers our path for probing.

/// /// Creates the composition container. ///
///
protected virtual CompositionContainer CreateCompositionContainer()
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new DirectoryCatalog(MapPath(“~/bin”)));

var config = CompositionConfigurationSection.GetInstance(); if (config != null && config.Catalogs != null) { config.Catalogs .Cast<CatalogConfigurationElement>() .ForEach(c => { if (!string.IsNullOrEmpty(c.Path)) { string path = c.Path; if (path.StartsWith("~")) path = MapPath(path); foreach (var directoryCatalog in GetDirectoryCatalogs(path)) { // Register our path for probing. RegisterPath(directoryCatalog.FullPath); // Add the catalog. catalog.Catalogs.Add(directoryCatalog); } } }); } var provider = new DynamicInstantiationExportProvider(); var container = new CompositionContainer(catalog, provider); provider.SourceProvider = container; return container;
Code language: PHP (php)

}
Here is our method, RegisterPath:

/// /// Registers the specified path for probing. ///
/// The probable path.
private void RegisterPath(string path)
{
AppDomain.CurrentDomain.AppendPrivatePath(path);
}
Ok, it’s not much, but what it is doing is appending each path for our DirectoryCatalog instances into the private path of the AppDomain. Through the type resolution process, the AppDomain will probe the private paths to try and find the required types, if its not GAC’d or previously found.

We’re nearly there, but now we need to make a final change to our views. We need to add in a command to the top of each view, pointing to the assembly which should be referenced for the view. In this example, I’ve added the MefMvcFramework.Blog assembly as the referenced one:

<%@ Assembly Name=”MefMvcFramework.Blog” %>
<%@ Import Namespace=”MefMvcFramework.Blog.Models” %>
<%@ Page Title=”” Language=”C#” MasterPageFile=”~/Views/Shared/Site.Master” Inherits=”System.Web.Mvc.ViewPage” %>

<%: Model.Title %>

Let’s run that, and it now works 🙂

Managing referenced libraries in built modules
It’s been noted that when we build a module that has references of it’s own, the default build action for references is to copy any non-GAC’d references to the output directory of the application. Commonly with shared functionality you’d put your support assemblies in the /bin folder and our modules will still be able to run correctly. For these shared assemblies, we can tell Visual Studio not to deploy them alongside our built modules, we do this by changing the CopyLocal properties of referenced assemblies.

In Visual Studio, select the reference in the solution explorer \References\, and select Properties with the context menu (or press F4):

Set the CopyLocal property to false, this will stop Visual Studio from deploying the referenced assemblies.

To see the effect, empty the /Areas/Blog folder of your main application, and rebuild, you should see a much cleaner number of files:

What’s next? I’d like to investigate dependency injection for Controllers, either through MEF alone, or possibly mixing it up with an IoC container, if required. Watch this space 🙂

Download VS2010 Project (fixed)

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Post