JoshRees
JoshRees

Reputation: 41

DI with viewmodel in ASP.NET MVC

I'm learning IoC for the first time but cannot work out how this works with viewmodels and model binding in a standard ASP.NET MVC controller. Let's say I have a basic controller using tightly coupled repository and viewmodel.

public class Sample
{
    [HttpGet]
    public ActionResult Index()
    {
        var repo = new SampleRepository();
        var model = new SampleViewModel();
        model.SampleItems = repo.Get();
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(SampleViewModel model) 
    {
        ...
    }
}

Now I want to use DI to loosely couple this controller from it's dependent classes so I inject the repository and viewmodel in via constructor injection

public class Sample
{
    private readonly ISampleRepository _sampleRepository;
    private readonly ISampleViewModel _sampleViewModel;

    public Sample(
          ISampleRepository sampleRepository,
          ISampleViewModel sampleViewModel)
    {
        _sampleRepository =  sampleRepository;
        _sampleViewModel =  sampleViewModel;
    }

    [HttpGet]
    public ActionResult Index()
    {
         _sampleViewModel.SampleItems = _sampleRepository.Get()

         return View(_sampleViewModel);
    }

    [HttpPost]
    public ActionResult Index(SampleViewModel model) 
    {
        ...
    }
}

My problem is, I'm now injecting a viewmodel in via an interface but the HttpPost Action requires a concrete SampleViewModel to do the model binding?

Have I misunderstood how this works? Should I be attempting to loosely couple my viewmodel from the controller or is this just something that needs tight coupling for the model binder to work? I've seen code out there where people use a service layer to return a viewmodel to the controller, and I know you could also write a custom model binder, but this seems like massive overkill for what I want to do here? All I'm after is a way of injecting in a basic viewmodel that can then be used by a view for GET and POST.

Upvotes: 4

Views: 4008

Answers (1)

NightOwl888
NightOwl888

Reputation: 56869

A viewmodel doesn't actually do anything. It is basically just a DTO that transfers data from your controller to your view. By definition, it cannot have any dependencies. Instead, it is part of the application's runtime state.

Injecting runtime data is anti-pattern. Instead, your controller should create an instance of your viewmodel, as it is always expected to return one. There is no reason to mock it for testing, nor is there any reason to replace its implementation. So, there is also no reason to make an abstraction of it (an interface or abstract class).

public class Sample
{
    private readonly ISampleRepository _sampleRepository;

    public Sample(
          ISampleRepository sampleRepository)
    {
        _sampleRepository =  sampleRepository;
    }

    [HttpGet]
    public ActionResult Index()
    {
        var sampleViewModel = new SampleViewModel()
        {
            SampleItems = _sampleRepository.Get(),
            // Other initialization here...
        };

        return View(sampleViewModel);
    }

    [HttpPost]
    public ActionResult Index(SampleViewModel model) 
    {
        ...
    }
}

Upvotes: 8

Related Questions