Virtual Happy Hour this month, Jun 28, we'll be getting a sneak preview at our soon to launch SaaS CMS!

Try our conversational search powered by Generative AI!

Integrating Data Annotations with the Localization Service


The EPiServer Localization Service comes pre-integrated with the various Data Annotations supported by EPiServer for use with Content Properties. This enables Implementors to create, for example, Page Properties such as the one below:

        [Display(Name = "H1 Heading",
            GroupName = SystemTabNames.Content,
            Order = 10)]
        [Required(AllowEmptyStrings = false, ErrorMessage = "/annotations/header/requirederror")]
        public virtual string Header { get; set; }

This all works straight out of the box whilst in Edit View mode; all is good and we are happy.

I would like to go further though and use Data Annotations on my Custom View Models that are requierd within my solutions and integrate those annotations with the EPiServer Localization Service so that EPiServer Content Mangement can be applied to the error/validation messages output by, say, MVC unobtrusive valdation; in a similar manner to the above Edit Mode scenario with my Content Model. For example, consider the following Custom View Model associated with a Login Page...

    public class LoginViewModel
        [Required(AllowEmptyStrings = false, ErrorMessage = "/annotations/usernamerequired")]
        [EmailAddress(ErrorMessage = "/annotations/mustbeanemail")]
        public string Username { get; set; }
        [Required(AllowEmptyStrings = false, ErrorMessage = "/annotations/passwordrequired")]
        public string Password { get; set; }

The out of the box behaviour is that Unobtrusive Validation outputs the Localization Key rather than the Localized String. What is the wiring that I need to undertake in order to have this work for me in Visitor Mode?

Any assistance on this would be most gratefully received.

Dec 18, 2013 17:09

Hi Martin, 


we used approach described in


Unfortunately our own implementation is not a nuget package yet, but briefly we customized 2 things: DataAnnotationsModelMetadataProvider and DataAnnotationsModelValidatorProvider. Please let me know if it's enough for you to start or you'd like more detailed code samples. 



Vladimir Levchuk

Dec 19, 2013 9:53


that's great. more than I hoped for. thank you

Dec 19, 2013 17:06

Hmm, using something based on CachedDataAnnotationsModelMetadataProvider to provide localised validation messages for ValidationAttributes on ViewModels whilst in Visitor Mode appears to work fine.

However, a whole world of pain ensues if your goal is to support a site with mutiple active language branches (only the first activated langauge branch can localise the message) or support editing of the messages (the value at first activation is always used) without restarting the AppPool.

Need to think again now.

Edited, Feb 26, 2014 18:49

Martin: Same issue here. Did you find a working solution?

Oct 07, 2015 13:17
Oct 07, 2015 19:31

Thanks, yes actually I was already using your implementation from that article. But then I found out to have trouble with localizing the [Display] attribute which I am also using. In a typical view model I have this property:

[Display(Name = "/fields/username")]
[Required(ErrorMessage = "/validation/required")]
public string Username { get; set; }

Using your LocalizableModelMetadataProvider (that detects ErrorMessage starting with "/" and stores the value as a custom property in AdditionalValues), and registering a LocalizableRequiredAnnotationsAdapter that looks for this custom property and translates the value using LocalizationService, works very well. It also works if I change the current UI culture and so forth. I even implemented support for default localized validation messages if I use attributes without setting the ErrorMessage, i.e. just using [Required]. Also working like a charm!

The problem I have now is that the Display attribute is not localized, and I'm not sure where or how to do it. I tried the following code in method CreateMetadataPrototype (in our custom LocalizableModelMetadataProvider):

var displayAttr = attributes.OfType<DisplayAttribute>().SingleOrDefault(a => !string.IsNullOrWhiteSpace(a.Name) && a.Name.StartsWith("/"));
if (displayAttr != null)
    prototype.DisplayName = LocalizationService.Current.GetString(displayAttr.Name, propertyName);

But the DisplayName value set here doesn't seem to do any difference. I noticed that the above snippet actually works if I have my provider inheriting DataAnnotationsModelMetadataProvider (instead of the CachedDataAnnotationsModelMetadataProvider), but then the ErrorMessage logic gets broken...

How to do this? Do I have to subclass the old DisplayNameAttribute instead? (the newer DisplayAttribute class is sealed...) :O :X :(

Edited, Oct 08, 2015 9:24
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.