Alex Rivera | Logout

Fetching data within an ASP.NET MVC ViewModel class?

Asked 2009-09-23T04:48:43.150
13

For those that create ViewModels (for use by typed views) in ASP.NET MVC, do you prefer to fetch the data from a service/repository from within the ViewModel, or the controller classes?

For example, we started by having ViewModels essentially being DTOs and allowing our Controllers to fetch the data (grossly oversimplified example assumes that the user can only change employee name):

public class EmployeeViewModel
{
    public String Name; //posted back
    public int Num; //posted back
    public IEnumerable<Dependent> Dependents; //static
    public IEnumerable<Spouse> Spouses; //static
}

public class EmployeeController()
{
    ...
    public ActionResult Employee(int empNum)
    {
        Models.EmployeeViewModel model = new Models.EmployeeViewModel();
        model.Name = _empSvc.FetchEmployee(empNum).Name;
        model.Num = empNum;
        model.Dependents = _peopleSvc.FetchDependentsForView(empNum);
        model.Spouses = _peopleSvc.FetchDependentsForView(empNum);
        return View(model);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Employee(Models.EmployeeViewModel model)
    {
        if (!_empSvc.ValidateAndSaveName(model.Num, model.Name))
        {
            model.Dependents = _peopleSvc.FetchDependentsForView(model.Num);
            model.Spouses = _peopleSvc.FetchDependentsForView(model.Num);
            return View(model);
        }
        this.RedirectToAction(c => c.Index());
    }
 }

This all seemed fine until we started creating large views (40+ fields) with many drop downs and such. Since the screens would have a GET and POST action (with POST returning a view if there was a validation error), we'd be duplicating code and making ViewModels larger than they probably should be.

I'm thinking the alternative would be to Fetch the data via the Service within the ViewModel. My concern is that we'd then have some data populated from the ViewModel and some

Edit
Report

1 Answer

3

There's more than that ;-) You can fetch in model binder or action filter. For the second option, check Jimmy Bogard's blog somewhere around here. I personally do it in model binders. I use ViewModel like this: My custom ASP.NET MVC entity binding: is it a good solution?. It is processed by my custom model binder:

public object BindModel(ControllerContext c, BindingContext b)
{
   var id = b.ValueProvider[b.ModelName]; // don't remember exact syntax
   var repository = ServiceLocator.GetInstance(GetRepositoryType(b.ModelType));
   var obj = repository.Get(id);
   if (obj == null)
     b.ModelState.AddModelError(b.ModelName, "Not found in database");
   return obj;
}

public ActionResult Action(EntityViewModel<Order> order)
{
   if (!ModelState.IsValid)
      ...;
}

You can also see an example of model binder doing repository access in S#arp Architecture.

As for static data in view models, I'm still exploring approaches. For example, you can have your view models remember the entities instead of lists, and

public class MyViewModel { public MyViewModel(Order order, IEmployeesSvc _svc) { }

  public IList<Employee> GetEmployeesList()
  {
      return _svc.GetEmployeesFor(order.Number);
  }

}

You decide how you inject _svc into ViewModel, but it's basically the same as you do for controller. Just beware that ViewModel is also created by MVC via parameterless constructor, so you either use ServiceLocator or extend MVC for ViewModel creation - for example, inside your custom model binder. Or you can use Jimmy Bogard's approach with

answered 2009-09-23T19:34:23.960

Your Answer