当ViewModel是(有)集合时,是否可以将ViewModel属性与匹配的ModelState.Key值匹配?
示例:要编辑viewmodel项的集合,我使用的是extension found here。
这会在页面上的字段ID中添加GUID。
示例:
class Pets
{
string animal;
string name;
}
对于Pets列表,生成的html源代码如下:
<input name="Pets.index" autocomplete="off" value="3905b306-a9..." type="hidden">
<input value="CAT" id="Pets_3905b306-a9...__animal" name="Pets[3905b306-a9...].animal" type="hidden">
<input value="MR. PEPPERS" id="Pets_3905b306-a9...__name" name="Pets[3905b306-a9...].name" type="hidden">
<input name="Pets.index" autocomplete="off" value="23342306-b4..." type="hidden">
<input value="DOG" id="Pets_23342306-b4...__animal" name="Pets[23342306-b4...].animal" type="hidden">
<input value="BRUTICUS" id="Pets_23342306-b4...__name" name="Pets[23342306-b4...].name" type="hidden">
因此,当它在post上绑定时,ModelState会加载所有表单字段。 在ModelSTate.Keys中,有:
Pets[23342306-b4...].name
Pets[23342306-b4...].animal
Pets[3905b306-a9...].name
Pets[3905b306-a9...].animal
到目前为止一切都很好,但我正在进行一些业务逻辑验证,例如,如果存在同名的新动物,则无法添加新动物。在这种情况下,我希望能够突出显示错误的输入字段。
因此,如果我的create函数失败,它将返回一个错误/键值对,如下所示:
{ error = "Duplicate Name", key="name" }
所以我至少会知道什么财产导致了这个问题。
但由于我的存储库函数不知道视图字段ID,如何将键“name”与相应的ModelState键匹配(在本例中,Pets [23342306-b4 ...]。name或宠物[3905b306-A9 ...]。名)?
答案 0 :(得分:0)
如果您使用MVC的内置功能来显示具有适当显示/编辑器模板的集合(Html.DisplayFor(m => m.Pets)
或Html.EditorFor(m => m.Pets)
),MVC将呈现如下内容:
Pets[0].name
Pets[0].animal
Pets[1].name
Pets[1].animal
这映射到IEnumerable<Pets>
,你知道第一项的索引是0,第二项是等等。
因此,如果第二项有错误,您可以为ModelState
键"Pets[1].name"
设置错误。
答案 1 :(得分:0)
如果您正在使用Html.BeginCollectionItem扩展方法,就像我一样,我可以通过不使用GUID来解决这个问题。我需要动态添加和删除,但我总是查找已知的项目,具有ID的人,我在编辑器中。因此,我只是在下面的代码中分配ID(uniqueId),而不是使用GUID。然后我可以找到钥匙,因为我知道这是人[234232]。当然,如果您要添加新项目而不显示所选项目,则可能对您无效。
public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName, string uniqueId)
{
var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : uniqueId;
// autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));
return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
}