validationasp.net-mvc-3lightspeed

MVC3 Validation with Lightspeed


My ORM (LightSpeed) generates this for Animals table, with Name and Age. Using MVC3 and Razor

   [Serializable]
  [System.CodeDom.Compiler.GeneratedCode("LightSpeedModelGenerator", "1.0.0.0")]
  [System.ComponentModel.DataObject]
  [Table(IdColumnName="AnimalID", IdentityMethod=IdentityMethod.IdentityColumn)]
  public partial class Animal : Entity<int>
  {     
    [ValidatePresence]
    [ValidateLength(0, 50)]
    private string _name;

    [ValidateComparison(ComparisonOperator.GreaterThan, 0)]
    private int _age;

    public const string NameField = "Name";
    public const string AgeField = "Age";

    [System.Diagnostics.DebuggerNonUserCode]
    [Required] // ****I put this in manually to get Name required working
    public string Name
    {
      get { return Get(ref _name, "Name"); }
      set { Set(ref _name, value, "Name"); }
    }

    [System.Diagnostics.DebuggerNonUserCode]
    public int Age
    {
      get { return Get(ref _age, "Age"); }
      set { Set(ref _age, value, "Age"); }
    }

With [Required] attribute added:

enter image description here

With no [Required] attribute added: (notice LightSpeed strange rendering of validation)

enter image description here

With name filled in:

enter image description here

In images above - the validation at the top is LightSpeed (put into ValidationSummary) and at the side is MVC3 (put into ValidationMessageFor)

Am only using Server Side validation currently.

Question: How do I get LightSpeed validation working well in MVC3?

I think it is something in this area http://www.mindscapehq.com/staff/jeremy/index.php/2009/03/aspnet-mvc-part4/

For the server side validation - you will want to use a custom model binder which emits the errors from LightSpeed validation more precisely rather than the leveraging the DefaultModelBinder behavior. Have a look at either directly using or adapting the EntityModelBinder from the community code library for Mvc

http://www.mindscapehq.com/forums/Thread.aspx?PostID=12051


Solution

  • See link http://www.mindscapehq.com/forums/Thread.aspx?ThreadID=4093

    Jeremys answer (Mindscape have great support!)

    public class EntityModelBinder2 : DefaultModelBinder
      {
        public static void Register(Assembly assembly)
        {
          ModelBinders.Binders.Add(typeof(Entity), new EntityModelBinder2());
    
          foreach (Type type in assembly.GetTypes())
          {
            if (typeof(Entity).IsAssignableFrom(type))
            {
              ModelBinders.Binders.Add(type, new EntityModelBinder2());
            }
          }
        }
    
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
          object result = base.BindModel(controllerContext, bindingContext);
    
          if (typeof(Entity).IsAssignableFrom(bindingContext.ModelType))
          {
            Entity entity = (Entity)result;
    
            if (!entity.IsValid)
            {
              foreach (var state in bindingContext.ModelState.Where(s => s.Value.Errors.Count > 0))
              {
                state.Value.Errors.Clear();
              }
    
              foreach (var error in entity.Errors)
              {
                if (error.ErrorMessage.EndsWith("is invalid")) continue;
                bindingContext.ModelState.AddModelError(error.PropertyName ?? "Custom", error.ErrorMessage);
              }
            }
          }
    
          return result;
        }
      }
    

    and in Global.asax register using:

    EntityModelBinder2.Register(typeof(MyEntity).Assembly);

    The Register call sets up the model binder to be used for each entity type in your model assembly so modify as required.