Search code examples
asp.net-mvcdependency-injectioninversion-of-controlmodel-bindingcustom-model-binder

How to use a DI / IoC container with the model binder in ASP.NET MVC 2+?


Let's say I have an User entity and I would want to set it's CreationTime property in the constructor to DateTime.Now. But being a unit test adopter I don't want to access DateTime.Now directly but use an ITimeProvider :

public class User {
    public User(ITimeProvider timeProvider) {
        // ...
        this.CreationTime = timeProvider.Now;
    }

    // .....
}

public interface ITimeProvider { 
    public DateTime Now { get; }
}

public class TimeProvider : ITimeProvider {
    public DateTime Now { get { return DateTime.Now; } }
}

I am using NInject 2 in my ASP.NET MVC 2.0 application. I have a UserController and two Create methods (one for GET and one for POST). The one for GET is straight forward but the one for POST is not so straight and not so forward :P because I need to mess with the model binder to tell it to get a reference of an implementation of ITimeProvider in order to be able to construct an user instance.

public class UserController : Controller {

    [HttpGet]
    public ViewResult Create() {
         return View();
    }

    [HttpPost]
    public ActionResult Create(User user) {

         // ...

    }
}

I would also like to be able to keep all the features of the default model binder.

Any chance to solve this simple/elegant/etc? :D


Solution

  • How about instead of using an ITimeProvider try this:

    public class User 
    {
        public Func<DateTime> DateTimeProvider = () => DateTime.Now;
    
        public User() 
        {
            this.CreationTime = DateTimeProvider();
        }
    }
    

    And in your unit test:

    var user = new User();
    user.DateTimeProvider = () => new DateTime(2010, 5, 24);
    

    I know that this is not very elegant but instead of messing with the model binder this could be a solution. If this doesn't feel like a good solution you could implement a custom model binder and override the CreateModel method where you would inject the dependencies in the constructor of the model.