How to Figure Out Which Key of Modelstate Has Error

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



Leave a reply



Submit