It’s The Little Things about ASP.NET MVC 4

asp.net mvc, asp.net, code 0 comments suggest edit

Conway’s Law states,

…organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations.

Up until recently, there was probably no better demonstration of this law than the fact that Microsoft had two ways of shipping angle brackets (and curly braces for that matter) over HTTP – ASP.NET MVC and WCF Web API.

The reorganization of these two teams under Scott Guthrie (aka “The GU” which I’m contractually bound to tack on) led to an intense effort to consolidate these technologies in a coherent manner. It’s an effort that’s lead to what we see in the recently released ASP.NET MVC 4 Beta which includes ASP.NET Web API.

For this reason, this is an exciting release of ASP.NET MVC 4 as I can tell you, it was not a small effort to get these two teams with different philosophies and ideas to come together and start to share a single vision. And this vision may take more than one version to realize fully, but ASP.NET MVC 4 Beta is a great start!

For me personally, this is also exciting as this is the last release I had any part in and it’s great to see the effort everyone put in come to light. So many congrats to the team for this release!

Some Small Things

small-things

If you take a look at Jon Galloway’s on ASP.NET MVC 4, he points to a lot of resources and descriptions of the BIG features in this release. I highly recommend reading that post.

I wanted to take a different approach and highlight some of the small touches that might get missed in the glare of the big features.

Custom IActionInvoker Injection

I’ve written several posts that add interesting cross cutting behavior when calling actions via the IActionInvoker interface.

Ironically, the first two posts are made mostly irrelevant now that ASP.NET MVC 4 includes ASP.NET Web API.

However, the concept is still interesting. Prior to ASP.NET MVC 4, the only way to switch out the action invoker was to write a custom controller factory. In ASP.NET MVC 4, you can now simply inject an IActionInvoker using the dependency resolver.

The same thing applies to the ITempDataProvider interface. There’s almost no need to write a custom IControllerFactory any longer. It’s a minor thing, but it was a friction that’s now been buffed out for those who like to get their hands dirty and extend ASP.NET MVC in deep ways.

Two DependencyResolvers

I’ve been a big fan of using the Ninject.Mvc3 package to inject dependencies into my ASP.NET MVC controllers.

ninject.mvc3

However, your Ninject bindings do not apply to ApiController instances. For example, suppose you have the following binding in the NinjectMVC3.cs file that the Ninject.MVC3 package adds to your project’s App_Start folder.

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<ISomeService>().To<SomeService>();
}

Now create an ApiController that accepts an ISomeService in its constructor.

public class MyApiController : ApiController
{
  public MyApiController(ISomeService service)
  {
  }
  // Other code...
}

That’s not going to work out of the box. You need to configure a dependency resolver for Web API via a call to GlobalConfiguration.Configuration.ServiceResolver.SetResolver.

However, you can’t pass in the instance of the ASP.NET MVC dependency resolver, because their interfaces are different types, even though the methods on the interfaces look exactly the same.

This is why I wrote a small adapter class and convenient extension method. Took me all of five minutes.

In the case of the Ninject.MVC3 package, I added the following line to the Start method.

public static void Start()
{
  // ...Pre-existing lines of code...

  GlobalConfiguration.Configuration.ServiceResolver
  .SetResolver(DependencyResolver.Current.ToServiceResolver());
}

With that in place, the registrations work for both regular controllers and API controllers.

I’ve been pretty busy with my new job to dig into ASP.NET MVC 4, but at some point I plan to spend more time with it. I figure we may eventually upgrade NuGet.org to run on MVC 4 which will allow me to get my hands really dirty with it.

Have you tried it out yet? What hidden gems have you found?

Found a typo or error? Suggest an edit! If accepted, your contribution is listed automatically here.

Comments

avatar

