Problem
I have a list of fields that the user can edit. When the model is submitted I want to check if this items are valid. I can't use data notations because each field has a different validation process that I will not know until runtime. If the validation fails I use the ModelState.AddModelError(string key, string error)
where the key is the name of the html element you want to add the error message to. Since there are a list of fields the name that Razor generates for the html item is like Fields[0].DisplayName
. My question is there a method or a way to get the key of the generated html name from the view model?
Attempted Solution
I tried the toString()
method for the key with no luck. I also looked through the HtmlHelper
class but I didn't see any helpful methods.
Code Snippet
View Model
public class CreateFieldsModel
{
public TemplateCreateFieldsModel()
{
FreeFields = new List<FieldModel>();
}
[HiddenInput(DisplayValue=false)]
public int ID { get; set; }
public IList<TemplateFieldModel> FreeFields { get; set; }
public class TemplateFieldModel
{
[Display(Name="Dispay Name")]
public string DisplayName { get; set; }
[Required]
[Display(Name="Field")]
public int FieldTypeID { get; set; }
}
}
Controller
public ActionResult CreateFields(CreateFieldsModel model)
{
if (!ModelState.IsValid)
{
//Where do I get the key from the view model?
ModelState.AddModelError(model.FreeFields[0], "Test Error");
return View(model);
}
}
After digging around in the source code I have found the solution. There is a class called ExpressionHelper
that is used to generate the html name for the field when EditorFor()
is called. The ExpressionHelper
class has a method called GetExpressionText()
that returns a string that is the name of that html element. Here is how to use it ...
for (int i = 0; i < model.FreeFields.Count(); i++)
{
//Generate the expression for the item
Expression<Func<CreateFieldsModel, string>> expression = x => x.FreeFields[i].Value;
//Get the name of our html input item
string key = ExpressionHelper.GetExpressionText(expression);
//Add an error message to that item
ModelState.AddModelError(key, "Error!");
}
if (!ModelState.IsValid)
{
return View(model);
}
You have to frame the key(name of the input element) inside the controller based upon how you are rendering the fields in the form.
For ex. if the validation of the second item in the FreeFields
collection of CreateFieldsModel
fails you can frame the name of the input element i.e. key as FreeFields[1].DisplayName
where the validation error is going to be mapped.
As far as I know you can't easily get that from controller.
来源:https://stackoverflow.com/questions/11090445/how-to-get-a-modelstate-key-of-an-item-in-a-list