Home » Headline | ASP.NET

MVC Perview 2 is out

1. October 2009 by thebeebs 0 Comments

mvc The MVC preview 2 is out and luckily they seem to have concentrated alot on data annotations, which makes me feel validated with my approach on the latest site I've been working on.

 

Despite preview 1 not supporting complex objects with data annotation model binding I chose to write a hack called the ObjectValidator . This enabled me to use standard model binding, that supports Complex object binding, and also validate it using Data annotations. This method was a hack, but I knew the MVC guys would be working on this anyway, and I thought what's the point writing my own custom model binder when those boys will be working on a better one already.

 

For those of you that are interested I’ve place my ObjectValidator below. All it does is validates the object based upon its data annotations and adds errors to the passed in ModelState, it only works at the top level so won’t validate sub objects or collections of objects, but it’s been very useful for us so far.

 

    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web.Mvc;

    /// <summary>
    /// Validates an object based upon data annotations
    /// </summary>
    public class ObjectValidator
    {
        /// <summary>
        /// A private field
        /// </summary>
        private ModelStateDictionary model;

        /// <summary>
        /// Initializes a new instance of the <see cref="ObjectValidator"/> class.
        /// </summary>
        public ObjectValidator()
        {
            this.model = new ModelStateDictionary();
            this.Suffix = string.Empty;
            this.Prefix = string.Empty;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="ObjectValidator"/> class.
        /// </summary>
        /// <param name="model">The model.</param>
        public ObjectValidator(ModelStateDictionary model)
        {
            this.model = model;
            this.Suffix = string.Empty;
            this.Prefix = string.Empty;
        }

        /// <summary>
        /// Gets or sets the object to validate
        /// </summary>
        /// <value>The address.</value>
        public object Object { get; set; }

        /// <summary>
        /// Gets the properties of the object
        /// </summary>
        /// <returns>All the objects properties</returns>
        public PropertyDescriptorCollection GetProperties
        {
            get
            {
                return new AssociatedMetadataTypeTypeDescriptionProvider(this.Object.GetType())
                    .GetTypeDescriptor(this.Object.GetType(), this.Object)
                    .GetProperties();
            }
        }

        /// <summary>
        /// Gets the model state which will contain any errors found
        /// </summary>
        /// <value>The errors.</value>
        public ModelStateDictionary Model
        {
            get { return this.model; }
        }
        
        /// <summary>
        /// Gets a value indicating whether this <see cref="ObjectValidator"/> is valid.
        /// </summary>
        /// <value><c>true</c> if valid; otherwise, <c>false</c>.</value>
        public bool Valid
        {
            get { return this.Model.Count > 0; }
        }

        /// <summary>
        /// Gets or sets the suffix
        /// </summary>
        /// <value>The suffix.</value>
        public string Suffix { get; set; }

        /// <summary>
        /// Gets or sets the prefix
        /// </summary>
        /// <value>The prefix.</value>
        public string Prefix { get; set; }

        /// <summary>
        /// Validates the specified object based upon data annotations.
        /// </summary>
        /// <param name="value">The object to validate.</param>
        /// <param name="model">The model.</param>
        /// <returns>A object validator</returns>
        public static ObjectValidator Validate(object value, ModelStateDictionary model)
        {
            return new ObjectValidator(model) { Object = value } .Validate();
        }

        /// <summary>
        /// Validates the specified object based upon data annotations using a prefix in the model
        /// </summary>
        /// <param name="value">The object to validate.</param>
        /// <param name="prefix">The prefix is used to append errors to the correct modelstate keys if a object that is only part of the model
        /// is validated </param>
        /// <param name="model">The model.</param>
        /// <returns>A object validator</returns>
        public static ObjectValidator Validate(object value, string prefix, ModelStateDictionary model)
        {
            return new ObjectValidator(model) { Object = value, Prefix = prefix } .Validate();
        }

        /// <summary>
        /// Validates this instance.
        /// </summary>
        /// <returns>Reutrns if the class validates againsts it's annotations</returns>
        public ObjectValidator Validate()
        {
            if (this.Object == null)
            {
                return this;
            }

            foreach (PropertyDescriptor property in this.GetProperties)
            {
                foreach (ValidationAttribute al in property.Attributes.OfType<ValidationAttribute>())
                {
                    if (!al.IsValid(property.GetValue(this.Object)))
                    {
                        this.Model.AddModelError(this.Prefix + property.Name + this.Suffix, al.ErrorMessage);
                    }
                }
            }

            return this;
        }
    }
 
And here is some sample usage:
 
        /// <summary>
        /// Checks that the object is valid
        /// </summary>
        [TestMethod]
        public void CheckAllObjectsAreValid()
        {
            // Arrange
            var ov = new ObjectValidator();
            var user = new User();
            ov.Object = user;

            // Act
            var actual = ov.Validate().Valid;

            // Assert
            Assert.IsTrue(actual);
        }

Comments

Add comment


(Will show your Gravatar icon)  

  Country flag

biuquote
  • Comment
  • Preview
Loading