37

I am new to web development and trying to learn ASP.Net MVC 5. I am looking for one record in database if the record is not found then I want to display an error message to the user. Below is my attempt:

Controller

    [HttpGet]
    public ActionResult Search()
    {
        return View();
    }

    [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();
        }
    }

View:

<p>@ViewBag.ErrorMessage</p>

ViewModel

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

But I read somewhere that I should put one property in my view model and set the error message on that property. I am confused now, how to achieve that and how to display the error in View then? And which one is the recommended/best practice?

5 Answers 5

62

But I read somewhere that I should put one property in my view model and set the error message on that property. I am confused now, how to achieve that and how to display the error in View then? And which one is the recommended/best practice?

The best practice is to alter the ModelState dictionary property of your controller like this:

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

Then in your view add the line below next to your email field;

@Html.ValidationMessageFor(m => m.Email)
Sign up to request clarification or add additional context in comments.

9 Comments

I like this solution as it is using Html Helper so I do not need to take care of other stuffs. So. I should follow this approach as best practice. But another answer to this question is more towards adding the error property to the Model. Can you please explain me What is actually ModelState.AddModelError is doing. I know if we put a field as [Required] and then we check the modelstate.isvalid then we can catch the error there. Is this AddError doing the same thing under the hood but its more custom made?
Yes that is exact. This is the best practice because imagine that you have many properties on your model you will end up creating many error message property for each of your model properties which will end up bloating your model. Using ModelState.AddModelError help to avoid that kind of things.
One thing I noticed it that KeyName should be same as the property name so that it can tied to that particular property.So basically first parameter in AddModelError is kind of tells that to which property in our model we need to bind this error message to. Kindly rectify me if I am wrong. But anyways thank you for the answer. :)
Yes. Also you can put an empty string as a key so the error message with be tied to the entire model. If you use thiat solution you must use this line @Html.ValidationSummary(true, "The following error has occured:")
@CodeNotFound, i had a similar situation and your solution worked like a charm for me. Much appreciated !!
|
6

But I read somewhere that I should put one property in my view model and set the error message on that property.

That's correct. You could add the error message to your view model:

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

    public string ErrorMessage { get; set; }
}

and then set this property on your view model and pass the view model to the view:

...
else
{
    viewModel.ErrorMessage = "Email not found or matched";
    return View(viewModel);
}

and finally in your strongly typed view use the property on your model:

@model ForgotPasswordMV
...
<p>@Model.ErrorMessage</p>

So basically here we are replacing the use of ViewBag with a strongly typed view model.

3 Comments

And is this the recommended practice? How you would have done if you had to do it? Viewbag or property in modelview?
Can you kindly see below answer, and let me know if that is the best practice as it is using helper methods
@Darin Dimitrov I have tried this but I am getting a NullReferenceException upon page load?
5

If anyone is looking for a simple fix and NOTHING PERMANENT than feel free to use this answer as this helped me out. DO NOT use this fix if you have to worry about security within your application.

In your controller:

TempData["Message"] = "This is my Error";

In your Error.cshtml file:

<h3><strong>@TempData["Message"]</strong></h3>

Result:

enter image description here

2 Comments

Please keep accesiblity in mind. using a heading to format an element without special meaning is failure in context of the WCAG. Error might be a heading. This is my error might be a list.
Yes, absolutely, this was only meant to be a quick example that may resolve the issue at hand.
2

As for me accepted anwser is not the best practice. We can handle all errors in annotations.
In our ViewModel we specify ErrorMessages for our properites.

public class UserLoginViewModel
{
    [Required(ErrorMessage = "User name is required")]
    [Display(Name = "User name")]
    [StringLength(500, ErrorMessage = "User name is too short", MinimumLength = 3)]
    public string Login { get; set; }

    [Required(ErrorMessage = "Password is required")]
    [Display(Name = "Password")]
    public string Password { get; set; }
}

In our controller

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(UserLoginViewModel model)
{
    if (!this.ModelState.IsValid)
    {
        return this.View();
    }
    ...
}

And our view

@Html.ValidationMessageFor(model => model.Login)
@Html.EditorFor(model => model.Login)
@Html.ValidationMessageFor(model => model.Password)
@Html.EditorFor(model => model.Password)

2 Comments

Here we are talking about errors that are coming from business logic, not the standard ones.
Aww, right. So maybe Remote Validation will be useful for someone. You could also use RV to check for email match/find.
0

I spent a lot of time to find the best solution for this too. It's very simple. In your Controller you can send an message like this.

        if (UnitCount >= 1000)
        {
            TempData["MsgChangeStatus"] = "Only 1000 units are allowed to modify at the same time!";
            return RedirectToAction("ChangeStatus");
        }

It's very important, after you use the TempData command you have to use an Return View() or return RedirectToAction() immediately, because these commands can send your message to the View.

In the View, you have to add the following part.

 @{
ViewBag.Title = "UnitState Change";
Layout = "~/Views/Shared/_Layout.cshtml";
var message = TempData["MsgChangeUS"] ?? string.Empty;
}


<script type="text/javascript">
var message = '@message';
if(message)
    alert(message);
</script>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.