0

I have an Asp.NET MVC application in which I use data annotations to add validation to some fields:

    [Required]
    [DisplayName("Course Name")]
    string Name { get; set; }

However this doesn't seem to work as I expected. Basically If the page contains any other errors that I manually check for and throw a new RuleViolation(), then the required violation is shown in the Validation Summary. If the required violation is the only error then it is not shown.

My controller has this code in it:

        catch (Exception ex)
        {
            ModelState.AddModelError("", ex.Message);
            ModelState.AddRuleViolations(courseViewModel.Course.GetRuleViolations());
            return View(courseViewModel);
        }

But given that the required violation is not throwing, I never go in here.

Do I need to do something that I dont know about to trap errors raised by DataAnnotation violation?

Thanks for any help

Edit:

Here is the controller action:

    [HttpPost]
    [ValidateInput(true)]
    public ActionResult Edit(int id, CourseViewModel courseViewModel)
    {

        var oldCourse = _eCaddyRepository.GetCourse(id);

        if (courseViewModel.Course == null)
        {
            return View("NotFound", string.Format("Course {0} Not Found", id));
        }

        try
        {
            courseViewModel.Update(oldCourse);
            _eCaddyRepository.SubmitChanges();

            return RedirectToAction("Index", "Course");
        }
        catch (Exception ex)
        {
            ModelState.AddModelError("", ex.Message);
            ModelState.AddRuleViolations(courseViewModel.Course.GetRuleViolations());
            return View(courseViewModel);
        }
    }

Where Update is :

    public class CourseViewModel : BaseViewModel
{
    public Course Course { get; set; }

    public void Update(Course oldCourse)
    {
        oldCourse.Name = this.Course.Name != null ? this.Course.Name.Trim() : string.Empty;
        oldCourse.Postcode = this.Course.Postcode != null ? this.Course.Postcode.Trim() : string.Empty;

        for (var i = 0; i < 18; i++)
        {
            oldCourse.Holes[i].Par = this.Course.Holes[i].Par;
            oldCourse.Holes[i].StrokeIndex = this.Course.Holes[i].StrokeIndex;
        }
    }
}

EDIT: Final code that works and validates as expected using dataannotations. Thanks to mare.

    [HttpPost]
    [ValidateInput(true)]
    public ActionResult Edit(int id, CourseViewModel courseViewModel)
    {
        var oldCourse = _eCaddyRepository.GetCourse(id);

        if (courseViewModel.Course == null)
        {
            return View("NotFound", string.Format("Course {0} Not Found", id));
        }

        if (ModelState.IsValid)
        {
            try
            {
                courseViewModel.Update(oldCourse);
                _eCaddyRepository.SubmitChanges();
                return RedirectToAction("Index", "Course");
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex.Message);
            }
        }

        // Return Model with errors
        ModelState.AddRuleViolations(courseViewModel.Course.GetRuleViolations());
        return View(courseViewModel);
    }
chrisp_68
  • 1,731
  • 23
  • 41
  • It depends on the code in your controller - specifically how you're updating the model. Can you post the full action method? – Jon Jul 24 '10 at 14:31
  • Hi Jon, thanks for hte reply. I have edited the original post to include the action. I have done it like this to avoid a problem I was having with Linq to Sql when updating. I would love to hear if there is there a better way? – chrisp_68 Jul 24 '10 at 18:41
  • The three lines of code in your try..catch block have nothing to do with Model Validation and DataAnnotations attaached to your model - here you are only "trying" to execute those three sentences and if they run fine (and I assume they do because they have no internal logic to check for Model validity) then no exception is thrown. What you need is ModelState.IsValid, see my answer. – mare Jul 25 '10 at 15:44

3 Answers3

3

I wonder how no one else pointed this out (jfar was close but his wording was off so chrisp_68 probably did not understand what jfar meant with model state violations) but you are missing this from your controller:

        if (ModelState.IsValid) // this check for model validity, not try..catch block
        {
            // do your stuff here, update to the datastore and return another view
        }

        // you can add additional Model State errors here manually if you wish
        // with AddModelError() like you do it now
        return View(editing); // return the same view with errors

So it's ModelState.IsValid check that you need, because DataAnnotations won't perform any exception throwing by themselves.

EDIT: Actually, to be precise, DataAnnotations don't do exception throwing because it would be nonsense if they did, because that would break the execution of your app, which of course you do not want. You want to return to the same View and give user a chance to correct his mistakes.

On the other hand, you can still have try..catch block inside the if(ModelState.IsValid) to catch the REAL exception like failure to write to disk or failing to store to the database or inserting nulls into DB columns where no nulls are allowed, etc etc.

HTH

mare
  • 13,033
  • 24
  • 102
  • 191
  • Thanks so much for your help on this everyone. Mare, you are absolutly correct in what you say above. I have made these changes and it is all working perfectly now. Many thanks. I have also shown the final code above for anyone with similar issues. – chrisp_68 Jul 25 '10 at 16:57
  • If data annotations don't throw an exception, what do they do then? Do they add the error to the model state dictionary? That doesn't make sense because you can do data annotations in non-mvc apps. – CatDadCode Jun 27 '11 at 17:27
  • please take a look at this question about how DA work and specifics about MVC http://stackoverflow.com/questions/6496705/how-do-data-annotations-work – mare Jun 28 '11 at 21:56
1

There is nothing in MVC2 that would throw an exception because of a [Required] field.

You get model state violations, thats it. Pretty sure exceptions are only thrown from a manual call to the ModelBinder when your trying to bind "Joel Atwood" to a DateTime field.

John Farrell
  • 24,673
  • 10
  • 77
  • 110
  • Do you know how the model state violations usually end up bing displayed. I have an Html.ValidationSummary and they are displayed there, but only if the code goes through the catch above. – chrisp_68 Jul 24 '10 at 17:56
0

On class property there u put data annotation, namespace should be "YouProject.Model"

Fan
  • 1
  • Thanks for the comment, yes I have done this and it works but only when if a different rules exception is thrown – chrisp_68 Jul 24 '10 at 17:58