How to figure out which key of ModelState has error
You can check the ViewData.ModelState.Values
collection and see what are the Errors.
[Httpost]
public ActionResult Create(User model)
{
if(ModelState.IsValid)
{
//Save and redirect
}
else
{
foreach (var modelStateVal in ViewData.ModelState.Values)
{
foreach (var error in modelStateVal.Errors)
{
var errorMessage = error.ErrorMessage;
var exception = error.Exception;
// You may log the errors if you want
}
}
}
return View(model);
}
}
If you really want the Keys(the property name), You can iterate through the ModelState.Keys
foreach (var modelStateKey in ViewData.ModelState.Keys)
{
var modelStateVal = ViewData.ModelState[modelStateKey];
foreach (var error in modelStateVal.Errors)
{
var key = modelStateKey;
var errorMessage = error.ErrorMessage;
var exception = error.Exception;
// You may log the errors if you want
}
}
Get value from ModelState with key name
You can iterate through keys like this:
foreach (var modelStateKey in ViewData.ModelState.Keys)
{
//decide if you want to show it or not...
//...
var value = ViewData.ModelState[modelStateKey];
foreach (var error in value.Errors)
{
//present it
//...
}
}
How to get all Errors from ASP.Net MVC modelState?
foreach (ModelState modelState in ViewData.ModelState.Values) {
foreach (ModelError error in modelState.Errors) {
DoSomethingWith(error);
}
}
See also How do I get the collection of Model State Errors in ASP.NET MVC?.
ASP.Net Core: How do you get the key of an invalid ModelState value?
While debugging, you can type this:
ModelState.Where(
x => x.Value.Errors.Count > 0
).Select(
x => new { x.Key, x.Value.Errors }
)
into your Watch window.
This will collect all Keys generating error together with the error descritti in.
Returning a list of keys with ModelState errors
var errors = from modelstate in ModelState.AsQueryable().Where(f => f.Value.Errors.Count > 0) select new { Title = modelstate.Key };
How do you get errors in the ModelState, for a particular property?
Assuming you want the error(s) for proeprty Name
string propertyName = "Name";
To get the first error (which is what will be displayed when using @Html.ValidationSummary()
, you can use
string error = ViewData.ModelState.Keys.Where(k => k == propertyName)
.Select(k => ModelState[k].Errors[0].ErrorMessage).First();
or to get all errors for a property
IEnumerable<string> errors = ModelState.Keys.Where(k => k == propertyName)
.Select(k => ModelState[k].Errors).First().Select(e => e.ErrorMessage);
and use your foreach
as noted in the question
How to check if ModelState contains errors which are not properties
Ok i think i have working solution
@if (ViewData.ModelState.Keys.Contains(string.Empty))
{
@Html.ValidationSummary(true)
}
asp.net mvc model state errors keys
in the end I found a solution to this problem. It is a bit complicated but it works.
First I've created an attribute.
public class ClientNameAttribute : Attribute, IMetadataAware
{
public ClientNameAttribute(string name)
{
this.Name = name;
}
public string Name { get; set; }
public void OnMetadataCreated(ModelMetadata metadata)
{
metadata.AdditionalValues["ClientName"] = this.Name;
}
}
Notice that this attribute also implements IMetadataAware
Next step was to create Html helper, so I could call this in a view.
public static class HtmlHelperExtensions
{
public static string CustomModelState<T>(this HtmlHelper<T> helper)
{
var errors = helper.ViewData.ModelState.Select(
m => new { Key = GenerateClientName(m.Key, helper), Value = m.Value.Errors.FirstOrDefault() }).Where(e=> e.Value != null);
return Json.Encode(errors);
}
private static string GenerateClientName<T>(string key, HtmlHelper<T> helper)
{
StringBuilder builder = new StringBuilder();
int periodIndex = -1;
do
{
periodIndex = key.IndexOf('.', periodIndex + 1);
string part = key.Substring(0, periodIndex==-1 ? key.Length : periodIndex);
var partMetadata = ModelMetadata.FromStringExpression(part, helper.ViewData);
object clientName;
if (builder.Length > 0)
{
builder.Append('.');
}
if (partMetadata.AdditionalValues.TryGetValue("ClientName", out clientName))
{
builder.Append(clientName);
}
else
{
builder.Append(partMetadata.PropertyName);
}
}
while (periodIndex != -1);
return builder.ToString();
}
}
CustomModelState
is a method that I call in a view.
like this:
var errors = @Html.Raw(Html.CustomModelState());
if (errors.length > 0) {
showErrors("masterModel",errors);
}
this will give you nicely formated errors, with your custom names of properties.
And here are tests for it:
public class TestModel
{
[Required]
public string Normal { get; set; }
[ClientName("Other")]
[Required]
public string Changed { get; set; }
[ClientName("Complicated")]
public TestModelTwo TestModelTwo { get; set; }
}
public class TestModelTwo
{
public string PropertyOne { get; set; }
[ClientName("Two")]
public string PropertyTwo{ get; set; }
}
[TestClass]
public class HtmlHelperExtensionsTests
{
[TestMethod]
public void CustomModelStateTests()
{
var model = new TestModel();
var page = new ViewPage();
page.ViewData.Model = model;
page.ViewData.ModelState.AddModelError("Normal", "Error1");
page.ViewData.ModelState.AddModelError("Changed", "Error2");
HtmlHelper<TestModel> helper = new HtmlHelper<TestModel>(new ViewContext(), page);
var custom = helper.CustomModelState();
string expectedResult =
"[{\"Key\":\"Normal\",\"Value\":{\"Exception\":null,\"ErrorMessage\":\"Error1\"}},{\"Key\":\"Other\",\"Value\":{\"Exception\":null,\"ErrorMessage\":\"Error2\"}}]";
Assert.AreEqual(expectedResult, custom);
}
[TestMethod]
public void CustomModelStateTests_ObjectProperty_With_ClientName()
{
var model = new TestModel();
model.TestModelTwo = new TestModelTwo();
var page = new ViewPage();
page.ViewData.Model = model;
page.ViewData.ModelState.AddModelError("TestModelTwo.PropertyOne", "Error1");
page.ViewData.ModelState.AddModelError("TestModelTwo.PropertyTwo", "Error2");
HtmlHelper<TestModel> helper = new HtmlHelper<TestModel>(new ViewContext(), page);
var custom = helper.CustomModelState();
string expectedResult =
"[{\"Key\":\"Complicated.PropertyOne\",\"Value\":{\"Exception\":null,\"ErrorMessage\":\"Error1\"}},{\"Key\":\"Complicated.Two\",\"Value\":{\"Exception\":null,\"ErrorMessage\":\"Error2\"}}]";
Assert.AreEqual(expectedResult, custom);
}
}
Get error message if ModelState.IsValid fails?
You can do this in your view without doing anything special in your action by using Html.ValidationSummary() to show all error messages, or Html.ValidationMessageFor() to show a message for a specific property of the model.
If you still need to see the errors from within your action or controller, see the ModelState.Errors property
Related Topics
Changing the View for a Viewmodel
Bug: Can't Choose Dates on a Datepicker That Fall Outside a Floating VSto Add-In
How to Dynamically Switch Web Service Addresses in .Net Without a Recompile
Benefits of Using Async and Await Keywords
Adding Custom Properties for Each Request in Application Insights Metrics
How to Generically Format a Boolean to a Yes/No String
Get Window State of Another Process
How to Remove a Single Attribute (E.G. Readonly) from a File
With Rx, How to Ignore All-Except-The-Latest Value When My Subscribe Method Is Running
Frombluetoothaddressasync Iasyncoperation Does Not Contain a Definition for 'Getawaiter' Error
Advantage of Using Thread.Start VS Queueuserworkitem
Why Does Binarywriter Prepend Gibberish to the Start of a Stream? How to Avoid It
How to Stop an Animation in C#/Wpf
Making Specific Text Boldefaced in a Textbox
How to Get Around Lack of Covariance with Ireadonlydictionary