Optimize user experience for editors with attribute validators

Den här artikeln är inte översatt till svenska och visas därför på engelska istället.


We talk a lot about how UX is so important for the end users – and it is, but don’t forget the experience your editors have when they are creating pages for users.

Uppskattad lästid : 2 minuter

Gå till avsnitt

Key takeaways

  • Validate for editors not for your convenience

How not to

The quick and dirty way is just to add a required attribute (and if you are a bit interested in your editor you will add an error message). But that will generate a horrible first page where editors must add the required values before creating the page.

The image represents the interface the editor experienced before the block is created

How it should be done 

I like to do one validator for each model I have. Here I can send out all my messages to the editor. I send out warnings and all my validation here. So, all fields on the page can be added on the same page. If one property depends on another property - tell the editor!

Here is a simple tutorial on how to validate your model

[ContentType(GUID = "740EB686-2DDD-4AD4-A8CF-615D3389DE6B")]
[SiteImageUrl]
public class LinksTutorialBlock : BlockData
{
    [CultureSpecific]
    [Display(Order = 100)]
    [UIHint(UIHint.MediaFile)]
    public virtual ContentReference? Link { get; set; }

    [CultureSpecific]
    [Display(Order = 200)]
    public virtual string? FileExtension { get; set; }

    [CultureSpecific]
    [Display(Order = 300)]
    [UIHint(UIHint.MediaFile)]
    public virtual ContentReference? SecondLink { get; set; }

    [CultureSpecific]
    [Display(Order = 400)]
    public virtual string? SecondFileExtension { get; set; }
}

And here is some examples of how to validate your model

public class LinksTutorialBlockValidator : IValidate<LinksTutorialBlock>
    {
        public IEnumerable<ValidationError> Validate(LinksTutorialBlock block)
        {
            if (block.FirstLink == null)
            {
                yield return new ValidationError
                {
                    ErrorMessage = "Add first link",
                    Severity = ValidationErrorSeverity.Error,
                    ValidationType = ValidationErrorType.PropertyValidation
                };
            }

            if (block.FirstLink != null && block.SecondLink != null)
            {
                if (string.IsNullOrEmpty(block.FirstFileExtension) || string.IsNullOrEmpty(block.SecondFileExtension))
                {
                    yield return new ValidationError
                    {
                        ErrorMessage =
                            "Add file extension for both links.",
                        Severity = ValidationErrorSeverity.Warning,
                        ValidationType = ValidationErrorType.PropertyValidation
                    };
                }
            }

            if (block.SecondLink != null && block.FirstLink == null)
            {
                yield return new ValidationError
                {
                    ErrorMessage = "Secondary link will not be displayed without first link",
                    Severity = ValidationErrorSeverity.Error,
                    ValidationType = ValidationErrorType.PropertyValidation
                };
            }

            const string pattern = "^[a-z|0-9]{0,4}$";

            if ((block.FirstFileExtension != null && !Regex.IsMatch(block.FirstFileExtension, pattern)) || (block.SecondFileExtension != null && !Regex.IsMatch(block.SecondFileExtension, pattern)))
            {
                yield return new ValidationError
                {
                    ErrorMessage = "File extensions can only contain letters and numbers and can only contain 4 characters" ,
                    Severity = ValidationErrorSeverity.Error,
                    ValidationType = ValidationErrorType.PropertyValidation
                };
            }
        }

I don't question that you have seen the IValidate before. But do use it more than before. If you keep this in mind, you don't need to answer questions down the road about how everything works.