Question

I'm working on an application which should validate the model based on some metadata saved in a database. The purpose of this is to allow administrators change how some models are validated, without changing the code, depending on clients' preferences. The changes are applied for the entire application, not for specific users accessing it. How it is changed, doesn't matter at the moment. They could be modified directly on the database, or using an application. The idea is that they should be customizable.

Let's say i have the model "Person" with the property "Name" of type "string".

public class Person
{
    public string Name { get; set; }
}

This model is used by my app which is distributed and istalled on several servers. Each of them is independent. Some users may want the Name to have maximum 30 letters and to be required when creating a new "Person", others may want it to have 25 and not to be required. Normally, this would be solved using data annotations, but those are evaluated during the compile time and are somehow "hardcoded".

Shortly, I want to find a way to customize and store in a database how the model validates, without the need of altering the application code.

Also, it would be nice to work with jquery validation and have as few request to database(/service) as possible. Besides that, i can't use any known ORM like EF.

Was it helpful?

Solution

You could create a custom validation attribute that validates by examining the metadata stored in the database. Custom validation attributes are easy to create, simply extend System.ComponentModel.DataAnnotations.ValidationAttribute and override the IsValid() method.

To get the client side rules that work with jQuery validation you will need to create a custom adapter for the type of your custom validation attribute that extends System.Web.Mvc.DataAnnotationsModelValidator<YourCustomValidationAttribute>. This class then needs to be registered in the OnApplicationStart() method of your Global.asax.

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(YourCustomValidationAttribute), typeof(YourCustomAdapter));

Here's an example adapter:

public class FooAdapter : DataAnnotationsModelValidator<FooAttribute>
{
    /// <summary>
    /// This constructor is used by the MVC framework to retrieve the client validation rules for the attribute
    /// type associated with this adapter.
    /// </summary>
    /// <param name="metadata">Information about the type being validated.</param>
    /// <param name="context">The ControllerContext for the controller handling the request.</param>
    /// <param name="attribute">The attribute associated with this adapter.</param>
    public FooAdapter(ModelMetadata metadata, ControllerContext context, FooAttribute attribute)
        : base(metadata, context, attribute)
    {
        _metadata = metadata;
    }

    /// <summary>
    /// Overrides the definition in System.Web.Mvc.ModelValidator to provide the client validation rules specific
    /// to this type.
    /// </summary>
    /// <returns>The set of rules that will be used for client side validation.</returns>
    public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
    {
        return new[] { new ModelClientValidationRequiredRule(
            String.Format("The {0} field is invalid.", _metadata.DisplayName ?? _metadata.PropertyName)) };
    }

    /// <summary>
    /// The metadata associated with the property tagged by the validation attribute.
    /// </summary>
    private ModelMetadata _metadata;
}

This may also be useful if you would like to asynchronously call server side validation http://msdn.microsoft.com/en-us/library/system.web.mvc.remoteattribute(v=vs.108).aspx

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top