Adding Dependency Injection to your ASP.NET MVC Twilio app using MEF (Managed Extensibility Framework)

Adding Dependency Injection to your ASP.NET MVC Twilio app using MEF (Managed Extensibility Framework)

http://www.twilio.com/blog/2012/11/adding-dependency-injection-to-your-asp-net-mvc-twilio-app-using-mef.html

Thanks for the Reblog Twilio!

IoC, Dependency Injection, Manage Extensiblity Framework (MEF), ServiceLocator in .NET 4, MVC 4, WebApi, IDependencyResolver with Closed Types e.g. Twilio Types

Being accustomed to writing Mvc apps with IoC, specifically with Ninject and Managed Extensibility Framework (Mef), I wanted to see how we could inject most our Twilio instances (types TwilioResponse and the TwilioRestClient) when using them in my Mvc 4 WebApi Controller Actions.

To “Mefify” your Mvc 4 .NET 4.0 app, download the Mvc4.Mef project and reference this in your web app.

Let’s quickly review some of important classes in this project (Mvc.Mef) that do the heavy lifting to wire up Mef in your Mvc app.

  1. MefMvcConfig.cs

    • Creating our CompositionContainer, the container that holds all our exports and imports.
    • AggregateCatalog, which is a collection of catalogs, in our case composed of a ComposableCatalog (we pass in a TypeCatalog later from our our Mvc app, which inherits the Composable Catalog) and DirectoryCatalog which are of the possible classes that are decorated with [Export] and [Import] attributes from the current executing assembly as well as another other assemblies that maybe in the bin from our other projects.

    Note: The RegisterMef method will be invoked from your Application_Start(), Global.asax.cs class to wire integrate and wire up Mef into your Mvc app.

    
        public static class MefMvcConfig
        {
            public static void RegisterMef(TypeCatalog typeCatalog)
            {
                var compositionContainer = ConfigureContainer(typeCatalog);
                ServiceLocator
                    .SetLocatorProvider(() => new MefServiceLocator(compositionContainer));
    
                ControllerBuilder
                    .Current.SetControllerFactory(
                    new MefMvcControllerFactory(compositionContainer));
    
                GlobalConfiguration
                    .Configuration
                    .DependencyResolver = 
                    new MefMvcDependencyResolver(compositionContainer);
            }
    
            private static CompositionContainer ConfigureContainer(
                ComposablePartCatalog composablePartCatalog)
            {
                var path = HostingEnvironment.MapPath("~/bin");
                if (path == null) throw new Exception("Unable to find the path");
    
                var aggregateCatalog = new AggregateCatalog(new DirectoryCatalog(path));
    
                if (composablePartCatalog != null)
                    aggregateCatalog.Catalogs.Add(composablePartCatalog);
    
                return new CompositionContainer(
                    aggregateCatalog,
                    new MefNameValueCollectionExportProvider(
                        ConfigurationManager.AppSettings));
            }
        }
    
  2. MefMvcControllerFactory.cs, which inherits the Overriding and setting the default Mvc ControllerFactory with our own that we use our DefaultControllerFactory, the MefMvcControllerFactory is used to scan our CompositionContainer when attempting to resolve Controller types.
    
        public class MefMvcControllerFactory : DefaultControllerFactory
        {
            private readonly CompositionContainer _compositionContainer;
    
            public MefMvcControllerFactory(CompositionContainer compositionContainer)
            {
                _compositionContainer = compositionContainer;
            }
    
            protected override IController GetControllerInstance(
                RequestContext requestContext, Type controllerType)
            {
                var export = _compositionContainer
                    .GetExports(controllerType, null, null).SingleOrDefault();
    
                IController result;
    
                if (null != export)
                    result = export.Value as IController;
                else
                {
                    result = base.GetControllerInstance(requestContext, controllerType);
                    _compositionContainer.ComposeParts(result);
                }
    
                return result;
            }
    
    
    
  3. MefMvcDependencyResolver.cs, which is used, when we override and the default Mvc DependencyResolver, so that when there are dependencies in our WebApi Controllers, the Mvc runtime will use our own MefMvcDependencyResolver to resolve those dependencies
    
        public class MefMvcDependencyResolver : IDependencyResolver
        {
            private readonly CompositionContainer _compositionContainer;
    
            public MefMvcDependencyResolver(CompositionContainer compositionContainer)
            {
                _compositionContainer = compositionContainer;
            }
    
            #region IDependencyResolver Members
    
            public IDependencyScope BeginScope()
            {
                return this;
            }
    
            public object GetService(Type type)
            {
                var export = _compositionContainer
                    .GetExports(type, null, null).SingleOrDefault();
    
                return null != export ? export.Value : null;
            }
    
            public IEnumerable<object> GetServices(Type type)
            {
                var exports = _compositionContainer.GetExports(type, null, null);
                var exportList = new List<object>();
                if (exports.Any()) exportList.AddRange(exports.Select(export => export.Value));
                return exportList;
            }
    
            public void Dispose()
            {
            }
    
            #endregion
        }
    
    
    
  4. MefNameValueCollectionExportProvider.cs, which enables us to load in to our CompositionContainer our Web.config AppSettings key and values in the case we want to resolve them with injection e.g. Twilio AccountSid and AuthoToken from our Web.config AppSettings.
    
        public class MefNameValueCollectionExportProvider : ExportProvider
        {
            private readonly List<Export> _exports;
    
            public MefNameValueCollectionExportProvider(NameValueCollection settings)
            {
                _exports = new List<Export>();
    
                foreach (string key in settings)
                {
                    var metadata = new Dictionary<string, object> {
                        {
                            CompositionConstants
                            .ExportTypeIdentityMetadataName, typeof (string)
                            .FullName
                        }};
    
                    var exportDefinition = new ExportDefinition(key, metadata);
    
                    _exports.Add(new Export(exportDefinition, () => settings[key]));
                }
            }
    
            protected override IEnumerable<Export> GetExportsCore(
                ImportDefinition importDefinition, AtomicComposition atomicComposition)
            {
                return _exports
                    .Where(x => importDefinition.IsConstraintSatisfiedBy(x.Definition));
            }
        }
    
    
  5. MefAdapter.cs, which is based from Mark Seemaan’s blog on Resolving Close Types with Mef, this class will be used so that we can add close classes/objects, which we cannot annotate with the [Export] and/or [Import] attributes, in this example I will demonstrate this with Twilio’s objects.

    
        public class MefAdapter<T> where T : new()
        {
            private readonly T _typeToExport;
    
            public MefAdapter()
            {
                _typeToExport = new T();
            }
    
            [Export]
            public virtual T TypeToExport
            {
                get { return _typeToExport; }
            }
        }
    
        public class MefAdapter<T1, T2, TResult>
        {
            private static readonly Func<T1, T2, TResult> 
                CreateExport = Create<T1, T2, TResult>();
    
            private readonly TResult _typeToExport;
    
            [ImportingConstructor]
            public MefAdapter(T1 arg1, T2 arg2)
            {
                _typeToExport = CreateExport(arg1, arg2);
            }
    
            [Export]
            public virtual TResult TypeToExport
            {
                get { return _typeToExport; }
            }
    
            internal static Func<T1, T2, TResult> Create<T1, T2, TResult>()
            {
                var constructorArgExpression1 = Expression.Parameter(typeof (T1), "arg1");
                var constructorArgExpression2 = Expression.Parameter(typeof (T2), "arg2");
    
                var constructorInfo = typeof (TResult).GetConstructor(new[]
                        {
                            typeof (T1),
                            typeof (T2)
                        });
    
                var constructorExpression = Expression
                    .New(constructorInfo, constructorArgExpression1, constructorArgExpression2);
    
                return Expression.Lambda<Func<T1, T2, TResult>>(
                    constructorExpression, 
                    constructorArgExpression1, 
                    constructorArgExpression2)
                    .Compile();
            }
        }
    

Now switching to your Mvc 4 app, here are the simple steps to wire this up, first few steps is to simply NuGet CommonServiceLocator, using this we obviously will also be practicing the ServiceLocator Pattern.

Now, download the Mvc4.Mef.Framework project, and reference it in your MVC 4 application and add one line to your Global.asax.cs file to get this all setup. Since we are here let’s go ahead and add some UriPathExtensionMapping configurations so that we can serve up some real Twilio request later on to demonstrate Dependency Injection with the TwilioRequest object from their Api, these UriPathExtensionMappings are not required for Mef’ing your Mvc app.

Note: notice that we are passing in a TypeCatalog when we invoke the RegisterMef method, this is so that we can pass in closed classes (types) that we would like to inject or resolve with Dependency Injection using Mef in this case the TwilioResponse object from their Api.

Global.asax.cs


    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            MefMvcConfig.RegisterMef(new TypeCatalog(typeof(MefAdapter<TwilioResponse>)));

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            GlobalConfiguration
                .Configuration.Formatters
                .XmlFormatter
                .AddUriPathExtensionMapping("xml", "text/xml");

            GlobalConfiguration
                .Configuration
                .Formatters
                .XmlFormatter
                .AddUriPathExtensionMapping("json", "application/json");
        }
    }

