I have a form where we want to enter several transactions for one client. The view for the form is as follows:
public class TradeSpendingEntryViewModel { public TradeSpendingEntryViewModel() { Records = new List<TradeSpendingEntryViewModelRecord>(); } public string CustomerNumber { get; set; } public DateTime Date { get; set; } public SelectList PlanningYears { get; set; } public List<TradeSpendingEntryViewModelRecord> Records { get; set; } }
We want to dynamically add and remove entries using javascript. Each entry in the collection:
public class TradeSpendingEntryViewModelRecord { public TradeSpendingEntryViewModelRecord() { } public string LOB { get; set; } public string ProductCode { get; set; } public SelectList AllowType { get; set; } public int Cases { get; set; } public bool EndCurrentDeal { get; set; } public Single DealRate { get; set; } public DateTime StartDate { get; set; } public DateTime EndDate { get; set; } public string Comments { get; set; } }
When I try to send data to my controller, I get the error "Without a constructor without parameters for this object:
[HttpPost] public ActionResult Index(TradeSpendingEntryViewModel vm) { try { if (ModelState.IsValid) { return RedirectToAction("Index"); }
The stack trace indicates that this happens during model binding:
[MissingMethodException: there is no constructor without parameters for the object). System.RuntimeTypeHandle.CreateInstance (RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean & canBeCached, RuntimeMethodHandleInternal & ctor, Boolean & bNeedSecurityCheck) +0 System.RuntimeType.CreateInstanceSlow (Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark & stackMark) +113 System.RuntimeType.CreateInstanceDefaultCtor (Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark & stackMark) +232 System.Activator.CreateInstance (Type Type, Boolean nonPublic) +83 System.Aectivator +. System.Activator +. Mvc.DefaultModelBinder.CreateModel (ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +183
My problem should be how I set up my view, the markup of which I based on this article http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
@using (Html.BeginForm()) { <header class="clearfix"> <img src="../../Content/images/logo.png" alt="Irving Consumer Products" /> <h1>Enter Customer Deals</h1> </header> <hr /> <fieldset> <legend>Customer details</legend> <table> <tr> <th> Date: </th> <td> <input type="date" disabled="disabled" value="@DateTime.Today.ToShortDateString()" /> </tr> <tr> <th> Customer Number: </th> <td> @Html.TextBoxFor(m => m.CustomerNumber, new { id = "customer-number" }) <a href="#" id="change-customer-number">Change me</a> </td> </tr> <tr> <th> Customer Name: </th> <td> <input type="text" id="customer-name" disabled="disabled" /> </td> <tr> <th> Planning Year: </th> <td> @Html.DropDownList("PlanningYear", Model.PlanningYears) <a href="#" id="change-planning-year">Change me</a> </td> </tr> </table> </fieldset> <div class="buttonGroup"> <input type="button" value="Add line" id="add-line"> <input type="button" value="Copy line" id="copy-line"> <input type="button" value="Delete line" id="delete-line"> </div> <hr /> <table id="tradeSpendingEntry"> <thead> <tr> <th> </th> <th> Line of business </th> <th> Product Code </th> <th> Product Description </th> <th> Allowance <br /> Type </th> <th> Cases </th> <th> End Current Deal </th> <th> Start Date </th> <th> End Date </th> <th> Rate </th> </tr> </thead> @foreach (var r in Model.Records) { <tbody data-entry-index="0"> <tr> <td> <input type="checkbox" /> </td> <td> <input type="text" name="records[0].LOB" class="lobSelect" value="@r.LOB"> </td> <td> <input type="text" name="records[0].ProductCode" value="@r.ProductCode"> </td> <td> <input type="text" class="product-description" disabled="disabled" /> </td> <td> @Html.DropDownList("records[0].AllowType", r.AllowType) </td> <td> <input name="records[0].Cases" type="number" /> </td> <td> <select name="records[0].EndCurrentDeal"> <option value="true" selected="selected">Yes</option> <option value="false">No</option> </select> </td> <td> <input type="date" name="records[0].StartDate" /> </td> <td> <input type="date" name="records[0].EndDate" /> </td> <td> <input type="text" name="records[0].DealRate" /> </td> </tr> <tr> <td></td> <td> Comments: </td> <td colspan="8"> <input type="text" class="comment" name="records[0].Comments" /> </td> </tr> </tbody> } </table> <footer> <div class="buttonGroup"> <input type="submit" value="Submit Changes"> <input type="button" value="Main Menu"> <input type="button" value="View Customer Deals"> </div> </footer> }
So, I hope that the fields in the first field set will map to the immediate properties of the TradeSpendingEntryViewModel object (CustomerName, Date, PlanningYears). Then, for each representing TradeSpendingEntryViewModelRecord it will be attached as an element in the TradeSpendingEntryViewModel.Records collection. Instead, I just get the cryptic “No parameters without constructor” exception, despite the fact that both the ViewModel and the recording object have parallel constructors.
My question is: can I use the default middleware using the conventions mentioned in the above article, or do I need to create a custom middleware for this?
For completeness of use, the following markup of the form, which is generated after the user dynamically adds a line to the form through javascript:
<form method="post" action="/TradeSpendingEntry/Index"> <header class="clearfix"> <img alt="Irving Consumer Products" src="../../Content/images/logo.png"> <h1>Enter Customer Deals</h1> </header> <hr> <fieldset> <legend>Customer details</legend> <table> <tbody> <tr> <th> Date: </th> <td> <input id="dp1363608756704" class="hasDatepicker" type="date" value="18/03/2013" disabled="disabled" style="background-color: rgb(238, 238, 238);"> </td> </tr> <tr> <th> Customer Number: </th> <td> <input id="customer-number" type="text" value="" name="CustomerNumber"> <a id="change-customer-number" href="#">Change me</a> </td> </tr> <tr> <th> Customer Name: </th> <td> <input id="customer-name" type="text" disabled="disabled" style="background-color: rgb(238, 238, 238);"> </td> </tr> <tr> <th> Planning Year: </th> <td> <select id="PlanningYears" name="PlanningYears"> <option value="2011">2011</option> <option value="2012">2012</option> <option value="2013">2013</option> <option value="2014">2014</option> </select> <a id="change-planning-year" href="#">Change me</a> </td> </tr> </tbody> </table> </fieldset> <div class="buttonGroup"> <input id="add-line" type="button" value="Add line"> <input id="copy-line" type="button" value="Copy line"> <input id="delete-line" type="button" value="Delete line"> </div> <hr> <table id="tradeSpendingEntry"> <thead> <tr> <th> </th> <th> Line of business </th> <th> Product Code </th> <th> Product Description </th> <th> Allowance <br> Type </th> <th> Cases </th> <th> End Current Deal </th> <th> Start Date </th> <th> End Date </th> <th> Rate </th> </tr> </thead> <tbody data-entry-index="0"> <tr> <td> <input type="checkbox"> </td> <td> <input class="lobSelect" type="text" name="records[0].LOB"> </td> <td> <input type="text" name="records[0].ProductCode"> </td> <td> <input class="product-description" type="text" disabled="disabled" style="background-color: rgb(238, 238, 238);"> </td> <td> <select id="records_0__AllowType" name="records[0].AllowType"> <option selected="selected">BillBack$</option> <option>Billback%</option> <option>O&A%</option> <option>Coop%</option> <option>VR%</option> <option>Lump - O&A$</option> <option>Lump - CP$</option> <option>Lump - VR$</option> <option>Lump - BB$</option> </select> </td> <td> <input type="number" name="records[0].Cases"> </td> <td> <select name="records[0].EndCurrentDeal"> <option selected="selected" value="true">Yes</option> <option value="false">No</option> </select> </td> <td> <input id="dp1363608756707" class="hasDatepicker" type="date" name="records[0].StartDate"> </td> <td> <input id="dp1363608756708" class="hasDatepicker" type="date" name="records[0].EndDate"> </td> <td> <input type="text" name="records[0].DealRate"> </td> </tr> <tr> <td></td> <td> Comments: </td> <td colspan="8"> <input class="comment" type="text" name="records[0].Comments"> </td> </tr> </tbody> <tbody data-entry-index="1"> <tr> <td> <input type="checkbox"> </td> <td> <input class="lobSelect" type="text" name="records[1].LOB"> </td> <td> <input type="text" name="records[1].ProductCode"> </td> <td> <input class="product-description" type="text" disabled="disabled" style="background-color: rgb(238, 238, 238);"> </td> <td> <select id="records_0__AllowType" name="records[1].AllowType"> <option selected="selected">BillBack$</option> <option>Billback%</option> <option>O&A%</option> <option>Coop%</option> <option>VR%</option> <option>Lump - O&A$</option> <option>Lump - CP$</option> <option>Lump - VR$</option> <option>Lump - BB$</option> </select> </td> <td> <input type="number" name="records[1].Cases"> </td> <td> <select name="records[1].EndCurrentDeal"> <option selected="selected" value="true">Yes</option> <option value="false">No</option> </select> </td> <td> <input id="dp1363608756709" class="hasDatepicker" type="date" name="records[1].StartDate"> </td> <td> <input id="dp1363608756710" class="hasDatepicker" type="date" name="records[1].EndDate"> </td> <td> <input type="text" name="records[1].DealRate"> </td> </tr> <tr> <td></td> <td> Comments: </td> <td colspan="8"> <input class="comment" type="text" name="records[1].Comments"> </td> </tr> </tbody> </table> <footer> <div class="buttonGroup"> <input type="submit" value="Submit Changes"> <input type="button" value="Main Menu"> <input type="button" value="View Customer Deals"> </div> </footer> </form>