MVC 3 passing entity as an Interface

2019-06-21 06:02发布

问题:

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!

回答1:

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)



回答2:

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.



回答3:

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?