ASP .NET MVC Dependency Injection Into Views

As some of you may know I mainly deal with WPF/WCF, but I like to keep an eye on things outside of that, and I am also working on a large web site personal project in my spare time, so definitely like to keep an eye on what ASP MVC does.

ASP MVC 3 is now officially released and I thought I would look at some of its new features, especially the new extensibility for doing dependency injection into pretty much all the layers (including views).

In versions prior to to MVC 3 one had to extend the DefaultControllerFactory and usually override the GetControllerInstance method, and it was not that easy to use DI in views without a lot of work, luckily with ASP .NET MVC 3 this is a lot easier to do.

DI For Controllers

All one needs to do now is implement the IControllerActivator interface, an example of which is shown below

public class UnityControllerActivator : IControllerActivator
{

    #region IControllerActivator Members
    public IController Create(RequestContext requestContext, 
        Type controllerType)
    {
        return DependencyResolver.Current.
            GetService(controllerType) as IController;
    }
    #endregion

}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Where I am using the Unity IOC container. You may also see above that this class simply delegates to a static method on DependencyResolver, which is  a new class that is available within ASP MVC 3.

DependencyResolver 

The IDependencyResolver interface implementation is what is responsible for resolving all dependency injection/container stored objects. Here is an example of how to create your own custom IDependencyResolver (again I am using the Unity IOC Container).  I will go through how this custom IDependencyResolver is applied to be used by MVC 3 in just a minute

public class UnityDependencyResolver : IDependencyResolver
{

    private IUnityContainer _container;


    public UnityDependencyResolver(IUnityContainer container)
    {
        _container = container;
    }


    public object GetService(Type serviceType)
    {
        try
        {
            return _container.Resolve(serviceType);
        }
        catch (Exception ex)
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return _container.ResolveAll(serviceType);
        }
        catch (Exception ex)
        {
            return new List<object>();
        }
    }

}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }So you can see that it is the role of this custom IDependencyResolver to well resolve objects from the Unity container.

Applying The Custom DependencyResolver To ASP MVC 3

So we now have a custom  IDependencyResolver but how do we get ASP MVC 3 to use it. Well that is done in Global.asax.cs, where you setup your IOC Container (Unity in my case), and than add your objects to the container, and then use a static method of DependencyResolver to set the current IDependencyResolver implementation that will be used, which will of course point to your custom IDependencyResolver

public class MvcApplication : System.Web.HttpApplication
{
    ....
    ....
    ....
    ....

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

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

