views:

159

answers:

3

Hi 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);
    }
+1  A: 

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.

jfar
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
A: 

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

Fan
Thanks for the comment, yes I have done this and it works but only when if a different rules exception is thrown
chrisp_68
+1  A: 

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
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