Now if we run our app you should see that the request from the HomeController is now getting resolved through our MefMvcControllerFactory from our CompositionContainer. In this screenshot, I’ve pinned the watch to source (Visual Studio 2012) to illustrate that the Controller type that is being succesfully resolved with DependencyInjection is indeed the HomeController.

In order for Mef to serve up and resolve these Controllers we have to decorate our controllers with the [Export] attribute e.g. HomeController.

Note: The [PartCreationPolicy(CreationPolicy.NonShared)], means that whenever this instance is requested, Mef will new up (instantiate) a new instance every time, the opposite would be CreationPolicy.Shared, which will new one up the first time and keep it alive, and serve this same instance, every time it is requested (which is the behavior we don’t want for Mvc Controllers).


    [Export]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Message = 
                "Modify this template to jump-start your ASP.NET MVC application.";

            return View();
        }

        public ActionResult About()
        {
            ViewBag.Message = "Your app description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }
}

Now for the fun part, this Mvc 4 project is from one of my previous blogs Multi-Step (Two-Factor) ASP.NET MVC 4 Registration with SMS using Twilio Cloud Communication and SimpleMembershipProvider for Increased User Validity, where we were using TwilioRestClient from their Api to send SMS messages for Two-Factor registration. Let’s see how we can inject this now with Mef in our Register Action.

