我有一个表单,我们希望为单个客户输入多笔交易。表单的viewmodel如下所示:
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; }
}
我们希望能够使用javascript动态添加和删除记录条目行。该集合中的每条记录都是:
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; }
}
当我尝试将数据发布到控制器时,出现错误,指示“没有为此对象定义无参数构造函数:
[HttpPost]
public ActionResult Index(TradeSpendingEntryViewModel vm)
{
try
{
if (ModelState.IsValid)
{
return RedirectToAction("Index");
}
// TODO: Add insert logic here
return View(vm);
}
catch
{
return View();
}
}
堆栈跟踪表明它在模型绑定期间发生:
[MissingMethodException:没有为此对象定义无参数构造函数。] System.RuntimeTypeHandle.CreateInstance(RuntimeType类型,Boolean publicOnly,Boolean noCheck,Boolean&amp; canBeCached,RuntimeMethodHandleInternal&amp; ctor,Boolean&amp; bNeedSecurityCheck)+0 System.RuntimeType.CreateInstanceSlow(Boolean publicOnly,Boolean skipCheckThis,Boolean fillCache,StackCrawlMark&amp; stackMark)+113 System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly,Boolean skipCheckThis,Boolean fillCache,StackCrawlMark&amp; stackMark)+232 System.Activator.CreateInstance(Type type,Boolean nonPublic)+83 System.Activator.CreateInstance(类型类型)+6 System.Web.Mvc.DefaultModelBinder.CreateModel(ControllerContext controllerContext,ModelBindingContext bindingContext,Type modelType)+183
我的问题必须源于我如何设置我的观点,我根据这篇文章制作标记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="hidden" name="records[0]ProductCodeSelected" value="@r.ProductCode" />-->
<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>
}
所以,我希望第一个字段集中的字段将映射到TradeSpendingEntryViewModel对象(CustomerName,Date,PlanningYears)的直接属性。然后,对于每个表示TradeSpendingEntryViewModelRecord的项将被绑定为TradeSpendingEntryViewModel.Records集合中的项。相反,我只是得到一个神秘的“无参数构造函数定义”异常,尽管ViewModel和记录对象都有无参数构造函数。
我的问题是,我可以使用上述文章中指出的约定来使用默认模型绑定器,还是需要为此目的构建自定义模型绑定器?
为了完整起见,以下是用户通过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>
答案 0 :(得分:11)
毫无疑问,它是SelectList
。我昨天遇到了同样的问题。
如果查看SelectList,它的所有构造函数都需要一个参数。 http://msdn.microsoft.com/en-us/library/system.web.mvc.selectlist(v=vs.108).aspx
问题在于Action
被称为public ActionResult Index(TradeSpendingEntryViewModel vm)
控制器尝试将POST
上发回的数据绑定到TradeSpendingEntryViewModel
,然后需要通过创建新{{1}来设置PlanningYears
的值。 }}
要解决此问题,您需要将SelectList设置为私有变量(即后备字段),然后默认将其设置为空列表。这为它提供了所需的参数化构造函数:
SelectList
或将PlanningYears更改为列表&lt;&gt;并将其转换为视图上的选择列表。
//select list
private SelectList planningYears = new SelectList(new List<YourObject>());
public SelectList PlanningYears
{
get
{
return planningYears;
}
set
{
locations = planningYears;
}
}
答案 1 :(得分:-1)
我有一个更好的主意!简单地将您的属性(selectList)声明为方法:
执行以下操作
//fill it if whatever you want from db
private List<YourList> happyList = new List<YourList>();
//that way mvc will never try to instantiate selectList on Action execution
public SelectList PlanningYears()
{
return new SelectList(happyList,"happyID","happyDesc","");
}
很多时候在c#中做属性让我忘记它是多么简单....