The Case Against Self-Aware ViewModels in ASP.NET MVC

ViewModels in ASP.NET MVC are a valuable tool and are widely considered a best practice in developing MVC applications. In this post, I will make a case for why ViewModels should NOT be self-aware.

ViewModels are a commonly used mechanism to deliver everything a View needs in a single object. Without them, you would have to push them to the View in a different manner. In a Single Page Application (SPA), this might be a moot point since you will likely be loading the View, then pulling the data separately. However, in a true MVC application, you would have to rely on the terrible ViewBag process or an equally bad mechanism to deliver that data since a Model that a View references can only be a single object. So, now that I have described why ViewModels are a good and necessary item, lets look at how to populate them. When you are working with ViewModels, I see three viable options that everyone has easy access to for loading the data into those ViewModels.

  1. Let your Controllers do it.
    BAD PROGRAMMER! Stop that! Your Controllers should be anorexic. So skinny that they could hula hoop in a Cheerio. Using your Controllers to populate data is just a really bad practice. This is not what they are intended to do. Controllers deliver Views and that is about all they should be doing. You can do this but you really shouldn’t and most experienced programmers will agree.
  2. Let the ViewModels load themselves.
    At one time, this was my preferred option and made the most sense to me. However, when you start to really look at it, it clearly violates the Single Responsibility Principle (SRP). This also makes the ViewModel object a bit less reusable. Below is an example of what this might look like.

    HomeController.cs

    public class HomeController : Controller
    {
        private IContactRepository _contactRepository = null;
    
        public HomeController(IContactRepository contactRepository)
        {
            _contactRepository = contactRepository;
        }
    
        public ActionResult Index()
        {
            HomeIndexViewModel viewModel = new HomeIndexViewModel(_contactRepository);
    
            if (viewModel.LoadViewModel())
            {
                return View(viewModel);
            }
            else
            {
                return RedirectToAction("ServerError");
            }
        }
    
        public ActionResult ServerError()
        {
            return View();
        }
    }

    HomeIndexViewModel.cs

    public class HomeIndexViewModel
    {
        private IContactRepository _contactRepository = null;
    
        public HomeIndexViewModel(IContactRepository contactRepository)
        {
            _contactRepository = contactRepository;
        }
    
        public List<Contact> Contacts { get; set; }
    
        public bool LoadViewModel()
        {
            Contacts = _contactRepository.GetContacts();
    
            return true;
        }
    }

    Note that we are already using a service (repository) to actually load the data so why muddy the waters by having the LoadViewModel method on the ViewModel class? It just doesn’t make much sense.

  3. Have an intermediary do it.
    This is really the only choice that aligns with SOLID principles. Your service knows about the ViewModel and can utilize a library like AutoMapper to make the process easier. You will have to be careful about where you place the ViewModel if your service is not in the MVC project because the MVC project knows about the service and not vice versa.

What do you think? How do you handle this problem in your own projects?

Leave a Reply

Your email address will not be published.