views:

1510

answers:

2

I have a custom ViewModel defined as :

public class SampleFormViewModel
{
    public SampleFormViewModel(SelectList companies, Widget widget)
    {
        Companies = companies;
        Widget = widget;
    }

    public SelectList Companies { get; private set; }
    public Widget Widget { get; private set; }
}

In my Edit POST handler I have the following entry:

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(SampleFormViewModel model)
{

Edit form is set up as:

Inherits="System.Web.Mvc.ViewPage<Sample.Web.Models.SampleFormViewModel>"

And it just blows up, not sure what’s going on, has the following error: No parameterless constructor defined for this object. Certain I’m missing something really obvious here. Some background, the GET works perfectly and display the dropdown from the SelectList as expected. I’m guessing the auto-binding back to the custom view model is what is failing but not sure what to do about it.

+3  A: 

You need to have a parameterless constructor and I believe that the properties need to have public setters. The default binder creates the object using a constructor that takes no parameters, then uses reflection on the public properties to set values from the form/query parameters.

public class SampleFormViewModel
{
    public SampleFormViewModel() { }

    public SelectList Companies { get; set; }
    public Widget Widget { get; set; }
}

I suspect, though, that what you really want to do is not get the view model, but the underlying Widget model and select list value on form post. I don't think the binder will be able to reconstruct a SelectList on post since it only has the selected value in the parameters.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit( int CompanyID, Widget widget )
{
}
tvanfosson
Yep, I get it now. Problem was that SelectList has no parameterless constructors.If I remove the SelectList (Companies) from the constructor. And build it on the fly (from information in the widget object) when I create the ViewModel it all works as expected.Only difference is how I handle it in the POST, signature is now:public ActionResult Edit(int id, FormCollection formValues)
Craig McGuff
A: 

MVC requires, on strongly typed views, that the view can create the class used on that view. This means a constructor without any parameters. And this makes sense. Folks new to MVC will see similar "huh?" issues when they forget/fail to make parameters public and all such related errors that popup when the view attempts to put itself together (as opposed to a compiler error).

But what is "interesting" in this class of parameterless constructor problems is when a property of your class also does NOT have a parameter-free constructor. I guess this is the pessimistic approach?

Having spent some learning time on the SelectList class - a class specific to MVC - I wanted to hopefully help some folks save a few minutes/hours.

This really important tool/class for dropdown list creation, has the following constructors:

public SelectList(IEnumerable items); public SelectList(IEnumerable items, object selectedValue); public SelectList(IEnumerable items, string dataValueField, string dataTextField); public SelectList(IEnumerable items, string dataValueField, string dataTextField, object selectedValue);

..and therefore, if these are properties on your class (the one used for the view), MVC will give you the elusive "No parameterless constructor" error.

BUT, if you create something like a helper class, cut-n-paste the exact code from your original class, and then make that helper class a parameter (NOT a get/set) on your original class; you're good to go.

And in this manner, you can use a single view for gets and posts. Which is more beautiful :)

Personnally, I'd have either created the compiler to recognize the associations and requirements of strong typed views, or let the dropdown (or other "customer" of the SelectList) just fail to work rather then wonder if there's a specific level of recursive checking on paramerterless constructors.

Thankfully, the current version seems to only be top-level. Feels like a hack and I hope it's by design.

HTH.

Llewellyn Preece