Logo

Maarten Balliauw {blog}

ASP.NET, ASP.NET MVC, Azure, PHP, OpenXML, VSTS, ...

About the author

Maarten Balliauw is currently employed as .NET Technical Consultant at RealDolmen. His interests are mainly web applications developed in ASP.NET (C#) or PHP and the Windows Azure cloud platform.
More about me More about me
Send mail E-mail me


ASP.NET MVC Quickly Subscribe to my RSS feed Follow me on Twitter! View Maarten Balliauw's profile on LinkedIn
View Maarten Balliauw's MVP profile

Search

Latest Twitter

    Follow me on Twitter...

    My projects

    Disclaimer

    The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

    © Copyright Maarten Balliauw 2010

    ASP.NET MVC 3 and MEF sitting in a tree...

    As I stated in a previous blog post: ASP.NET MVC 3 preview 1 has been released! I talked about some of the new features and promised to do a blog post in the dependency injection part. In this post, I'll show you how to use that together with MEF.

    Download my sample code: Mvc3WithMEF.zip (256.21 kb)

    kick it on DotNetKicks.com

    Dependency injection in ASP.NET MVC 3

    First of all, there’s 4 new hooks for injecting dependencies:

    • When creating controller factories
    • When creating controllers
    • When creating views (might be interesting!)
    • When using action filters

    In ASP.NET MVC 2, only one of these hooks was used for dependency injection: a controller factory was implemented, using a dependency injection framework under the covers. I did this once, creating a controller factory that wired up MEF and made sure everything in the application was composed through a MEF container. That is, everything that is a controller or part thereof. No easy options for DI-ing things like action filters or views…

    ASP.NET MVC 3 shuffled the cards a bit. ASP.NET MVC 3 now contains and uses the Common Service Locator’s IServiceLocator interface, which is used for resolving services required by the ASP.NET MVC framework. The IServiceLocator implementation should be registered in Global.asax using just one line of code:

    MvcServiceLocator.SetCurrent(new SomeServiceLocator());

    This is, since ASP.NET MVC 3 preview 1, the only thing required to make DI work. In controllers, in action filters and in views. Cool, eh?

    Leveraging MEF with ASP.NET MVC 3

    First of all: a disclaimer. I already did posts on MEF and ASP.NET MVC before, and in all these posts, I required you to explicitly export your controller types for composition. In this example, again, I will require that, just for keeping code a bit easier to understand. Do note that are some variants of a convention based registration model available.

    As stated before, the only thing to build here is a MefServiceLocator that is suited for web (which means: an application-wide catalog and a per-request container). I’ll still have to create my own controller factory as well, because otherwise I would not be able to dynamically compose my controllers. Here goes…

    Implementing ServiceLocatorControllerFactory

    Starting in reverse, but this thing is the simple part :-)

    [Export(typeof(IControllerFactory))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class ServiceLocatorControllerFactory
        : DefaultControllerFactory
    {
        private IMvcServiceLocator serviceLocator;

        [ImportingConstructor]
        public ServiceLocatorControllerFactory(IMvcServiceLocator serviceLocator)
        {
            this.serviceLocator = serviceLocator;
        }

        public override IController CreateController(RequestContext requestContext, string controllerName)
        {
            var controllerType = GetControllerType(requestContext, controllerName);
            if (controllerType != null)
            {
                return this.serviceLocator.GetInstance(controllerType) as IController;
            }

            return base.CreateController(requestContext, controllerName);
        }

        public override void ReleaseController(IController controller)
        {
            this.serviceLocator.Release(controller);
        }
    }

    Did you see that? A simple, MEF enabled controller factory that uses an IMvcServiceLocator. This thing can be used with other service locators as well.

    Implementing MefServiceLocator

    Like I said, this is the most important part, allowing us to use MEF for resolving almost any component in the ASP.NET MVC pipeline. Here’s my take on that:

    [Export(typeof(IMvcServiceLocator))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class MefServiceLocator
        : IMvcServiceLocator
    {
        const string HttpContextKey = "__MefServiceLocator_Container";

        private ComposablePartCatalog catalog;
        private IMvcServiceLocator defaultLocator;

        [ImportingConstructor]
        public MefServiceLocator()
        {
            // Get the catalog from the MvcServiceLocator.
            // This is a bit dirty, but currently
            // the only way to ensure one application-wide catalog
            // and a per-request container.
            MefServiceLocator mefServiceLocator = MvcServiceLocator.Current as MefServiceLocator;
            if (mefServiceLocator != null)
            {
                this.catalog = mefServiceLocator.catalog;
            }

            // And the fallback locator...
            this.defaultLocator = MvcServiceLocator.Default;
        }

        public MefServiceLocator(ComposablePartCatalog catalog)
            : this(catalog, MvcServiceLocator.Default)
        {
        }

        public MefServiceLocator(ComposablePartCatalog catalog, IMvcServiceLocator defaultLocator)
        {
            this.catalog = catalog;
            this.defaultLocator = defaultLocator;
        }

        protected CompositionContainer Container
        {
            get
            {
                if (!HttpContext.Current.Items.Contains(HttpContextKey))
                {
                    HttpContext.Current.Items.Add(HttpContextKey, new CompositionContainer(catalog));
                }

                return (CompositionContainer)HttpContext.Current.Items[HttpContextKey];
            }
        }

        private object Resolve(Type serviceType, string key = null)
        {
            var exports = this.Container.GetExports(serviceType, null, null);
            if (exports.Any())
            {
                return exports.First().Value;
            }

            var instance = defaultLocator.GetInstance(serviceType, key);
            if (instance != null)
            {
                return instance;
            }

            throw new ActivationException(string.Format("Could not resolve service type {0}.", serviceType.FullName));
        }

        private IEnumerable<object> ResolveAll(Type serviceType)
        {
            var exports = this.Container.GetExports(serviceType, null, null);
            if (exports.Any())
            {
                return exports.Select(e => e.Value).AsEnumerable();
            }

            var instances = defaultLocator.GetAllInstances(serviceType);
            if (instances != null)
            {
                return instances;
            }

            throw new ActivationException(string.Format("Could not resolve service type {0}.", serviceType.FullName));
        }

        #region IMvcServiceLocator Members

        public void Release(object instance)
        {
            var export = instance as Lazy<object>;
            if (export != null)
            {
                this.Container.ReleaseExport(export);
            }

            defaultLocator.Release(export);
        }

        #endregion

        #region IServiceLocator Members

        public IEnumerable<object> GetAllInstances(Type serviceType)
        {
            return ResolveAll(serviceType);
        }

        public IEnumerable<TService> GetAllInstances<TService>()
        {
            var instances = ResolveAll(typeof(TService));
            foreach (TService instance in instances)
            {
                yield return (TService)instance;
            }
        }

        public TService GetInstance<TService>(string key)
        {
            return (TService)Resolve(typeof(TService), key);
        }

        public object GetInstance(Type serviceType)
        {
            return Resolve(serviceType);
        }

        public object GetInstance(Type serviceType, string key)
        {
            return Resolve(serviceType, key);
        }

        public TService GetInstance<TService>()
        {
            return (TService)Resolve(typeof(TService));
        }

        #endregion

        #region IServiceProvider Members

        public object GetService(Type serviceType)
        {
            return Resolve(serviceType);
        }

        #endregion
    }

    HOLY SCHMOLEY! That is a lot of code. Let’s break it down…

    First of all, I have 3 constructors. 2 for convenience, one for MEF. Since the MefServiceLocator will be instantiated in Global.asax and I only want one instance of it to live in the application, I have to do a dirty trick: whenever MEF wants to create a new MefServiceLocator for some reason (should in theory only happen once per request, but I want this thing to live application-wide), I’m giving it indeed a new instance which at least shares the part catalog with the one I originally created. Don’t shoot me for doing this…

    Next, you will also notice that I’m using a “fallback” locator, which in theory will be the instance stored in MvcServiceLocator.Default, which is ASP.NET MVC 3’s default MvcServiceLocator. I’m doing this for a reason though… read my disclaimer again: I stated that everything should be decorated with the [Export] attribute when I’m relying on MEF. Now since the services exposed by ASP.NET MVC 3, like the IFilterProvider, are not decorated with this attribute, MEF will not be able to find those. When I find myself in that situation, the MefServiceLocator is simply asking the default service locator for it. Not a beauty, but it works and makes my life easy.

    Wiring things

    To wire this thing, all it takes is adding 3 lines of code to my Global.asax. For clarity, I’m giving you my entire Global.asax Application_Start method:

    protected void Application_Start()
    {
        // Register areas

        AreaRegistration.RegisterAllAreas();

        // Register filters and routes

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        // Register MEF catalogs

        var catalog = new DirectoryCatalog(
            Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin"));
        MvcServiceLocator.SetCurrent(new MefServiceLocator(catalog, MvcServiceLocator.Default));
    }

    Can you spot the 3 lines of code? This is really all it takes to make the complete application use MEF where appropriate. (Ok, that is a bit of a lie since you would still have to implement a very small IFilterProvider if you want MEF in your action filters, but still.)

    Hooks

    The cool thing is: a lot of things are now requested in the service locator we just created. When browsing to my site index, here’s all the things that are requested:

    • Resolve called for serviceType: System.Web.Mvc.IControllerFactory
    • Resolve called for serviceType: Mvc3WithMEF.Controllers.HomeController
    • Resolve called for serviceType: System.Web.Mvc.IFilterProvider
    • Resolve called for serviceType: System.Web.Mvc.IFilterProvider
    • Resolve called for serviceType: System.Web.Mvc.IFilterProvider
    • Resolve called for serviceType: System.Web.Mvc.IFilterProvider
    • Resolve called for serviceType: System.Web.Mvc.IViewEngine
    • Resolve called for serviceType: System.Web.Mvc.IViewEngine
    • Resolve called for serviceType: ASP.Index_cshtml
    • Resolve called for serviceType: System.Web.Mvc.IViewEngine
    • Resolve called for serviceType: System.Web.Mvc.IViewEngine
    • Resolve called for serviceType: ASP._LogOnPartial_cshtml

    Which means that you can now even inject stuff into views or compose their parts dynamically.

    Conclusion

    I have a strong sense of a power in here… ASP.NET MVC 3 will support DI natively if you want to use it, and I’ll be one of the users happily making use of it. There’s use cases for injecting/composing something in all of the above components, and ASP.NET MVC 3 made this just simpler and more straightforward.

    Here’s my sample code with some more examples in it: Mvc3WithMEF.zip (256.21 kb)


    MEF will not get easier, it’s cool as ICE

    Over the past few weeks, several people asked me to show them how to use MEF (Managed Extensibility Framework), some of them seemed to have some difficulties with the concept of MEF. I tried explaining that it will not get easier than it is currently, hence the title of this blog post. MEF is based on 3 keywords: export, import, compose. Since these 3 words all start with a letter that can be combined to a word, and MEF is cool, here’s a hint on how to remember it: MEF is cool as ICE!

    kick it on DotNetKicks.com

    Imagine the following:

    You want to construct a shed somewhere in your back yard. There’s tools to accomplish that, such as a hammer and a saw. There’s also material, such as nails and wooden boards.

    Let’s go for this! Here’s a piece of code to build the shed:

    public class Maarten
    {
        public void Execute(string command)
        {
            if (command == “build-a-shed”)
            {
              List<ITool> tools = new List<ITool>
              {
                new Hammer(),
                new Saw()
              };

              List<IMaterial> material = new List<IMaterial>
              {
                new BoxOfNails(),
                new WoodenBoards()
              };

              BuildAShedCommand task = new BuildAShedCommand(tools, material);
              task.Execute();
            }
        }
    }

    That’s a lot of work, building a shed! Imagine you had someone to do the above for you, someone who gathers your tools spread around somewhere in the house, goes to the DIY-store and gets a box of nails, … This is where MEF comes in to place.

    Compose

    Let’s start with the last component of the MEF paradigm: composition. Let’s not look for tools in the garage (and the attic), let’s not go to the DIY store, let’s “outsource” this task to someone cheap: MEF. Cheap because it will be in .NET 4.0, not because it’s, well, “cheap”. Here’s how the outsourcing would be done:

    public class Maarten
    {
        public void Execute(string command)
        {
            if (command == “build-a-shed”)
            {
              // Tell MEF to look for stuff in my house, maybe I still have nails and wooden boards as well
              AssemblyCatalog catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
              CompositionContainer container = new CompositionContainer(catalog);

              // Start the job, and ask MEF to find my tools and material
              BuildAShedCommand task = new BuildAShedCommand();
              container.ComposeParts(task);
              task.Execute();
            }
        }
    }

    Cleaner, no? The only thing I have to do is start the job, which is more fun when my tools and material are in reach. The ComposeParts() call figures out where my tools and material are. However, MEF's stable composition promise will only do that if it can find ("satisfy") all required imports. And MEF will not know all of this automatically. Tools and material should be labeled. And that’s where the next word comes in play: export.

    Export

    Export, or the ExportAttribute to be precise, is a marker for MEF to tell that you want to export the type or property on which the attribute is placed. Really think of it like a label. Let’s label our hammer:

    [Export(typeof(ITool))]
    public class Hammer : ITool
    {
      // ...
    }

    The same should be done for the saw, the box of nails and the wooden boards. Remember to put a different label color on the tools and the material, otherwise MEF will think that sawing should be done with a box of nails.

    Import

    Of course, MEF can go ahead and gather tools and material, but it will not know what to do with it unless you give it a hint. And that’s where the ImportAttribute (and the ImportManyAttribute) come in handy. I will have to tell MEF that the tools go on one stack, the material goes on another one. Here’s how:

    public class BuildAShedCommand : ICommand
    {
      [ImportMany(typeof(ITool))]
      public IEnumerable<ITool> Tools { get; set; }

      [ImportMany(typeof(IMaterial))]
      public IEnumerable<IMaterial> Materials { get; set; }

      // ...
    }

    Conclusion

    Easy, no? Of course, MEF can do a lot more than this. For instance, you can specify that a certain import is only valid for exports of a specific type and specific metadata: I can have a small and a large hammer, both ITool. For building a shed, I will require the large hammer though.

    Another cool feature is creating your own export provider (example at TheCodeJunkie.com). And if ICE does not make sense, try the Zoo example.

    kick it on DotNetKicks.com


    PHPMEF 0.1.0 released!

    PHP MEF A while ago, I did a conceptual blog post on PHP Managed Extensibility Framework – PHPMEF. Today, I’m proud to announce the first public release of PHPMEF! After PHPExcel, PHPLinq, PHPPowerPoint and the Windows Azure SDK for PHP, PHPMEF is the 5th open-source project I started on interoperability (or conceptual interoperability) between the Microsoft world and the PHP world. Noble price for peace upcoming :-)

    What is this thing?

    PHPMEF is a PHP port of the .NET Managed Extensibility Framework, allowing easy composition and extensibility in an application using the Inversion of Control principle and 2 easy keywords: @export and @import.

    PHPMEF is based on a .NET library, MEF, targeting extensibility of projects. It allows you to declaratively extend your application instead of requiring you to do a lot of plumbing. All this is done with three concepts in mind: export, import and compose. “PHPMEF” uses the same concepts in order to provide this extensibility features.

    Show me an example!

    Ok, I will. But not here. Head over to http://phpmef.codeplex.com and have a look at the principles and features behind PHPMEF.

    Enjoy!


    Categories: C# | General | MEF | PHP | Projects

    PHP Managed Extensibility Framework – PHPMEF

    image While flying sitting in the airplane to the Microsoft Web Developer Summit in Seattle, I was watching some PDC09 sessions on my laptop. During the MEF session, an idea popped up: there is no MEF for PHP! 3500 kilometers after that moment, PHP got its own MEF…

    What is MEF about?

    MEF is a .NET library, targeting extensibility of projects. It allows you to declaratively extend your application instead of requiring you to do a lot of plumbing. All this is done with three concepts in mind: export, import and compose. (Glenn, I stole the previous sentence from your blog). “PHPMEF” uses the same concepts in order to provide this extensibility features.

    Let’s start with a story… Imagine you are building a Calculator. Yes, shoot me, this is not a sexy sample. Remember I wrote this one a plane with snoring people next to me…The Calculator is built of zero or more ICalculationFunction instances. Think command pattern. Here’s how such an interface can look like:

    interface ICalculationFunction
    {
        public function execute($a, $b);
    }

    Nothing special yet. Now let’s implement an instance which does sums:

    class Sum implements ICalculationFunction
    {
        public function execute($a, $b)
        {
            return $a + $b;
        }
    }

    Now how would you go about using this in the following Calculator class:

    class Calculator
    {
        public $CalculationFunctions;
    }

    Yes, you would do plumbing. Either instantiating the Sum object and adding it into the Calculator constructor, or something similar. Imagine you also have a Division object. And other calculation functions. How would you go about building this in a maintainable and extensible way? Easy: use exports…

    Export

    Exports are one of the three fundaments of PHPMEF. Basically, you can specify that you want class X to be “ exported”  for extensibility. Let’s export Sum:

    /**
      * @export ICalculationFunction
      */

    class Sum implements ICalculationFunction
    {
        public function execute($a, $b)
        {
            return $a + $b;
        }
    }

    Sum is exported as Sum by default, but in this case I want PHPMEF to know that it is also exported as ICalculationFunction. Let’s see why this is in the import part…

    Import

    Import is a concept required for PHPMEF to know where to instantiate specific objects. Here’s an example:

    class Calculator
    {
        /**
          * @import ICalculationFunction
          */

        public $SomeFunction;
    }

    In this case, PHPMEF will simply instantiate the first ICalculationFunction instance it can find and assign it to the Calculator::SomeFunction variable. Now think of our first example: we want different calculation functions in our calculator! Here’s how:

    class Calculator
    {
        /**
          *  @import-many ICalculationFunction
          */

        public $CalculationFunctions;
    }

    Easy, no? PHPMEF will ensure that all possible ICalculationFunction instances are added to the Calculator::CalculationFunctions array. Now how is all this being plumbed together? It’s not plumbed! It’s composed!

    Compose

    Composing matches all exports and imports in a specific application path. How? Easy! Use the PartInitializer!

    // Create new Calculator instance
    $calculator = new Calculator();

    // Satisfy dynamic imports
    $partInitializer = new Microsoft_MEF_PartInitializer();
    $partInitializer->satisfyImports($calculator);

    Easy, no? Ask the PartInitializer to satisfy all imports and you are done!

    Advanced usage scenarios

    The above sample was used to demonstrate what PHPMEF is all about. I’m sure you can imagine more complex scenarios. Here are some other possibilities…

    Single instance exports

    By default, PHPMEF instantiates a new object every time an import has to be satisfied. However, imagine you want our Sum class to be re-used. You want PHPMEF to assign the same instance over and over again, no matter where and how much it is being imported. Again, no plumbing. Just add a declarative comment:

    /**
      * @export ICalculationFunction
      * @export-metadata singleinstance
      */

    class Sum implements ICalculationFunction
    {
        public function execute($a, $b)
        {
            return $a + $b;
        }
    }

    Export/import metadata

    Imagine you want to work with interfaces like mentioned above, but want to use a specific implementation that has certain metadata defined. Again: easy and no plumbing!

    My calculator might look like the following:

    class Calculator
    {
        /**
          *  @import-many ICalculationFunction
          */

        public $CalculationFunctions;

        /**
          *  @import ICalculationFunction
          *  @import-metadata CanDoSums
          */

        public $SomethingThatCanDoSums;
    }

    Calculator::SomeThingThatCanDoSums is now constrained: I only want to import something that has the metadata “CanDoSums” attached. Here’s how to create such an export:

    /**
      * @export ICalculationFunction
      * @export-metadata CanDoSums
      */

    class Sum implements ICalculationFunction
    {
        public function execute($a, $b)
        {
            return $a + $b;
        }
    }

    Here’s an answer to a question you may have: yes, multiple metadata definitions are possible and will be used to determine if an export matches an import.

    One small note left: you can also ask the PartInitializer for the metadata defined on a class.

    // Create new Calculator instance
    $calculator = new Calculator();

    // Satisfy dynamic imports
    $partInitializer = new Microsoft_MEF_PartInitializer();
    $partInitializer->satisfyImports($calculator);

    // Get metadata
    $metadata = $partInitializer->getMetadataForClass('Sum');

    Can I get the source?

    No, not yet. For a number of reasons. I first want to make this thing a bit more stable, as well as deciding if all MEF features should be ported. Also, I’m looking for an appropriate name/library to put this in. You may have noticed the Microsoft_* naming, a small hint to the Interop team in incorporating this as another Microsoft library in the PHP world. Yes Vijay, talking to you :-)


    Categories: General | MEF | PHP | Projects | Software

    Revised: ASP.NET MVC and the Managed Extensibility Framework (MEF)

    A while ago, I did a blog post on combining ASP.NET MVC and MEF (Managed Extensibility Framework), making it possible to “plug” controllers and views into your application as a module. I received a lot of positive feedback as well as a hard question from Dan Swatik who was experiencing a Server Error with this approach… Here’s a better approach to ASP.NET MVC and MEF.

    kick it on DotNetKicks.com

    The Exception

    Server Error

    The stack trace was being quite verbose on this one:

    InvalidOperationException

    The view at '~/Plugins/Views/Demo/Index.aspx' must derive from ViewPage, ViewPage<TViewData>, ViewUserControl, or ViewUserControl<TViewData>.

    at System.Web.Mvc.WebFormView.Render(ViewContext viewContext, TextWriter writer) at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass11.<InvokeActionResultWithFilters>b__e() at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass11.<>c__DisplayClass13.<InvokeActionResultWithFilters>b__10() at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters, ActionResult actionResult) at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) at System.Web.Mvc.Controller.ExecuteCore() at System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) at System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContextBase httpContext) at System.Web.Mvc.MvcHandler.ProcessRequest(HttpContext httpContext) at System.Web.Mvc.MvcHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext httpContext) at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

    Our exception seemed to be thrown ONLY when the following conditions were met:

    • The View was NOT located in ~/Views but in ~/Plugins/Views (or other path)
    • The View created in our MEF plugin was strong-typed

    Problem one… Forgot to register ViewTypeParserFilter…

    Allright, go calling me stupid… Our ~/Plugins/Views folder was not containing the following Web.config file:

    <?xml version="1.0"?>
    <configuration>
      <system.web>
        <httpHandlers>
          <add path="*" verb="*"
              type="System.Web.HttpNotFoundHandler"/>
        </httpHandlers>

        <!--
            Enabling request validation in view pages would cause validation to occur
            after the input has already been processed by the controller. By default
            MVC performs request validation before a controller processes the input.
            To change this behavior apply the ValidateInputAttribute to a
            controller or action.
        -->
        <pages
            validateRequest="false"
            pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
            pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
            userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
          <controls>
            <add assembly="System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
          </controls>
        </pages>
      </system.web>

      <system.webServer>
        <validation validateIntegratedModeConfiguration="false"/>
        <handlers>
          <remove name="BlockViewHandler"/>
          <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler"/>
        </handlers>
      </system.webServer>
    </configuration>

    Now why would you need this one anyway? Well: first of all, you do not want your views to expose their source code. Therefore, we add the HttpNotFoundHandler for this folder. Next, we do not want request validation to happen again (because this is already done when invoking the controller). Next: we want the MvcViewTypeParserFilter to be used for enabling strong-typed views (more on this by Phil Haack).

    Problem two: MEF’s approach to plugins and ASP.NET’s approach to rendering views…

    When compiling a view, ASP.NET dynamically compiles the markup into a temporary assembly, after which it is rendered. This compilation process knows only the assemblies loaded by your web application’s AppDomain. Unfortunately, assemblies loaded by MEF are not available for this compilation process… I went ahead and checked with Reflector if we could do something about this on ASP.NET side: nope. The main classes we need for this are internal :-( The MEF side could be easily tweaked since its source code is available on CodePlex, but… it’s still subject to change and will be included in .NET 4.0 as a framework component, which would limit my customizations a bit for the future.

    Now let’s describe this problem as one, simple sentence: we need the MEF plugin assembly loaded in our current AppDomain, available for all other components in the web application.

    The solution to this: I want a MEF DirectoryCatalog to monitor my plugins folder and load/unload the assemblies in there dynamically. Loading should be no problem, but unloading… The assemblies will always be locked by my web server’s process! So let’s go for another approach: monitor the plugins folder, copy the new/modified assemblies to the web application’s /bin folder and instruct MEF to load its exports from there. The solution: WebServerDirectoryCatalog. Here’s the code:

    public sealed class WebServerDirectoryCatalog : ComposablePartCatalog
    {
        private FileSystemWatcher fileSystemWatcher;
        private DirectoryCatalog directoryCatalog;
        private string path;
        private string extension;

        public WebServerDirectoryCatalog(string path, string extension, string modulePattern)
        {
            Initialize(path, extension, modulePattern);
        }

        private void Initialize(string path, string extension, string modulePattern)
        {
            this.path = path;
            this.extension = extension;

            fileSystemWatcher = new FileSystemWatcher(path, modulePattern);
            fileSystemWatcher.Changed += new FileSystemEventHandler(fileSystemWatcher_Changed);
            fileSystemWatcher.Created += new FileSystemEventHandler(fileSystemWatcher_Created);
            fileSystemWatcher.Deleted += new FileSystemEventHandler(fileSystemWatcher_Deleted);
            fileSystemWatcher.Renamed += new RenamedEventHandler(fileSystemWatcher_Renamed);
            fileSystemWatcher.IncludeSubdirectories = false;
            fileSystemWatcher.EnableRaisingEvents = true;

            Refresh();
        }

        void fileSystemWatcher_Renamed(object sender, RenamedEventArgs e)
        {
            RemoveFromBin(e.OldName);
            Refresh();
        }

        void fileSystemWatcher_Deleted(object sender, FileSystemEventArgs e)
        {
            RemoveFromBin(e.Name);
            Refresh();
        }

        void fileSystemWatcher_Created(object sender, FileSystemEventArgs e)
        {
            Refresh();
        }

        void fileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            Refresh();
        }

        private void Refresh()
        {
            // Determine /bin path
            string binPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin");

            // Copy files to /bin
            foreach (string file in Directory.GetFiles(path, extension, SearchOption.TopDirectoryOnly))
            {
                try
                {
                    File.Copy(file, Path.Combine(binPath, Path.GetFileName(file)), true);
                }
                catch
                {
                    // Not that big deal... Blog readers will probably kill me for this bit of code :-)
                }
            }

            // Create new directory catalog
            directoryCatalog = new DirectoryCatalog(binPath, extension);
        }

        public override IQueryable<ComposablePartDefinition> Parts
        {
            get { return directoryCatalog.Parts; }
        }

        private void RemoveFromBin(string name)
        {
            string binPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin");
            File.Delete(Path.Combine(binPath, name));
        }
    }

    Download the example code

    First of all: this was tricky, and the solution to it is also a bit tricky. Use at your own risk!

    You can download the example code here: RevisedMvcMefDemo.zip (1.03 mb)

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | Debugging | General | MEF | MVC | Personal

    ASP.NET MVC and the Managed Extensibility Framework (MEF)

    Microsoft’s Managed Extensibility Framework (MEF) is a .NET library (released on CodePlex) that enables greater re-use of application components. You can do this by dynamically composing your application based on a set of classes and methods that can be combined at runtime. Think of it like building an appliation that can host plugins, which in turn can also be composed of different plugins. Since examples say a thousand times more than text, let’s go ahead with a sample leveraging MEF in an ASP.NET MVC web application.

    kick it on DotNetKicks.com

    Getting started…

    The Managed Extensibility Framework can be downloaded from the CodePlex website. In the download, you’ll find the full source code, binaries and some examples demonstrating different use cases for MEF.

    Now here’s what we are going to build: an ASP.NET MVC application consisting of typical components (model, view, controller), containing a folder “Plugins” in which you can dynamically add more models, views and controllers using MEF. Schematically:

    Sample Application Architecture

    Creating a first plugin

    Before we build our host application, let’s first create a plugin. Create a new class library in Visual Studio, add a reference to the MEF assembly (System.ComponentModel.Composition.dll) and to System.Web.Mvc and System.Web.Abstractions. Next, create the following project structure:

    Sample Plugin Project

    That is right: a DemoController and a Views folder containing a Demo folder containing Index.aspx view. Looks a bit like a regular ASP.NET MVC application, no? Anyway, the DemoController class looks like this:

    [Export(typeof(IController))]
    [ExportMetadata("controllerName", "Demo")]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class DemoController : Controller
    {
        public ActionResult Index()
        {
            return View("~/Plugins/Views/Demo/Index.aspx");
        }
    }

    Nothing special, except… what are those three attributes doing there, Export and PartCreationPolicy? In short:

    • Export tells the MEF framework that our DemoController class implements the IController contract and can be used when the host application is requesting an IController implementation.
    • ExportMetaData provides some metadata to the MEF, which can be used to query plugins afterwards.
    • PartCreationPolicy tells the MEF framework that it should always create a new instance of DemoController whenever we require this type of controller. By defaukt, a single instance would be shared across the application which is not what we want here. CreationPolicy.NonShared tells MEF to create a new instance every time.

    Now we are ready to go to our host application, in which this plugin will be hosted.

    Creating our host application

    The ASP.NET MVC application hosting these plugin controllers is a regular ASP.NET MVC application, in which we’ll add a reference to the MEF assembly (System.ComponentModel.Composition.dll). Next, edit the Global.asax.cs file and add the following code in Application_Start:

    ControllerBuilder.Current.SetControllerFactory(
        new MefControllerFactory(
            Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Plugins")));

    What we are doing here is telling the ASP.NET MVC framework to create controller instances by using the MefControllerFactory instead of ASP.NET MVC’s default DefaultControllerFactory. Remember that everyone’s always telling ASP.NET MVC is very extensible, and it is: we are now changing a core component of ASP.NET MVC to use our custom MefControllerFactory class. We’re also telling our own MefControllerFactory class to check the “Plugins” folder in our web application for new plugins. By the way, here’s the code for the MefControllerFactory:

    public class MefControllerFactory : IControllerFactory
    {
        private string pluginPath;
        private DirectoryCatalog catalog;
        private CompositionContainer container;

        private DefaultControllerFactory defaultControllerFactory;

        public MefControllerFactory(string pluginPath)
        {
            this.pluginPath = pluginPath;
            this.catalog = new DirectoryCatalog(pluginPath);
            this.container = new CompositionContainer(catalog);

            this.defaultControllerFactory = new DefaultControllerFactory();
        }

        #region IControllerFactory Members

        public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            IController controller = null;

            if (controllerName != null)
            {
                string controllerClassName = controllerName + "Controller";
                Export<IController> export = this.container.GetExports<IController>()
                                                 .Where(c => c.Metadata.ContainsKey("controllerName")
                                                     && c.Metadata["controllerName"].ToString() == controllerName)
                                                 .FirstOrDefault();
                if (export != null) {
                    controller = export.GetExportedObject();
                }
            }

            if (controller == null)
            {
                return this.defaultControllerFactory.CreateController(requestContext, controllerName);
            }

            return controller;
        }

        public void ReleaseController(IController controller)
        {
            IDisposable disposable = controller as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }

        #endregion
    }

    Too much? Time for a breakdown. Let’s start with the constructor:

    public MefControllerFactory(string pluginPath)
    {
        this.pluginPath = pluginPath;
        this.catalog = new DirectoryCatalog(pluginPath);
        this.container = new CompositionContainer(catalog);

        this.defaultControllerFactory = new DefaultControllerFactory();
    }

    In the constructor, we are storing the path where plugins can be found (the “Plugins” folder in our web application). Next, we are telling MEF to create a catalog of plugins based on what it can find in that folder using the DirectoryCatalog class. Afterwards, a CompositionContainer is created which will be responsible for matching plugins in our application.

    Next, the CreateController method we need to implement for IControllerFactory:

    public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        IController controller = null;

        if (controllerName != null)
        {
            string controllerClassName = controllerName + "Controller"
            Export<IController> export = this.container.GetExports<IController>()
                                             .Where(c => c.Metadata.ContainsKey("controllerName"
                                                 && c.Metadata["controllerName"].ToString() == controllerName)
                                             .FirstOrDefault();
            if (export != null) {
                controller = export.GetExportedObject();
            }
        }

        if (controller == null)
        {
            return this.defaultControllerFactory.CreateController(requestContext, controllerName);
        }

        return controller;
    }

    This method handles the creation of a controller, based on the current request context and the controller name that is required. What we are doing here is checking MEF’s container for all “Exports” (plugins as you wish) that match the controller name. If one is found, we return that one. If not, we’re falling back to ASP.NET MVC’s DefaultControllerBuilder.

    The ReleaseController method is not really exciting: it's used by ASP.NET MVC to correctly dispose a controller after use.

    Running the sample

    First of all, the sample code can be downloaded here: MvcMefDemo.zip (270.82 kb)

    When launching the application, you’ll notice nothing funny. That is, untill you want to navigate to the http://localhost:xxxx/Demo URL: there is no DemoController to handle that request! Now compile the plugin we’ve just created (in the MvcMefDemo.Plugins.Sample project) and copy the contents from the \bin\Debug folder to the \Plugins folder of our host application. Now, when the application restarts (for example by modifying web.config), the plugin will be picked up and the http://localhost:xxxx/Demo URL will render the contents from our DemoController plugin:

    Sample run MEF ASP.NET MVC

    Conclusion

    The MEF (Managed Extensibility Framework) offers a rich manner to dynamically composing applications. Not only does it allow you to create a plugin based on a class, it also allows exporting methods and even properties as a plugin (see the samples in the CodePlex download).

    By the way, sample code can be downloaded here: MvcMefDemo.zip (270.82 kb)

    kick it on DotNetKicks.com


    Categories: ASP.NET | C# | General | MEF | MVC | Quality code