43 responses

  1. Avatar for Josh Carroll
    Josh Carroll March 11th, 2012

    Nice! Big kudos to you and others on a job well done.
    I did something similar to this for Structure map so I could use the same container for the Dependency Resolvers used in WebApi, MVC, and SignalR.
    It's nice to see this kind of pattern start to make it's way into more and more libraries by default. I'm wondering if we are starting to see the beginnings of "standard" interfaces in software development. It's an interesting idea anyway...

  2. Avatar for Mohamed Meligy
    Mohamed Meligy March 11th, 2012

    Phil,
    Great how you related what you tried before to the new stuff in ASP.NET MVC 4. Nice write up :)
    For others findings, there is one thing not specific to ASP.NET MVC 4, but I discovered it when trying ASP.NET MVC 4 out in VS 11. Some helper file for JS intellisense named '_References.js'. I wrote about it here: http://bit.ly/_referencesjs

  3. Avatar for Bilal
    Bilal March 11th, 2012

    Hi Phil,
    Many thanks for shedding light on Ninject problem. I have been struggling with this for weeks now and have posted my problem here
    forums.asp.net/.../1
    But now I try with your way and it tells me this "does not appear to implement Microsoft.Practices.ServiceLocation.IServiceLocator.
    Parameter name: commonServiceLocator"... Any pointers where I am wrong.
    Regards
    Bilal

  4. Avatar for Khalid Abuhakmeh
    Khalid Abuhakmeh March 11th, 2012

    Why was the decision to make two identical interfaces in two separate assemblies? Is it because the WebAPI was supposed to be hostable from anywhere and the team didn't want references to System.Web.Mvc in a none MVC project?

  5. Avatar for haacked
    haacked March 11th, 2012

    Bilal, use my adapter.
    Khalid, that's exactly it.

  6. Avatar for Bilal
    Bilal March 11th, 2012

    And it worked. I was using the MVC namespace for IDependencyResolver, realised the mistake and used Http.Service namespace to make it work.
    Really appreciate you taking out time to respond back.
    Cheers
    Bilal

  7. Avatar for Iian
    Iian March 12th, 2012

    Is it just me or did anybody else keep reading 'IServiceResolver' as 'IServiceRevolver'? ;-)

  8. Avatar for Dmitry
    Dmitry March 12th, 2012

    Why couldn't they just use Microsoft.Practices.ServiceLocation.IServiceLocator for everything?

  9. Avatar for haacked
    haacked March 12th, 2012

    Dmitry, they *do* support that. You can pass in an instance of IServiceLocator. In fact, if you pass in new Object() to SetResolver you'll get an exception message stating such. I just didn't have an instance handy so I wrote a simple adapter.

  10. Avatar for Vincenzo
    Vincenzo March 12th, 2012

    In order to call actions from javascript have also a look to JsAction, with upcoming WebApi support!
    http://jsaction.codeplex.com

  11. Avatar for James
    James March 12th, 2012

    Phil, what is your opinion on service locator being an anti-pattern? A recent question on SO was posed about the use of service locator in ASP.NET MVC here: http://bit.ly/A34lO5

  12. Avatar for Josh Carroll
    Josh Carroll March 12th, 2012

    @James - Using a Service Locator is not an anti-pattern, and the question on SO incorrectly represents the arguments made in the book "Dependency Injection in .NET"
    Mark Seemann never says that using a container or service locator is an anit-pattern. He simply states what we should all already know. Mainly that your objects should be composed at the composition root, and the service locator should be used there.
    If you would take the time to look over the code you would find that the MVC use of the DependencyResolver is pretty minimal, and as close to the composition root as you can get in ASP.Net. i.e. Called from an IHttpHandler.
    Please do a little research first before chiding Phil over something you don't understand.

  13. Avatar for haacked
    haacked March 12th, 2012

    @Josh let's be civil now. :) James didn't necessarily plug that post.
    @James, I agree with Josh. I think a Framework's use of it would be an anti-pattern if it FORCED you to use the pattern.
    But if you notice all the ASP.NET MVC examples show constructor injection for the Controllers. While MVC might use service location in a few places, *your* code doesn't need to. But you can if you choose to.
    The only time your code needs to deal with service location is to configure a container with the built in dependency resolver.

  14. Avatar for James
    James March 12th, 2012

    @Phil - Thanks for your opinion on service locator in ASP.NET MVC.
    @Josh - I never "chided" anyone. I respect Phil's opinions and simply asked for his thoughts on the question posed on SO. I never said that I endorse the opinion expressed by the poster of the SO question either. I also follow Mark Seamann's blog and know his opinions regarding resolving dependencies at the composition root, so please do not infer my intent or my knowledge of service locators based on my question posed to Phil.

  15. Avatar for brad
    brad March 13th, 2012

    "an intense effort to consolidate these technologies in a coherent manner."
    I just hope the flawed web-thinking doesnt spoil real WCF. (WCF Web whatever rest thing can die in a fire. I am just worried about real WCF.)

  16. Avatar for Ed DeGagne
    Ed DeGagne March 13th, 2012

    I think @Josh posted his response before his first cup of coffee was fully consumed. :)
    Been plugging away with MVC 4 Beta for about 3 weeks now, so far I like what I am seeing.

  17. Avatar for dfndn
    dfndn March 14th, 2012

    Allowed tags: blockquote, a, strong, em, p, u, strike, super, sub, code

  18. Avatar for Jme
    Jme March 16th, 2012

    Even when using your adapter, I still get the error that bilal was stating:
    does not appear to implement
    Microsoft.Practices.ServiceLocation.IServiceLocator.
    Parameter name: commonServiceLocator"... Any pointers where I am wrong.
    What could I be doing wrong - all I did was copy your service adapter class and static extension class into my project and added the line to the NinjectMVC3 Start() method to set the resolver, same way you did, and I still get this problem...thanks!

  19. Avatar for Brian Chandley
    Brian Chandley March 17th, 2012

    Jme,
    I ran into the same problem the problem here namespaces. In my case, System.Web.Http.Services.IDependencyResolver and System.Web.Mvc.IDependencyResolver were swapped.
    In Phil's wrapper class on git hub, apply the following using statements:
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Http.Services;
    HTH!

  20. Avatar for Jme
    Jme March 19th, 2012

    Awesome, works - I didn't realize - thanks!

  21. Avatar for Paul
    Paul March 19th, 2012

    Nice post! Will there be a Ninject.MVC4 package like the StructureMap.MVC4 package that just "works"?

  22. Avatar for haacked
    haacked March 20th, 2012

    @Paul You'll have to ask the Ninject team, but I would assume so. :)

  23. Avatar for Tien Do
    Tien Do March 22nd, 2012

    It didn't work until I found out that I needed one more line of code to register all Web API controllers, like this one:
    container.Register(AllTypes.FromThisAssembly().BasedOn<IHttpController>().LifestyleTransient());
    Thanks,

  24. Avatar for John Jelinek
    John Jelinek March 26th, 2012

    When I use the namespace System.Web.Http.Services.DependencyResolver on Phil's class, I get the following error from Start:
    "Unable to cast object of type 'Ninject.Web.Mvc.NinjectDependencyResolver' to type 'System.Web.Http.Services.IDependencyResolver'."
    It seems that if I try to make it use System.Web.Http.Services, there is no "Current" property available in this line:
    GlobalConfiguration.Configuration.ServiceResolver.SetResolver(DependencyResolver.Current.ToServiceResolver())
    Has anyone else run into this?

  25. Avatar for John Jelinek
    John Jelinek March 26th, 2012

    Never mind. It's all fixed now.

    Imports System
    Imports System.Collections.Generic
    Imports System.Linq
    Imports System.Web
    Imports System.Web.Http.Services
    Public Class ServiceResolverAdapter
    Implements IDependencyResolver
    Private ReadOnly dependencyResolver As System.Web.Mvc.IDependencyResolver
    Public Sub New(dependencyResolver As System.Web.Mvc.IDependencyResolver)
    If dependencyResolver Is Nothing Then
    Throw New ArgumentNullException("dependencyResolver")
    End If
    Me.dependencyResolver = dependencyResolver
    End Sub
    Public Function GetService(serviceType As Type) As Object Implements IDependencyResolver.GetService
    Return dependencyResolver.GetService(serviceType)
    End Function
    Public Function GetServices(serviceType As Type) As IEnumerable(Of Object) Implements IDependencyResolver.GetServices
    Return dependencyResolver.GetServices(serviceType)
    End Function
    End Class
    Public Module ServiceResolverExtensions
    Sub New()
    End Sub
    <System.Runtime.CompilerServices.Extension()> _
    Public Function ToServiceResolver(dependencyResolver As System.Web.Mvc.IDependencyResolver) As IDependencyResolver
    Return New ServiceResolverAdapter(dependencyResolver)
    End Function
    End Module

  26. Avatar for wazz
    wazz March 26th, 2012

    @lian "Is it just me or did anybody else keep reading 'IServiceResolver' as 'IServiceRevolver'? ;-)"
    i did. :\

  27. Avatar for Joe
    Joe April 4th, 2012

    Does this also work with the MVC 4 Single Page App?

  28. Avatar for Pete
    Pete April 15th, 2012

    @Josh: Mark Seeman does say that Service Location is an anti-pattern, he does it on his blog and here in an interview on InfoQ (http://www.infoq.com/articles/DI-Mark-Seemann): "which again leads to the Service Locator anti-pattern". I haven't read his book but I'd exepct him to support this claim in the book too. Also what is even worse Mark says "DI also solves all of the problems that Service Locator claims to solve, so there’s absolutely no reason to ever use a Service Locator." which is totally in conflict with what you say (and I agree with your opinion, not Mark's). It is really surprising that someone who writes a book about Depenedency Injection has such narrow view of the subject. So to sum up, YES Mark Seeman does claim that Service Location is an anti-pattern and is thus doing a bad service to the community with this opinion and that's why people get confused ask such questions i.e. here on Phil's blog since Phil is very respected.

  29. Avatar for vtortola
    vtortola April 24th, 2012

    Thanks! It would be better if you put the full class name (with namespaces) in the example, it would make things more clear :)

  30. Avatar for Tom McKearney
    Tom McKearney May 2nd, 2012

    Though WCF Web Api has eliminated most of the need for your McvHaack.Ajax library, there is still the need to get the "root" url of the application into your Javascript modules, unless I'm missing something.
    I guess this could be done with some "global" property though

  31. Avatar for Rei
    Rei May 25th, 2012

    Hi Phil! I'm not using ninject. I'm using nuget package structuremap.mvc4.
    When debugging I am getting errors :
    "Activation error occured while trying to get instance of type
    IActionValueBinder, key ""."
    After I hit several times ok, it finds the apicontroller and resolves and returns the data back no problem... Am I forgetting something?

  32. Avatar for Nicolas Van Hoorde
    Nicolas Van Hoorde May 29th, 2012

    Hero! Finally got rid of that 'db is in use' in MVC4 thanks to this!
    Now I'm stuck on something for a while (totally different though). I use Entity Framework and I want my Portfolio class to have a required User attached to it. I can map this, problem is that I can't define a key for ASP Users in my context.
    I know there is a possibilty to extend the default Members and providers that work with those members, but I'm just getting started with ASP.NET MVC3/4 and the articles I find on the internet really don't give any CLEAR information on how to implement this.
    Thanks anyway!

  33. Avatar for Tiendq
    Tiendq June 5th, 2012

    Hi Phil,
    I just updated to MVC 4 RC yesterday and ServiceResolver is no longer exist in HttpConfiguration class. Is there any new update to work with RC?
    Regards,

  34. Avatar for Brian Adams
    Brian Adams June 5th, 2012

    MVC4 broke this. I can't seem to figure out how to resolve it now. Any updates?

  35. Avatar for StarTrekRedneck
    StarTrekRedneck June 6th, 2012

    As an alternative,

    public class MyDependencyResolver :
    System.Web.Http.Services.IDependencyResolver,
    System.Web.Mvc.IDependencyResolver

  36. Avatar for Tom Stickel
    Tom Stickel July 20th, 2012

    I posted the article about the Service Locator being an anti-pattern. It totally is, not sure what someone is smoking, but Mark Seemann HIGHLY in his book AND on the Stackoverflow posting of mine IS VERY AGAINST IT. Please re-read his book, and the Stackoverflow posting to those who think that they really understand what is being said, what is the science and not merely some opinion by someone with a big ego

  37. Avatar for gustyn
    gustyn July 22nd, 2012

    In VS2012 RC, I am noticing a problem with Intellisense recognizing ServiceResolver. I am using Ninject as my dependency resolver. It first came to light with Resharper 7 giving a cannot resolve symbol error for ServiceResolver in NinjectWebCommon:
    public static void Start()
    {
    DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
    DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
    Bootstrapper.Initialize(CreateKernel);
    GlobalConfiguration.Configuration.ServiceResolver
    .SetResolver(DependencyResolver.Current.ToServiceResolver());
    }
    Intellisense does not disply it either neither in the Object Explorer. It was fine in this project in VS2010.
    What am I missing? It has to be an obvious thing.

  38. Avatar for Gustyn
    Gustyn July 23rd, 2012

    Never mind, They changed things around for the RC so you have to use DependencyResolver instead of ServiceResolver and some other changes.
    Thanks for this great post though.

  39. Avatar for Josh
    Josh August 23rd, 2012

    Brian, Tiendng, all,
    I found this similar issue being asked on Stackoverflow (http://stackoverflow.com/a/10855037)
    Brad Wilson's sample code (https://gist.github.com/2417226) helps with the resolving. Inside the CreateKernel() and after the var kernel has been instantiated, you can call the following:

    System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);

    Hope this helps!

  40. Avatar for vinod
    vinod October 5th, 2012

    write a program to count the number of constructor of a class.

  41. Avatar for Kiev Marble
    Kiev Marble December 6th, 2012

    Been plugging away with MVC 4 Beta for about 3 weeks now, so far I like what I am seeing.

  42. Avatar for Mohammad Bilal
    Mohammad Bilal May 6th, 2013

    Good article...I want to find back links to my website in asp.net(C#) using MVC4 web api can any one help me for this...

  43. Avatar for Murali M
    Murali M December 1st, 2013

    I could not see this ServiceResolver in Assembly System.Web.Http.WebHost.dll, v4.0.30319, the downloaded via Nuget <package id="Microsoft.AspNet.WebApi.WebHost" version="4.0.20710.0" targetframework="net40"/>

    Also GlobalConfiguration.Dispatcher class. I am following this http://onionarch.codeplex.com project to create Onion Architecture, However I failed to initialize the DependencyResolver for WebAPI.

    What is the current class does this ?