Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC 3 passing entity as an Interface

I'm currently working on an MVC 3 project using Ninject as my DI, the business objects are stored in a separate assembly. I'm running into an issue with the controller parameters, when posting back for CRUD operations I'm getting the error "Cannot create an instance of an interface". I am aware that you can't create an instance of an interface, but it seems like the only way I can get around this is to use a custom model binder and pass the FormCollection through. This seems really messy and I want to keep as much type specific code out of the project as I can - hence interfaces everywhere and Ninject to DI the concretes. Not only does custom model binding seem messy - won't I also lose my DataAnnotations?

Some code to describe what I have:

public ActionResult Create()
{
    // I'm thinking of using a factory pattern for this part
    var objectToCreate = new ConcereteType();
    return (objectToEdit);
}

[HttpPost]
public ActionResult Create(IRecord record)
{
    // check model and pass to repository
    if (ModelState.IsValue)
    {
        _repository.Create(record);
        return View();
    }

    return View(record);
}

Has anyone run into this before? How did you get over it?

Thanks!

like image 989
Paul Aldred-Bann Avatar asked Nov 21 '11 16:11

Paul Aldred-Bann


People also ask

Why can't I use an interface in MVC?

The reason why you cannot use the interface is because of serialization. When a request comes in it only contains string key/value pairs that represent the object: When the action method gets invoked the MVC runtime tries to create values to populate the method's parameters (via a process called model binding).

How does MVC create the parameters of an action?

When the action method gets invoked the MVC runtime tries to create values to populate the method's parameters (via a process called model binding). It uses the type of the parameter to infer how to create it.

What is generic abstract class in MVC?

This generic abstract class provides common implementation of Observer design pattern used by all MVC views. BaseViewMvc abstract class: In this abstract class I put various “utility” methods used by other MVC views. So, each class and interface in this hierarchy has a purpose.

What is baseviewmvc abstract class?

BaseViewMvc abstract class: In this abstract class I put various “utility” methods used by other MVC views. So, each class and interface in this hierarchy has a purpose. However, it doesn’t change the fact that this scheme is very complex. I’ve been using MVC for years and stopped noticing this complexity long ago.


3 Answers

but it seems like the only way I can get around this is to use a custom model binder

A custom model binder is the correct way to go. And by the way you should use view models as action arguments, not domain models or interfaces.

Not only does custom model binding seem messy - won't I also lose my DataAnnotations?

I don't know why you think that a custom model binder would make things messy. For me it's a great way to separate mapping logic into a reusable class. And, no you will not lose DataAnnotations. They will work perfectly fine on the concrete instance that the custom model binder would return.

like image 182
Darin Dimitrov Avatar answered Oct 02 '22 10:10

Darin Dimitrov


Data passed to controllers action are simply holders for values. There shouldn't be any logic in them so there is nothing to decouple from. You can use concrete types (e.g Record) instead of interface (IRecord)

like image 30
Novakov Avatar answered Oct 02 '22 10:10

Novakov


I made the same simple mistake. Ninject injects parameters into your constructor, but you added parameters to the Index Controller action.

It should look like this:

public class HomeController : Controller
{
    private IRecord _record;

    public HomeController(IRecord record)
    {
        _record = record;
    }

    public ActionResult Index()
    {
        ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application. " +
                          _record .HelloWorld();

        return View();
    }
}

Make sense?

like image 37
Dan Csharpster Avatar answered Oct 02 '22 08:10

Dan Csharpster