Custom DataAnnotation attribute with datastore access in ASP.NET MVC 2

Posted by mare on Stack Overflow See other posts from Stack Overflow or by mare
Published on 2010-04-05T17:26:10Z Indexed on 2010/04/05 17:53 UTC
Read the original article Hit count: 715

I have my application designed with Repository pattern implemented and my code prepared for optional dependency injection in future, if we need to support another datastore.

I want to create a custom validation attribute for my content objects. This attribute should perform some kind of datastore lookup. For instance, I need my content to have unique slugs. To check if a Slug already exist, I want to use custom DataAnnotation attribute in my Base content object (instead of manually checking if a slug exists each time in my controller's Insert actions). Attribute logic would do the validation.

So far I have come up with this:

public class UniqueSlugAttribute : ValidationAttribute
{
    private readonly IContentRepository _repository;

    public UniqueSlugAttribute(ContentType contentType)
    {
        _repository = new XmlContentRepository(contentType);
    }

    public override bool IsValid(object value)
    {
        if (string.IsNullOrWhiteSpace(value.ToString()))
        {
            return false;
        }

        string slug = value.ToString();
        if(_repository.IsUniqueSlug(slug))
            return true;

        return false;
    }
}

part of my Base content class:

...
        [DataMember]
        public ContentType ContentType1 { get; set; }

        [DataMember]
        [Required(ErrorMessageResourceType = typeof (Localize), ErrorMessageResourceName = "Validation_SlugIsBlank")]
        [UniqueSlug(ContentType1)]
        public string Slug
        {
            get { return _slug; }
            set
            {
                if (!string.IsNullOrEmpty(value))
                    _slug = Utility.RemoveIllegalCharacters(value);
            }
        }
...

There's an error in line

    [UniqueSlug(ContentType1)]

saying: "An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type."

Let me explain that I need to provide the ContentType1 parameter to the Constructor of UniqueSlug class because I use it in my data provider.

It is actually the same error that appears if you try do to this on the built-in Required attribute:

[Required(ErrorMessageResourceType = typeof (Localize), ErrorMessageResourceName = Resources.Localize.SlugRequired]

It does not allow us to set it to dynamic content. In the first case ContentType1 gets known at runtime, in the second case the Resources.Localize.SlugRequired also gets known at runtime (because the Culture settings are assigned at runtime).

This is really annoying and makes so many things and implementation scenarios impossible.

So, my first question is, how to get rid of this error? The second question I have, is whether you think that I should redesign my validation code in any way?

© Stack Overflow or respective owner

Related posts about form-validation

Related posts about asp.net-mvc