        IUnityContainer container = SetupDependencyInjection();
        DependencyResolver.SetResolver(
        new UnityDependencyResolver(container));
    }

    private static IUnityContainer SetupDependencyInjection()
    {
        var container = new UnityContainer();
        container.RegisterType<IRidiculousTranslatorService, 
        RidiculousTranslatorService>();
        container.RegisterType<IControllerActivator, 
        UnityControllerActivator>();  
        return container;
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

It can also be seen here that we register our Unity based  IControllerActivator controller activator within the UnityContainer. Which means that whenever the ASP MVC 3 framework tries to resolve a controller, it will use this IControllerActivator controller activator. If ASP MVC 3 does not find a registered IControllerActivator instance by using the current DependencyResolver (which for this example will be the custom Unity IDependencyResolver implementation I showed above), it will fall back to  DefaultControllerFactory.

What About Views, Can We DI Into Them?

Now what about views, can we get DI/IOC to work with them, and why would we want to? Well suppose we have a web site that has to be multi-cultural, we could imagine we have a localization service, which takes a string, and returns another string based on the current culture.

So can we do that with ASP MVC 3? Yes we can, lets have a look how shall we.

The 1st thing to do, is create a custom class that inherits from either WebViewPage or WebViewPage<TModel> if you are using a strongly typed view. For the demo I am always using a strongly typed view, so I have only included a new class that inherits from WebViewPage<TModel>, which looks like this:

public abstract class InjectedWebViewPage<TModel> 
    : WebViewPage<TModel>
{
    [Dependency]
    public IRidiculousTranslatorService 
        RidiculousTranslatorService { get; set; }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }Where I am expected a dummy DI/IOC resolved service that was registered within the Unity IOC container which we saw in the global.asax.cs code above

Here is what the service looks like

public interface IRidiculousTranslatorService
{
    string TranslateAString(string stringToTranslate);
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }And here is its most ridiculous service implementation, just to demonstrate the concept, which simply returns a random string from a list of strings. This is obviously dummy, and you would not have a service do this in your real code, its just to demonstrate the DI/IOC ability of views using the ASP MVC 3 framework

public class RidiculousTranslatorService : IRidiculousTranslatorService
{
    private List<string> translationStrings = new List<string>();
    private Random rand = new Random();

    public RidiculousTranslatorService()
    {
        //create some dummy strings
        translationStrings.Add("bendy arms");
        translationStrings.Add("robot wanders");
        translationStrings.Add("crazed biscuit");
        translationStrings.Add("sweet chariot");
        translationStrings.Add("junkie boys");
    }

    public string TranslateAString(string stringToTranslate)
    {
        return translationStrings[rand.Next(translationStrings.Count)];
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }So now we have seen how we can create a custom WebViewPage<TModel>, base class that any of our own views can inherit from. Here is an example of that (obviously its using the new Razor view engine, so if you have not used ASP MVC 3 yet this may look a bit odd), the important bit is on line 1, where we declare what we are inheriting from, where we point to our custom InjectedWebViewPage<TModel>

 

@inherits Mvc3ViewDIApplication.Views.
InjectedWebViewPage<Mvc3ViewDIApplication.Models.DummyModel>

@{
    ViewBag.Title = "DummyView";
}

<h2>DummyView</h2>
<p>The translated text of @Model.DisplayText is 
@RidiculousTranslatorService.TranslateAString(Model.DisplayText) </p>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

And see how I output some translated text using the RidiculousTranslatorService which should be DI’d into the InjectedWebViewPage<TModel>  base class this view inherits from.

Here is a screen shot of the Dummy view to show it all working:

image

And if I load this page again I get a different word, which is what my RidiculousTranslatorService is actually setup to do, just to demonstrate that things are working via DI/IOC. Obviously in your real code, you would have proper services, not returning random results.

image

As always here is a small demo project : http://dl.dropbox.com/u/2600965/Blogposts/2011/02/Mvc3ViewDIApplication.zip

About these ads

8 thoughts on “ASP .NET MVC Dependency Injection Into Views

  1. Daniel says:

    Hi Sacha,

    Great Post.

    The interface IDependencyResolver was introduced to abstract from a concrete DI-container.
    But in your class ‘InjectedWebViewPage’ you have a dependency on ‘Microsoft.Practices.Unity.DependcyAttribute’, which is specific for Unity.

    Would’t it be better to configure the container appropriatly? Perhaps you need an IViewPageActivator to accomplish this?!
    The only problem is that Register-method of the container expects a concrete type. But views don’t have a type at compile time.

    What do you think? Any ideas?

    • sacha says:

      Daniel, good point, you could indeed abstract this further behind an interface, I did not want to go to deep in this post as I just wanted to show how you could DI into your views, but well spotted, there is indeed a dependency on Unity, as you say you could resolve this by further abstraction.

    • sacha says:

      Great link Daniel, thanks for sharing. I am not much of a web man, so what I did was the basics, I will share that link with my work collegue who digs this whole new fangled web thingy-a-me-watsit-doo-dah. Thanks

  2. Roy says:

    I suppose it depends on where you draw the line about code in the views.

    It’s ok DI-ing into the view if you want to bring .Net object up close and personal. But working with graphics HTML front end guys for the last year on a major project, the only stuff allowed front end was JQuery / Json / HTML and Silverlight of course :- )

    We used absolutely no Redmond stuff in the Views; all JQuery/HTML, delivered via Ajax to/from controllers, the controllers used DI (as you outlined) to services etc.

    We didn’t use Views as such but pushed HTML via the Controllers, as there was a problem with the View rendering of certain JQuery components, odd behaviour in all browsers.

    Working with the HTML designers who were using DreawWeaver on Apple Macs, that was hard, ever tried getting DW on Macs to interface into TFS, ahhhhhhh.

    By the way have you seen this ExtJs from www sencha dot com these are some of the front end components we used, is this the death of Silverlight for non-Intranet applications ???

    Hanging out (whoo hoo) with the HTML designers, it seems the Jquery/ Ajax crew are putting the fear of God (if one believes in that) into MS, who are pinning an awful lot on SL v5.

    SL is still lagging way behind Flash on it’s general uptake, even though Flash is now so dated.

    BTW, Just loved your TPL stuff, bob on, mate.

  3. sacha says:

    Roy

    I agree I feel HTML 5 and CSS 3 are better alternative to SL. I do not dig SL at all, I like WPF though as you know. Thanks for your comments, and glad you like my TPL stuff, more coming up soon.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s