I recently answered a question that came up on the StackOverflow website. Here was the situation.

Let's consider the following model:

public class ForgotPasswordMV
{
    [Display(Name = "Enter your email"), Required]
    public string Email { get; set; }
}

 

This model is used in a controller action as follows:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Search(ForgotPasswordMV viewModel)
{
    if(Temp.Check(viewModel.Email))
        return RedirectToAction("VerifyToken"new { query = viewModel.Email });
    else
    {
        ViewBag.ErrorMessage = "Email not found or matched";
        return View();
    }
}

 

The question was whether using the ViewBag dynamic property of the controller to expose the error message was a good practice, as the OP investigations suggested that it was necessary to expose properties from the model.

Obviously it is highly recommended NOT to use the ViewBag property since it does not provide any Strong Typing. If you want to communicate with the view you should always involve a typed model. The suggested solution is therefore legitimate in that respect, however, it is not a good practice when it comes to model error handling in ASP.NET MVC.

 

The solution for exposing error messages (as in the previous example, which does not use data annotation attributes) derives from the use of the AddModelError method, from the ModelStateDictionary class. We do not need to instantiate this class because a ModelState property containing an instance of this class already exists in the Controller.

 

Therefore, the right solution is the following:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Search(ForgotPasswordMV viewModel)
{
    if
    {
        // ...
    }
    else
    {
        this.ModelState.AddModelError("Email", "Email not found or matched");
        return View(viewModel);
    }
}

 

 

It should be noted that this method receives as first parameter the name of the property of the model to which the error message is associated. So, in order to display this error message in the view near the Email field, you can simply add the following line next to it:

@Html.ValidationMessageFor(m => m.Email)

 

However it is possible to have a general error message for the whole model, that is, an error message which is not attached to any property of the model. For this, it would be necessary to use an empty String as first parameter:

ModelState.AddModelError(String.Empty, "Email not found or matched");

 

In the Razor View, use the following line:

@Html.ValidationSummary(true, "The following error has occured:")

 

The first Boolean parameter indicates that you do not want to display error messages that are already attached to model properties.

 

In this post, we saw that we do not need to pollute our model, nor do we need to attach our error messages to specific properties. It's all about using ASP.NET MVC tools to make things easy.

I hope this post has been helpful to you.

 

[Translated from a contribution by Holty Sow]