Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Model (ViewModel) binding when model needs dependencies injected

I'm using Ninject for dependency injecting in an ASP.Net MVC application (This is my first project using Ninject or DI at all for that matter).

I'm opting to using the Model-View-ViewModel pattern. The view model will provide all my properties I'll bind to my actual view, but also need to access the database for things such as lists of data. Eg:

public class CreateGetIncidentViewModel
{

    private IDBContext _dbContext = null;

    [Required]
    public EmployeeType EmployeeType { get; set; }


    [Required]
    [StringLength(50)]
    public string Department { get; set; }

    /
    public IEnumerable<SelectListItem> GetEmployeeTypeSelectList()
    {
        // Simplified for brevity
        var employeeTypes = _dbContext.EmployeTypes.Where().... // Go select the employee types

        var employeeTypeSelectList = new List<SelectListItem>();

        foreach(var employeeType in employeeTypes){
            employeeTypeSelectList.Add(new SelectListItem(){
                // Set select list properties
            });
        }           

        return employeeTypeSelectList;
    }
}

My problem is:

  • IDBContext is a registered dependency within Ninject. Accessing the concrete type directly by instantiating it would be a no-no.
  • I must somehow get that dependency injected into this class or somehow access the dependency through some other class that already has the dependency resolved.

Given that my ViewModel is often hydrated by ASP.Net MVC automatically through model binding, how do I get my dependency into my ViewModel?

There are multiple ways which I've through about but they all seem dirty. I COULD (but don't want to)

  • Implement the service locator pattern to just simply resolve my IDBContext dependency from within the ViewModel.
  • Resolve the IDBContext within my controller and pass it into my ViewModel upon manual construction of the ViewMode i.e. new CreateGetIncidentViewModel(dbContext);
    • This doesn't solve the problem of the view model being hydrated by MVC though when the model is being posted to an action

Suggestions?

like image 835
Ryan Griffith Avatar asked May 21 '13 20:05

Ryan Griffith


2 Answers

Given that my ViewModel is often hydrated by ASP.Net MVC automatically through model binding, how do I get my dependency into my ViewModel?

You could write a custom model binder that will inject the dependency into the view model constructor.

This being said, using the MVVM pattern in ASP.NET MVC IMHO is wrong approach from the beginning and if you go that way you must be prepared for lots of suffering. Are you ready for that?

If not, here's what I would recommend you:

Controller -> Domain model -> View model -> View

In this pattern you have the controller knowing about the repository (DbContext - being injected automatically into it by your DI framework).

Flow 1:

  1. The controller receives a request from the user
  2. The controller uses the repository to query one or more domain models
  3. The controller uses a mapping layer to map those domain models to a view model
  4. The controller passes this (single) view model to the view for rendering

Flow 2:

  1. The controller receives a request from the view (form submit for example)
  2. The model binder automatically binds the request body to a single view model that your controller action is taking as argument
  3. The controller is using a mapping layer to map this view model to one or more domain models
  4. The controller is using the repository to update those domain models.

In this examples the view model doesn't know anything about any repository or data access or DbContexts. The view model is the representation of the view. The mapping between the domain model and the view is a responsibility of the controller (which could be delegated to a mapping layer). Personally I use AutoMapper to perform the mapping between my domain models and view models.

like image 67
Darin Dimitrov Avatar answered Nov 15 '22 22:11

Darin Dimitrov


In case you wish to go the Custom Model Binder route that Darin mentioned, check this out: https://stackoverflow.com/a/24166483/71906

like image 27
James McCormack Avatar answered Nov 15 '22 22:11

James McCormack