Validating part property based on property of another part

Topics: Customizing Orchard, Writing modules
Jun 12, 2012 at 5:13 PM
Edited Jun 12, 2012 at 5:13 PM

I have extended the user type with a custom part and am using a similar approach to the Extended Registration module (http://extendedregistration.codeplex.com/) to allow user's to input the data for the part when they register, but when it comes to validating my custom part I need to access the email address from the user part.

As a potential solution I have added an Email property to my custom part. Obviously this doesn't get populated by the default model binder so I've added a custom model binder.

public CustomPart : ContentPart<CustomPartRecord>
{
      public string CustomProperty 
      {
           get { return Record.CustomProperty; }
           set { Record.CustomProperty = value; }
      }

      public string Email { get; set; }
}

public class CustomPartModelBinder : DefaultModelBinder
    {
        protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor)
        {
            if (propertyDescriptor.Name == "Email")
            {
                var value = bindingContext.ValueProvider.GetValue("email");
                SetProperty(controllerContext, bindingContext, propertyDescriptor, value); 
            }

            base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
        }
    }

public class ContainerModule : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            System.Web.Mvc.ModelBinders.Binders.Add(typeof(CustomPart), new CustomPartModelBinder());

            base.Load(builder);
        }
    }

This successfully binds the value to the Email property in my custom part, great stuff, but I'm wondering if there's a better or more straight forward way to do this?

Coordinator
Jun 13, 2012 at 4:51 AM

Parts are supposed to be self-contained, so you're clearly stepping outside the design goals for them here.

Jun 13, 2012 at 4:02 PM

Point taken. I think in this case I should probably actually be using a field on the user part (which I think would satisfy your objection) however after playing around a bit more it looks as though fields have their own drivers, so I think I'd have the same problem. 

Coordinator
Jun 14, 2012 at 6:06 AM

Not sure I understand why you need your own validation to the user part's e-mail. If you need to modify its behavior I would probably replace the whole thing.

Jun 14, 2012 at 7:57 AM
Edited Jun 14, 2012 at 8:24 AM

I can see how to do it if I replace the whole thing but I ideally wanted to end up with a module like Extended Registration, where I can allow the user to enter any additional part data on the registration page. The net result being that I could use the module in any Orchard site, so I don't have to re-write the same code over and over to support an extended user model.

In this case I've added a membership number to the user which needs to be verified against the email address in a 3rd party membership system, so I'm validating based on a method call like DoesMemberExistInMembershipSystem(email, membershipNumber). Perhaps needing the email address to validate membership number is just a particular quirk of this site and wont be an issue with many other sites we implement.

I'm wondering if I performed this validation on the client side using an ajax call in order to display user friendly messaging, could I use one of the events (e.g. OnCreating, OnActivating) in the ContentHandler for my part to perform my check server side and just prevent the user being created in case someone bypasses the client validation? So can I put something like this in one of the events (I found I can get the populated userpart in OnCreating but my custom part isn't populated yet)...

 

var email = part.As<UserPart>().Email
if (!CheckMembership(email, part.MembershipNumber))
   // either delete the user, cancel the transaction, something else?

 

Doesn't seem like a much better solution though to be honest.