Before:


        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                // Attempt to register the user
                try
                {
                    var smsVerificationCode =
                        GenerateSimpleSmsVerificationCode();

                    WebSecurity.CreateUserAndAccount(
                        model.UserName,
                        model.Password,
                        new
                            {
                                model.Mobile,
                                IsSmsVerified = false,
                                SmsVerificationCode = smsVerificationCode
                            },
                        true);

                    var twilioRestClient = new TwilioRestClient(
                        ConfigurationManager.AppSettings.Get("Twilio:AccoundSid"),
                        ConfigurationManager.AppSettings.Get("Twilio:AuthToken"));

                    twilioRestClient.SendSmsMessage(
                        "+19722001298",
                        model.Mobile,
                        string.Format(
                            "Your ASP.NET MVC 4 with Twilio " +
                            "registration verification code is: {0}",
                            smsVerificationCode)
                        );

                    Session["registrationModel"] = model;

                    return RedirectToAction("SmsVerification", "Account", model);
                }
                catch (MembershipCreateUserException e)
                {
                    ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

After:


        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public ActionResult Register(RegisterModel model)
        {
            if (ModelState.IsValid)
            {
                // Attempt to register the user
                try
                {
                    var smsVerificationCode =
                        GenerateSimpleSmsVerificationCode();

                    WebSecurity.CreateUserAndAccount(
                        model.UserName,
                        model.Password,
                        new
                            {
                                model.Mobile,
                                IsSmsVerified = false,
                                SmsVerificationCode = smsVerificationCode
                            },
                        true);

                    var twilioRestClient = ServiceLocator.Current.GetInstance<TwilioRestClient>();

                    twilioRestClient.SendSmsMessage(
                        "+19722001298",
                        model.Mobile,
                        string.Format(
                            "Your ASP.NET MVC 4 with Twilio " +
                            "registration verification code is: {0}",
                            smsVerificationCode)
                        );

                    Session["registrationModel"] = model;

                    return RedirectToAction("SmsVerification", "Account", model);
                }
                catch (MembershipCreateUserException e)
                {
                    ModelState.AddModelError("", ErrorCodeToString(e.StatusCode));
                }
            }

            // If we got this far, something failed, redisplay form
            return View(model);
        }

Notice in line 25, we are now using ServiceLocator to resolve the dependency in our Register action for the TwilioRestClient. Here Mef will take care of activating and setting up our TwilioRestClient instance for us.

Ideally we would want to wrap (Composition Pattern) the TwilioRestClient, implementing our own interface and injecting the interface with our wrapped TWilioRestClient. If time permits, I’ll cover this in another post, for now we’ll just have fun with injecting closed classes with Mef.

Let’s see the TwilioRestClient injection with ServiceLocator in action by running the app and registering.

Register View

Debugging in our Register Action from the AccountController, notice how our TwilioRestClient is successfully being activated, injected and resolved with the ServiceLocator, which really is just scanning our CompositionContainer we had setup earlier, which was made possible with our TwilioRestClientMefAdapter.

Great! We received a test SMS text message with our injected TwilioRestClient.

How did this happen? Will we had to create a TwilioRestClientMefAdapter (this is a variation of the Adapter Pattern) class, this was needed because the TwilioRestClient does not have parameterless constructor, and those parameters were our Twilio AccountSid and AuthToken which were in our Web.config.


    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class TwilioRestClientMefAdapter
    {
        private readonly TwilioRestClient _twilioRestClient;

        [ImportingConstructor]
        public TwilioRestClientMefAdapter(
            [Import("Twilio:AccoundSid")] string accountSid,
            [Import("Twilio:AuthToken")] string authToken)
        {
            _twilioRestClient = new TwilioRestClient(accountSid, authToken);
        }

        [Export]
        public TwilioRestClient TwilioRestClient
        {
            get { return _twilioRestClient; }
        }
    }

Let’s debug the activation process, just to understand what’s happening here.

Now, when we inject our TwilioRestClient with


var twilioRestClient = ServiceLocator.Current.GetInstance<TwilioRestClient>();

what’s happening is that, what’s marked for Export is the property named TwilioRestClient. In order for Mef to export that property it must instantiate the class that it lives in which in our case is the TwilioRestClientMefAdapter class. The constructor marked with [ImportingConstructor] is what Mef will scan for, to activate this class. In the constructor is where we are also injecting our AccountSid and AuthToken from our web.conf appSettings that was loaded earlier into our CompositionContainer using our MefNameValueCollectionExportProvider.cs class, where we passed in ConfigurationManager.AppSettings to our MefMvcConfig.ConfigureContainer method. Fortunately for us, the ConfigurationManager.AppSettings happens to be a NameValueCollection.


        private static CompositionContainer ConfigureContainer(
            ComposablePartCatalog composablePartCatalog)
        {
            var path = HostingEnvironment.MapPath("~/bin");
            if (path == null) throw new Exception("Unable to find the path");

            var aggregateCatalog = new AggregateCatalog(new DirectoryCatalog(path));

            if (composablePartCatalog != null)
                aggregateCatalog.Catalogs.Add(composablePartCatalog);

            return new CompositionContainer(
                aggregateCatalog,
                new MefNameValueCollectionExportProvider(
                    ConfigurationManager.AppSettings));
        }


Now, one more injection test with the TwilioResponse object, which is probably used most when developing with Twilio Cloud. We will test our WeatherController, which is pretty much a voice caller, calling in, being prompt to enter in their zip code and our our application telling the user what the weather is like for their zip. For this test we will need the Curl command line utility since it’s a WebApi method that will be invoked via a POST.

Let’s run, our app and test the pseudo WeatherController which we use an injected instance of the TwilioResponse. For this test, we will use the [Import] attribute to inject and activate our TwilioResponse vs. using the ServiceLocator. There’s no wrong or right way to get our instances activated, this is just preference.

Now lets run this command with Curl.

curl http://localhost:64190/api/weather/gatherzipcode.xml -X POST -d “fro
m=123”

With breakpoints setup, we can see that our TwilioResponse is being successfully activated and injected into our WeatherController using the [Import] attribute!

Our WebApi returns the required TwiML response.


<Response><Gather action="http://myapp.com/api/Weather/RetrieveWeather.xml" finishOnKey="#"><Say voice="woman">Please en
ter the zip code of the area you would like the weather in.</Say></Gather><Gather action="http://myapp.com/api/Weather/R
etrieveWeather.xml" finishOnKey="#"><Say voice="woman">Please enter the zip code of the area you would like the weather
in.</Say></Gather></Response>

How did our TwilioResponse object get resolved, activated and injected into our WeatherController? Well when we registered the Mef framework in our Global.asax.cs with:


MefMvcConfig.RegisterMef(new TypeCatalog(typeof(MefAdapter<TwilioResponse>)));

We passed in a TypeCatalog, and we initialized the TypeCatalog, passing in a list of types, in our case we are passing in our MefAdapter, that is used for the TwilioResponse type. This is because the TwilioResponse object is a closed object that we have no control over, and cannot decorate the class with any [Export] attributes.

Now let’s take a quick look at the internals of the MefAdapter, to understand how this is happening, it’s behavior is pretty similar to our TwilioRestClientAdapter we implemented earlier.


    public class MefAdapter<T> where T : new()
    {
        private readonly T _typeToExport;

        public MefAdapter()
        {
            _typeToExport = new T();
        }

        [Export]
        public virtual T TypeToExport
        {
            get { return _typeToExport; }
        }
    }

When we pass in the MefAdapter to our TypeCatalog, and we request an instance of T, Mef will new up our MefAdapter, by default use the parameterless constructor, which will new up an instance of T (which is TwilioResponse in our case), and now the TwilioResponse is initialized and passed back to our WeatherController.

Well, there we have it, integrating Mef into our .NET 4 Mvc 4 project, and injecting closed objects which we are unable to attribute with [Export] and/or [Import] attributes with our Mef adapters.

Happy Coding…! 🙂

Download sample solution: https://skydrive.live.com/redir?resid=949A1C97C2A17906!2391

Building a Composite MVC3 Application with Ninject

Update: 05/04/2012 – Preferred alternative approach without using IoC for Plugins (http://blog.longle.net/2012/03/29/building-a-composite-mvc3-application-with-pluggable-areas/).

So there’s great support in Prism to building composite applications with Silverlight with the notion of Prism modules. They have a nice discovery approach for dynamically discovering modules when loading XAPs and assemblies during runtime for all the different modules your Silverlight app may need. You can load them during start-up or on demand so that you don’t have to download the entire application at one time.

When building an enterprise MVC application, I wanted to borrow some of the ideas and architecture of the Prism extensible plug and play concepts to provide the ability to build modules (areas) of your MVC application outside of your core MVC application.

For example if you had a MVC application and it’s primary role is an E-Commerce site (core site), however you have this new requirement to build a integration point to show customers all their tracking statuses for their orders. Now you have to ramp up a development team as quick as possible so that they can build out this feature, however you now find yourself giving them a full blown training and overview of your core MVC application, full source control of your entire VS Solution set which could have up to 20-30 projects in it.

Now when devs from the team compile it’s taking forever…! Here we can easily see that our MVC app’s footprint is getting to large and somewhat difficult to manage. So here is now the need to break it down into blocks that can be injected into the app during runtime so that development for these different pieces, blocks, or modules can happen in parallel with your core MVC application (loose coupling, modularity and extensibility).

My preference here is to actually use Mef since I have experience with it and the great support for MVC3 and Mef now. However, I’ve been given the opportunity to be engaged on a project that uses Ninject. With this being the situation at hand I wanted to explore and see if we could borrow the some concepts from Prism, and incorporate them using what was out of the box with Ninject. Some of these concepts include separation of concerns and loosely coupled components (modules) that can evolve independently but can be easily and seamlessly integrated into the overall application, which is also known as a composite application.

With a little bit of Googling I stumbled upon this article http://www.thegecko.org/index.php/2010/06/pluggable-mvc-2-0-using-mef-and-strongly-typed-views/ which was pretty much what we were looking for however it just needed to be ported from MVC2 to MVC3, use Ninject instead of Mef and just a tad bit of polishing.

So after a little bit of poking around with Ninject, I quickly found that Ninject also has a notion of Modules, NinjectModules, or classes that implement the INinjectModule interface. You can ask the Ninject Kenerl (container) to scan an assembly and it will scan for all any classes that implement INinjectModule, this can be done directly by implementing the actual interface or inheriting their out of the box NinjectModule abstract class.

So rather than starting from ground zero here, I’m going to continue with the project from my last post http://blog.longle.net/2012/02/15/wrapping-the-ninject-kernel-with-servicelocator/.

Quick breakdown on the VS Solution structure:

  • MvcApplication

    This is our main MVC application which will host all the Plugins

  • MvcApplication.Plugin.Framework

    This is a C# class library where all the plugin infrastructure classes will reside

  • MvcApplicationA.Plugin

    Example PluginA

  • MvcApplicationA.Plugin

    Example PluginB

  • MvcApplicationA.Plugin

    Example PluginB

Let’s take a quick look at some of the classes in the MvcApplication.PluginFramework VS Project.

  • MyController.cs (implements IMyController)

    All controllers from plugins will need to inherit MyController, this provides some meta-data so that we can infer the correct type of a plugin Controller from our IoC that was requested.

  • MyPlugin.cs

    There will be one class in each plugin that must inherit MyPlugin, this class provides meta-data about the plugin, e.g. PluginName, AssemblyName, etc.. It also gives us the overidable Load operation where we can setup our Ninject bindings e.g. Controller and plugin bindings.

  • MyControllerFactory.cs

    We inherit the DefaultControllerFactory and override the GetControllerType method so that when a user is routed to a controller that is in a plugin, we can help the MVC runtime derive what it’s type is by scanning our IoC for registered instances for that a given Controller and return it’s type.

    
        public class MyControllerFactory : DefaultControllerFactory
        {
            protected override Type GetControllerType(RequestContext requestContext, 
                string controllerName)
            {
                var controllerType = base.GetControllerType(requestContext, controllerName);
    
                if (controllerType == null)
                {
                    var controller = ServiceLocator.Current.GetAllInstances<IController>().ToList()
                    .OfType<IMyController>()
                    .SingleOrDefault(c => c.ControllerName == controllerName);
    
                    if (controller != null)
                    {
                        return controller.GetType();
                    }
                }
    
                return controllerType;
            }
        }
    
    
  • MyRazorViewEngine (MyViewEngine.cs)

    Custom RazorViewEngine so that we can properly return Views *.cshtml (Razor) that have been copied to our Plugins directory in our main app (MvcApplication/Plugins).

  • MyWebFormEngine (MyViewEngine.cs)

    Custom WebFormViewEngine so that we can properly return MVC *.aspx (non-Razor) Views that have been copied to our Plugins directory in our main app (MvcApplication/Plugins).

  • MyPluginBootstrapper.cs and yes, I borrowed the name from Prism :p

    • Scans the “MvcApplication/Plugin” directory and loads all of our plugins
    • Register’s any custom routes from our plugins
    • Register’s our MyControllerFactory with the MVC runtime
    • Register’s our MyWebFormViewEngine with the MVC runtime
    • Register’s our MyRazorViewEngine with the MVC runtime
    
        public class MyPluginBootstrapper : NinjectModule
        {
            private const string _pluginPath = "Plugins";
            private readonly string _fullPluginPath;
            private const string _defaultMaster = "Site";
            private const string _defaultRazorMaster = "_Layout";
    
            public MyPluginBootstrapper()
            {
                _fullPluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, _pluginPath);
            }
    
            public override void Load()
            {
                var assemblies = new List<Assembly>();
    
                // Discover  Modules in plugin directory (e.g. site/plugins)
                foreach (var file in Directory.EnumerateFiles(_fullPluginPath, "*.Plugin.dll"))
                    assemblies.Add(Assembly.LoadFile(file));
    
                Kernel.Load(assemblies);
    
                //  plugins discovery
                var plugins = new List<IMyPlugin>();
                foreach (IMyPlugin plugin in ServiceLocator.Current.GetAllInstances<IMyPlugin>())
                {
                    plugins.Add(plugin);
                    plugin.RegisterRoutes(RouteTable.Routes);
                }
    
                // Register ControllerFactory with site
                IControllerFactory myControllerFactory = new MyControllerFactory();
                ControllerBuilder.Current.SetControllerFactory(myControllerFactory);
    
                // Setup ViewEngines
                var myWebFormViewEngine = 
                    new MyWebFormViewEngine(_pluginPath, plugins, _defaultMaster);
    
                var myRazorViewEngine = 
                    new MyRazorViewEngine(_pluginPath, plugins, _defaultRazorMaster);
    
                // Register ViewEngines with site
                ViewEngines.Engines.Clear();
                ViewEngines.Engines.Add(myWebFormViewEngine);
                ViewEngines.Engines.Add(myRazorViewEngine);            
            }
        }
    
    

So what’s all required to setup an MVC plugin now?

  1. Create a regular MVC3 app project to be the plugin
  2. Assembly name must match this pattern *.Plugin.dll, yes we are using convention for this.
  3. Must have one class that inherits MyPlugin.cs

    
        public class PluginA : MyPlugin
        {
            public override void Load()
            {
                Bind<IMyPlugin>().To<PluginA>();
                Bind<IController>().To<PluginAController>()
                    .Named(GetControllerName<PluginAController>());
            }
        }
    
    
  4. Setup binding for the plugin e.g. IMyPlugin -> PluginA

    
        public class PluginA : MyPlugin
        {
            public override void Load()
            {
                Bind<IMyPlugin>().To<PluginA>();
                Bind<IController>().To<PluginAController>()
                    .Named(GetControllerName<PluginAController>());
            }
        }
    
    
  5. Setup bindings for any Controllers for the plugin e.g. IController -> PluginAController
    
        public class PluginA : MyPlugin
        {
            public override void Load()
            {
                Bind<IMyPlugin>().To<PluginA>();
                Bind<IController>().To<PluginAController>()
                    .Named(GetControllerName<PluginAController>());
            }
        }
    
    
  6. All plugin Controllers must inherit MyController.cs
    
        public class PluginAController : MyController
        {
            public ActionResult Index()
            {
                return View();
            }
        }
    
    

Wrapping up, we have addressed the following concerns:

  • Loose coupling
  • Separation of concerns
  • Application modularity
  • Building our application from partitioned components
  • IoC & Dependency Injection
  • ServiceLocation with ServiceLocator and/or Ninject’s IKernel
  • Composite pattern

As requirements changed and the project matures, it will be helpful that we can change parts of the application without having these changes cascade throughout the system. Modularizing an application allow you to build application components separately (and loosely coupled) and to change whole parts of your application without affecting the rest of your code base.

Happy coding…! 🙂

Wrapping the Ninject Kernel with ServiceLocator

I was a big fan of using Unity or Mef for IoC in my apps, we used Prism heavily in one of my past projects with Silverlight. Prism offered a IoC with your choice of Unity or Mef for your container as well as very good approach to building a scalable application with the notion of Prism Modules.

I recently came on board to a project extensively using Ninject for our MVC3 application. Ninject has the notion of a Kernel which is pretty much how you access your container of registered or bound instances.

In the event where you would ever change out or switch your IoC implementation or choice of frameworks, a nice wrapper, that wrapped your method of accessing your container would be great. You can in theory switch out your IoC (container) with Mef, Unity, Sprint.NET, AutoFac, Castle Windsor, or any other IoC framework with minimal refactoring (here’s a great list of some popular IoC frameworks from Scott Hanselman). 

With a little research I found that Ninject has a ServiceLocator adapter that you can wire up when you setup your Kernel. With this wired up you can access your Ninject container with the standard Microsoft ServiceLocator, which is also a widely used pattern.

For this demonstration we are just going to use the MVC3 application used from my previous blog: http://blog.longle.net/2012/02/15/inject-ioc-my-mvc3-application-in-less-than-5-minutes/

  1. Right click your references folder and click “Manage NuGet Packages”
  2. Search for ServiceLocator, and install the CommonServiceLocator.NinjectAdapter Package
  3. You should now see the NinjectAdapter reference added
  4. Let’s wire this up now, we will visit the Global.asax.cs file where we setup and initialized our Kernel (container), here’s where we an register the NinjectServiceLocator Adapter with Microsoft.Practices.ServiceLocation.ServiceLocator interface.
    
            protected void Application_Start()
            {
                RegisterMyDependencyResolver();            
                AreaRegistration.RegisterAllAreas();
                RegisterGlobalFilters(GlobalFilters.Filters);
                RegisterRoutes(RouteTable.Routes);
            }
    
            private void RegisterMyDependencyResolver()
            {
                var standardKernel = new StandardKernel();
                standardKernel.Bind<IHelloWorldService>().To<HelloWorldService>();
                ServiceLocator.SetLocatorProvider(() => new NinjectServiceLocator(standardKernel));
                DependencyResolver.SetResolver(new MyDependencyResolver(standardKernel));
            }
    
    
  5. So the first place I wanted to use the ServiceLocator was in our MyDependendencyResolver class, where the MVC runitme routes all request get instances for all your registered or bound interfaces. What happens here is that when the MVC runtime requests for a registered instance of a specific interface and your container does not have one, MVC expects a your IoC container to return a null value and at this point MVC will fallback and attempt to return the default instance.

    For example if the MVC runtime requests for an IControllerFactory and you didn’t setup a binding or registration for this interface the MVC runtime will just return a DefaultControllerFactory in this case. The Ninject Kernel will automatically return null in this case.

    However when using the ServiceLocator interface, there is not a TryGet method like the Ninject Kernel offers when requesting instance, the TryGet method will actually scan the container for any registrations for a given interface and if it doesn’t find one it will return null for you.

    So I have to admit there wasn’t a way to really elegantly handle this. So to mimic this behaivor, which is returning a null when we weren’t able to find any registrations with the ServiceLocator, I had to wrap they request and catch the Microsoft.Practices.ServiceLocation.ActivationException, and if this exception was caught then we would return null so that the MVC runtime could take over and return default instances e.g. when requesting the IControllerFactory, ServiceLocator would return null, and MVC would take over and return the DefaultControllerFactory.

    Here’s the exception before wrapping the request:

    
        public class MyDependencyResolver : IDependencyResolver
        {
            public object GetService(Type serviceType)
            {
                    return ServiceLocator.Current.GetInstance(serviceType);
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                    return ServiceLocator.Current.GetAllInstances(serviceType);
            }
        }
    
    

  6. After wrapping the request to our container and returning null after scanning our container and not finding a registered instance for that interface, in our case the IControllerFactory.
    
        public class MyDependencyResolver : IDependencyResolver
        {
            public object GetService(Type serviceType)
            {
                try
                {
                    return ServiceLocator.Current.GetInstance(serviceType);
                }
                catch (Microsoft.Practices.ServiceLocation.ActivationException ex)
                {
                    return null;
                }
            }
    
            public IEnumerable<object> GetServices(Type serviceType)
            {
                try
                {
                    return ServiceLocator.Current.GetAllInstances(serviceType);
                }
                catch (Microsoft.Practices.ServiceLocation.ActivationException ex)
                {
                    return null;
                }
            }
        }
    
    

    Obviously we could create a two extension methods for ServiceLocator maybe TryGet and TryGetAll, but in the interest of time we’ll skip that for now.

    Note, you can always use ServiceLocator everywhere else in your application when requesting for instance(s) for a given interface from your Kernel and leave our former implementation of MyDependencyResolver accessing the Ninject Kenerl directly if you are uncomfortable with wrapping it with the try/catch block to return null, so that the MVC runtime can fallback and return default instances e.g. IControllerFactory -> DefaultControllerFactory.

    Again, not the most elegant way, however when doing a deep dive on the TryGet method from the Ninject Kernel with Reflector I notice that we weren’t to far off from what Ninject was actually doing here.

  7. If you look at the GetValue method that we reflected on (which is what eventually get’s called by the Ninject’s _kernel.TryGet method, notice the return statement ending with the lambda expression SingleOrDefault()
    
    protected virtual object GetValue(Type service, IContext parent)
    {
        Ensure.ArgumentNotNull(service, "service");
        Ensure.ArgumentNotNull(parent, "parent");
        IRequest request = parent.Request.CreateChild(service, parent, this);
        request.IsUnique = true;
        return parent.Kernel.Resolve(request).SingleOrDefault<object>();
    }
    
    

    which returns null if a registration was not found for that interface in our Ninject container.

    Obviously wrapping our request and catching the ActivationException, we are swallowing the exception, which could create some difficulties in debugging true exceptions where things weren’t wired up correctly for Ninject to bind and activate instances to return to us.

  8. Now let’s see do a quick demonstration on using the ServiceLocator pattern other than in our MyDependencyResolver class. Let’s revisit the HomeController where we were orginall injected the IHelloWorldService in the constructor. An alternative way here is we can manually get this injected by requesting it with ServiceLocator.
    Before:
    
        public class HomeController : Controller
        {
            private readonly IHelloWorldService _helloWorldService;
    
            public HomeController(IHelloWorldService helloWorldService)
            {
                _helloWorldService = helloWorldService;
            }
    
            public ActionResult Index()
            {
                ViewBag.Message = _helloWorldService.Hello(@"Welcome to ASP.NET MVC!");
                return View();
            }
    
            public ActionResult About()
            {
                return View();
            }
        }
    
    

    After:

    
        public class HomeController : Controller
        {
            private readonly IHelloWorldService _helloWorldService;
    
            public HomeController()
            {
                _helloWorldService = ServiceLocator.Current.GetInstance<IHelloWorldService>();
            }
    
            public ActionResult Index()
            {
                ViewBag.Message = _helloWorldService.Hello(@"Welcome to ASP.NET MVC!");
                return View();
            }
    
            public ActionResult About()
            {
                return View();
            }
        }
    
    

    Now it’s really preference whether you want the MVC runtime to use our MyDependencyResolver in conjunction with Ninject to automagically figure out what needs to be injected like in our [before] case which was injecting the IHellowWorldService in the constructor of HomeController, or manually requesting it using ServiceLocator.

    Again I don’t see a wrong or right in eithier way, it’s just really preference, I prefer going with our before case where we let MyDependencyResolver and Ninject figure out what, when and where things automagically need to be injected, however I just wanted to demonstrate abstracting Ninject’s Kernel with ServiceLocator if you wanted to have the flexibility of easiliy swapping out our choice of IoC frameworks with mininmal refactoring or code change. 🙂

Download sample application: https://skydrive.live.com/redir.aspx?cid=949a1c97c2a17906&resid=949A1C97C2A17906!371&parid=949A1C97C2A17906!361