ASP.Net MVC 4.0 - Validation Issues With array based properties on ViewModel .
Scenario : When a ViewModel has a string array as a property type,the default Scaffolding template for say, Edit, does not render the that property in the markup.
Say, I have ViewModel setup like this :
Employee.cs
public class Employee
{
[Required]
public int EmpID
{
get;
set;
}
[Required]
public string FirstName
{
get;
set;
}
[Required]
public string LastName
{
get;
set;
}
[Required]
public string[] Skills
{
get;
set;
}
}
}
The (strongly typed) Edit View generated by the scaffolding template, as shown below, typically skips the portion relevant to field Skills.
**Employee.cshtml**
@model StringArray.Models.Employee
@{
ViewBag.Title = "EditEmployee";
}
<h2>EditEmployee</h2>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Employee</legend>
<div class="editor-label">
@Html.LabelFor(model => model.EmpID)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.EmpID)
@Html.ValidationMessageFor(model => model.EmpID)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.FirstName)
@Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.LastName)
@Html.ValidationMessageFor(model => model.LastName)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
The corresponding Controller code is
..
[HttpGet]
public ActionResult EditEmployee()
{
Employee E = new Employee()
{
EmpID = 1,
FirstName = "Sandy",
LastName = "Peterson",
Skills = new string[] { "Technology", "Management", "Sports" }
};
return View(E);
}
[HttpPost]
public ActionResult EditEmployee(Employee E)
{
return View(E);
}
To get the missing section for the Skills field, I added
Snippet to the View
<div class="editor-label"> @Html.LabelFor(model => model.Skills) </div> <div class="editor-field"> @Html.EditorFor(model => model.Skills) @Html.ValidationMessageFor(model => model.Skills) </div>Corresponding UIHint to the ViewModel
[UIHint("String[]")] public string[] Skills ...
EditorTemplates inside relevant folder as ~\View\shared\EditorTemplates\String[].cshtml and ~\View\shared\EditorTemplates\mystring.cshtml
string[].cshtml
@model System.String[] @if(Model != null && Model.Any()) { for (int i = 0; i < Model.Length; i++) { @Html.EditorFor(model => model[i], "mystring") //Html.ValidationMessageFor(model => model[i]) } }mystring.cshtml
@model System.String @{ //if(Model != null) { //To resolve issue/bug with extra dot getting rendered in the name - like //Skills.[0], Skills.[1], etc. //ViewData.TemplateInfo.HtmlFieldPrefix=ViewData.TemplateInfo.HtmlFieldPrefix.Replace(".[", "["); @Html.TextBoxFor(model => model) } }
But despite this all, the Validations for the Skills section [with 3 fields/elements - refer the EditEmployee method in Controller above.] are entirely skipped, on postback.
I tried below changes inside the mystring.cshtml EditorTemplate :
//to correct the rendered names in the browser from Skills.[0] to Skills for all the 3 items in the
//Skills (string array), so that model binding works correctly.
string x = ViewData.TemplateInfo.HtmlFieldPrefix;
x = x.Substring(0, x.LastIndexOf("."));
@Html.TextBoxFor(model =>model, new { Name = x })
Postback WORKS But Validations DON'T, since the "data-valmsg-for" still points to <span class="field-validation-valid" data-valmsg-for="Skills" data-valmsg-replace="true"></span>
and thus doesn't apply at granular level - string element level.
Lastly, I tried removing @Html.ValidationMessageFor(model => model.Skills) from the Employee.cshtml and correspondingly adding the same to string[].cshtml as @Html.ValidationMessageFor(model => model[i]). But this led to data-valmsg-for getting rendered for each granular string element like
data-valmsg-for="Skills.[0]" , data-valmsg-for="Skills.[1]" and data-valmsg-for="Skills.[2]", respectively.
Note: Validations work for other fields - EmpID, FirstName LastName, BUT NOT for Skills.
Question How do I set the data-valmsg-for="Skills" for each of the above three granular elements related to Skills property.
I am stuck on this for quite some time now. It would be nice if some one can point out the issue, at the earliest.
Thanks, Sandesh L