Model Validation Not Working

Topics: Customizing Orchard, General, Troubleshooting, Writing modules
Dec 6, 2011 at 3:02 PM

Hi,

Just trying to get the validation of my models working.  I have added the [Required] annotation to my Record class and then attempt to save a new ContentItem.  I am expecting the ModelState.IsValid to be false and so the save to be aborted and a message displayed.  However the ModelState.IsValid is true and the save happily completes.

I can't seem to see what I am doing wrong, here is my Record:

 

using System.ComponentModel.DataAnnotations;
using Orchard.ContentManagement.Records;

namespace CPD.Courses.Models
{
    public class CoursePartRecord : ContentPartRecord {
        [Required]
        public virtual string Summary { get; set; }
    }
}

 

My model:

 

using Orchard.ContentManagement;
using Orchard.Core.Common.Models;
using Orchard.Core.Routable.Models;

namespace CPD.Courses.Models
{
    public class CoursePart : ContentPart<CoursePartRecord> {
        
        public string Name
        {
            get { return this.As<RoutePart>().Title; }
            set { this.As<RoutePart>().Title = value; }
        }

        public string Slug
        {
            get { return this.As<RoutePart>().Slug; }
            set { this.As<RoutePart>().Slug = value; }
        }

        public string Description
        {
            get { return this.As<BodyPart>().Text; }
            set { this.As<BodyPart>().Text = value; }
        }

        public string Summary
        {
            get { return Record.Summary; }
            set { Record.Summary = value; }
        }
    }
}

My driver:

protected override DriverResult Editor(CoursePart part, IUpdateModel updater, dynamic shapeHelper) {
     if (updater != null)
     {
          updater.TryUpdateModel(part, Prefix, null, null);
     }
     return Editor(part, shapeHelper);
}

My Shape Template:

@model CPD.Courses.Models.CoursePart
<fieldset class="course-summary">
    <div class="summary">
        @Html.LabelFor(m => m.Summary)
        @Html.TextAreaFor(m => m.Summary)@Html.ValidationMessageFor(m => m.Summary)
    </div>   
</fieldset>

My Controller:

[HttpPost, ActionName("Create")]
        public ActionResult CreateCourse() {
            if (!Services.Authorizer.Authorize(Permissions.CreateCourse, T("Couldn't create course")))
                return new HttpUnauthorizedResult();

            var course = Services.ContentManager.New<CoursePart>("Course");
            var model = Services.ContentManager.UpdateEditor(course.ContentItem, this);

            if (!ModelState.IsValid) {
                Services.TransactionManager.Cancel();
                return View((object)model);
            }

            Services.ContentManager.Create(course, VersionOptions.Published);

            return RedirectToAction("Index");
        }

Now if I don't set a title (via the RoutePart) the ModelState is invalid and doesn't get saved, but with my own Summary does not seem to validate, it saves even if it is empty.

I can't see anything different from what I am doing and say the Routing module.

It seems as though the same problem exists in the Blog module.  It has a max string length of 10000 on its BlogPartRecord.Description field, however I can set it to larger than this length and the validation doesn't stop me??

Any ideas? Thanks,

Jeff

 

Dec 6, 2011 at 3:07 PM

Since the model is validating on CoursePart, not CoursePartRecord, you may need to add [Required] on CoursePart.

Dec 6, 2011 at 4:02 PM

Cheers Pete, I missed that!  I think it was because I was comparing it to how the RoutePartDriver works, as it too validates on the RoutePart, whereas its the RoutePartRecord that has the StringLength attribute, but it still works??

Dec 6, 2011 at 4:09 PM

RoutePart has its own validation in the driver or handler, I think.

Dec 6, 2011 at 4:31 PM

Yeah I took a look but could only see a call to _routableService.IsSlugValid(part.Slug) but this doesn't handle an empty slug.  I maybe missing something, I must be!

Its seems as though its a mistake (putting the validation attributes on the Record rather than the Part) that is also made in the Blogs module, I will report the bug.

Cheers for your help.

Dec 6, 2011 at 4:33 PM

Routable uses a ViewModel with validation attributes:

    public class RoutableEditorViewModel {

        public int Id { get; set; }
        public string ContentType { get; set; }

        [Required]
        [StringLength(1024)]
        public string Title { get; set; }
        [StringLength(1024)]
        public string Slug { get; set; }
        public int? ContainerId { get; set; }
        public bool PromoteToHomePage { get; set; }

        public string ContainerAbsoluteUrl { get; set; }
    }

So that's what it's binding against.

Dec 6, 2011 at 4:39 PM

Arhh yeah I see that now, thanks :)