所以我有一个像这样的控制器:
public class TestController : Controller
{
//
// GET: /Test/
public ActionResult Index()
{
return View("Test");
}
public ActionResult Post(IList<Test> LanguageStrings, IList<Test> LanguageStringsGroup, IList<string> Deleted, IList<string> DeletedGroup)
{
if (LanguageStrings == null)
{
throw new ApplicationException("NULL");
}
return View("Test");
}
}
public class Test
{
public string Val { get; set; }
public string Another { get; set; }
}
这样的观点:
<h2>Test</h2>
@using (Html.BeginForm("Post", "Test"))
{
@Html.Hidden("LanguageStrings[0].Val", "test1")
@Html.Hidden("LanguageStrings[0].Another")
@Html.Hidden("LanguageStrings[1].Val", "test2")
@Html.Hidden("LanguageStrings[1].Another")
@Html.Hidden("LanguageStringsGroup[0].Val", "test4")
@Html.Hidden("Deleted[0]")
@Html.Hidden("Deleted[1]")
@Html.Hidden("Deleted[2]")
@Html.Hidden("DeletedGroup[0]")
<button>Post</button>
}
当我发布表单时,我的控制器会抛出异常,因为LanguageStrings为null。我在标题中提到的一个奇怪的部分是,如果我在列表中再添加一条记录,一切正常。 像这样:
<h2>Test</h2>
@using (Html.BeginForm("Post", "Test"))
{
@Html.Hidden("LanguageStrings[0].Val", "test1")
@Html.Hidden("LanguageStrings[0].Another")
@Html.Hidden("LanguageStrings[1].Val", "test2")
@Html.Hidden("LanguageStrings[1].Another")
@Html.Hidden("LanguageStrings[2].Val", "test3")
@Html.Hidden("LanguageStrings[2].Another")
@Html.Hidden("LanguageStringsGroup[0].Val", "test4")
@Html.Hidden("Deleted[0]")
@Html.Hidden("Deleted[1]")
@Html.Hidden("Deleted[2]")
@Html.Hidden("DeletedGroup[0]")
<button>Post</button>
}
当我删除“已删除”列表时,它也有效。 像这样:
<h2>Test</h2>
@using (Html.BeginForm("Post", "Test"))
{
@Html.Hidden("LanguageStrings[0].Val", "test1")
@Html.Hidden("LanguageStrings[0].Another")
@Html.Hidden("LanguageStrings[1].Val", "test2")
@Html.Hidden("LanguageStrings[1].Another")
@Html.Hidden("LanguageStringsGroup[0].Val", "test4")
@Html.Hidden("DeletedGroup[0]")
<button>Post</button>
}
这与我正在使用的命名有关。我已经解决了将LanguageStrings重命名为其他问题的问题。但我想了解这里发生了什么,因为我可以从中学到一些东西,MVC如何映射请求体,并且能够避免类似的耗时问题。 请帮助我解释原因。
答案 0 :(得分:5)
您在MVC 4的PrefixContainer中发现了一个已在MVC 5中修复的错误。
这是固定版本,其中包含有关错误的评论:
internal bool ContainsPrefix(string prefix)
{
if (prefix == null)
{
throw new ArgumentNullException("prefix");
}
if (prefix.Length == 0)
{
return _sortedValues.Length > 0; // only match empty string when we have some value
}
PrefixComparer prefixComparer = new PrefixComparer(prefix);
bool containsPrefix = Array.BinarySearch(_sortedValues, prefix, prefixComparer) > -1;
if (!containsPrefix)
{
// If there's something in the search boundary that starts with the same name
// as the collection prefix that we're trying to find, the binary search would actually fail.
// For example, let's say we have foo.a, foo.bE and foo.b[0]. Calling Array.BinarySearch
// will fail to find foo.b because it will land on foo.bE, then look at foo.a and finally
// failing to find the prefix which is actually present in the container (foo.b[0]).
// Here we're doing another pass looking specifically for collection prefix.
containsPrefix = Array.BinarySearch(_sortedValues, prefix + "[", prefixComparer) > -1;
}
return containsPrefix;
}
答案 1 :(得分:0)
我使用@ Html.HiddenFor()获得了更多成功,可以回发给控制器。代码看起来像这样:
@for (int i = 0; i < @Model.LanguageStrings.Count; i++)
{
@Html.HiddenFor(model => model.LanguageStrings[i].Val, string.Format("test{0}", i))
@Html.HiddenFor(model => model.LanguageStrings[i].Another)
}
大多数HTML帮助程序方法都有一个“For”帮助程序,用于将数据绑定到模型。这是网站上的另一篇文章,它很好地解释了“For”方法:What is the difference between Html.Hidden and Html.HiddenFor