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
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?.
ModelState.IsValid == false, why?
About "can it be that 0 errors and IsValid == false": here's MVC source code from https://github.com/Microsoft/referencesource/blob/master/System.Web/ModelBinding/ModelStateDictionary.cs#L37-L41
public bool IsValid {
get {
return Values.All(modelState => modelState.Errors.Count == 0);
}
}
Now, it looks like it can't be. Well, that's for ASP.NET MVC v1.
Model State Is Not Valid But Why?
ModelState
has a property that will tell you exactly why it's not valid. Use that.
Here's an answer with an example: Get error message if ModelState.IsValid fails?
Custom RequiredIfAttribute not producing error message on ModelState.IsValid check
In the end it was actually a very simple fix I had set the default value of the sub dropdownlist to 0 as shown below:
SelectListItem defaultItem = new SelectListItem();
defaultItem.Value = "0";
defaultItem.Text = "Sub organisation type...";
items.Add(defaultItem);
This was causing both the client and server side validation to validate the selection as true.
In order to fix I removed the default of 0 to an empty string again this change is shown below:
SelectListItem defaultItem = new SelectListItem();
defaultItem.Value = "";
defaultItem.Text = "Sub organisation type...";
items.Add(defaultItem);
Display errors from ModelState.Values
There is no need to pass errors explicitly by using ViewBag. The model state dictionary will have the errors when model validation fails. All you have to do is to execute your code when the model validation passes.
Also, since you already have a class, you can use that as the parameter of your http post action method. The default model binder will be able to map the form values to the properties of this class's object.
[HttpPost]
[Route("quotes")]
public IActionResult Quotes(Home model)
{
if(!ModelState.IsValid)
{
return View(model);
}
//continue your code to save
return RedirectToAction("Index");
}
And in the view you may use the validation helper methods to display the validation errors
@Html.ValidationSummary(false)
Also , i noticed you have nested forms in the view. Nested forms are not valid markup. So i suggest you fix that as well.
<h1>Welcome to the Quoting Dojo</h1>
@using(Html.BeginForm("Quote","Home"))
{
<p>@Html.ValidationSummary(false)</p>
<p>
<label>Your Name</label>
@Html.TextBoxFor(s=>s.Name)
</p>
<p>
<label>Your Quote</label>
@Html.TextAreaFor(d=>d.Quote)
</p>
<input type="submit" name="submit" value="Add my quote!"/>
}
<form action="quotes" method="get">
<input type="submit" name="submit" value="Skip to quotes!"/>
</form>
ModelState.IsValid Is Always Returning False Edit Form
What the code says. Model is not valid. That could be anything in regards to the model you are passing though the endpoint. Perhaps ItemModel has a [Required] attribute on one of its properties and you are trying to pass a NULL value on that property.
Also, as per the comment from Stephen Muecke:
You can inspect ModelState to determine the Keys (property names) and associated errors by accessing the Keys property of the ModelState like so
var errors = ModelState.Keys
.Where(k => ModelState[k].Errors.Count > 0)
.Select(k => new
{
propertyName = k,
errorMessage = ModelState[k].Errors[0].ErrorMessage
}).ToList()
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
}
}
Related Topics
Possible to Use Automapper to Map One Object to List of Objects
Entity Framework Code First Lazy Loading
Does ASP.NET MVC Have Application Variables
Entity Framework/Linq to SQL: Skip & Take
Visual Studio One Project with Several Dlls as Output
"Async Task Then Await Task" VS "Task Then Return Task"
What Is the C# Equivalent of Nan or Isnumeric
Write Values in App.Config File
How to Extend Identityuser with Custom Property
C# Native Host with Chrome Native Messaging
How to List All Loaded Assemblies
Cast Linq Result to Observablecollection
How to Generate a Hashcode from a Byte Array in C#
Why Does Timespan.Parseexact Not Work
How to Ignore the Utf-8 Byte Order Marker in String Comparisons