Modular ASP.NET MVC using the Managed Extensibility Framework (MEF), Part Two
2013-02-03 21:33 yezhi 阅读(565) 评论(0) 收藏 举报http://www.fidelitydesign.net/?p=130
- 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:
<system.web>
<pages
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
</pages>
</system.web>
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.
/// <summary>
/// Creates the composition container.
/// </summary>
/// <returns></returns>
protectedvirtualCompositionContainerCreateCompositionContainer()
{
var catalog =newAggregateCatalog();
catalog.Catalogs.Add(newDirectoryCatalog(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 inGetDirectoryCatalogs(path)){
// Register our path for probing.
RegisterPath(directoryCatalog.FullPath);
// Add the catalog.
catalog.Catalogs.Add(directoryCatalog);
}
}
});
}
var provider =newDynamicInstantiationExportProvider();
var container =newCompositionContainer(catalog, provider);
provider.SourceProvider= container;
return container;
}
Here is our method, RegisterPath:
/// <summary>
/// Registers the specified path for probing.
/// </summary>
/// <param name="path">The probable path.</param>
privatevoidRegisterPath(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:
<%@AssemblyName="MefMvcFramework.Blog" %>
<%@ImportNamespace="MefMvcFramework.Blog.Models" %>
<%@PageTitle=""Language="C#"MasterPageFile="~/Views/Shared/Site.Master"Inherits="System.Web.Mvc.ViewPage<Post>" %>
<asp:ContentContentPlaceHolderID="MainContent"runat="server">
<h2><%:Model.Title %></h2>
</asp:Content>
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 ![]()






浙公网安备 33010602011771号