ASP.NET MVC - DataAnnotation Localization

May 29, 2017 by C#   ASP.NET   PostSharp   MVC  

Strangely enough - especially seeing that localization has been a requirement in all of my work related codebases for the last 4 years or so, this is the first time that I am writing on the subject of localization.

In this post we're going to have a look at localizing DataAnnotations.

Observe the following data annotated snippet.

public class User
{
	[Display(Name = "FirstName")]
	public string FirstName { get; set; }

	[Display(Name = "LastName")]
	public string LastName { get; set; }

	[EmailAddress]
	[Required]
	[Display(Name = "Email")]
	public string Email { get; set; }
}


On the frontend (assuming you're using Razor), you will generally do something like this.

@Html.LabelFor(model => model.FirstName)
@Html.DisplayFor(model => model.FirstName)


In a nutshell, the LabelFor helper will output the display value associated with the property while the DisplayFor helper will output the most appropriate editor template it can find, e.g. date picker for a DateTime, checkbox for a bool etc.

The nice thing with this approach is that we've got a central point governing the output (and thereby input - validation) of our properties (perhaps too tightly coupled for MVC?).

Now in order to localize these properties, we need to add resx files to our solution, in the sample git repository linked with this post, I added resx files for Afrikaans and English, seen over here.

Note the use of Access Modifier: Public - this is required in order to make the resources visible to our models, quite strange that this isn't the default modifier, don't you think?

resxpublic
The amended snippet (using the resource files) will look something like this.

public class User
{
    [Display(Name = "FirstName", ResourceType = typeof(Resources.User))]
    public string FirstName { get; set; }

    [Display(Name = "LastName", ResourceType = typeof(Resources.User))]
    public string LastName { get; set; }

    [EmailAddress(ErrorMessageResourceName = "Email_InValid", ErrorMessageResourceType = typeof(Resources.User))]
    [Required(ErrorMessageResourceName = "Email_Required", ErrorMessageResourceType = typeof(Resources.User))]
    [Display(Name = "Email", ResourceType = typeof(Resources.User))]
    public string Email { get; set; }
}

Hmm, not all that pretty though (starting to resemble something out of Frankenstein's monster), seeing that you will need to assign a ResourceType / ErrorMessageResourceType to every decorated property.

Some alternatives I've seen on the web involves inheriting from the DisplayAttribute and encapsulating the ResourceType property inside the inherited class - crappy thing is that you will need to do this for each and every DataAnnotation type that you're planning to use.

Another alternative is to write a custom DataAnnotationsModelMetadataProvider (included in Sample2 of the git repository) - along with a very simple attribute.

Note that this provider doesn't seem to follow the standard provider pattern (as far as I can see at least) - to use it in your project, you will need to assign it in your global.asax, hmmm...

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ModelMetadataProviders.Current = new ResourceTypeModelMetadataProvider();
The amended snippet (using the custom ResourceTypeAttribute along with the custom meta provider) looks something like this.

[ResourceType(typeof(Resources.User))]
public class User
{
    [Display(Name = "FirstName")]
    public string FirstName { get; set; }

    [Display(Name = "LastName")]
    public string LastName { get; set; }

    [EmailAddress(ErrorMessageResourceName = "Email_InValid")]
    [Required(ErrorMessageResourceName = "Email_Required")]
    [Display(Name = "Email")]
    public string Email { get; set; }
}


Instead of assigning a resourcetype to every property, we simply decorate the parent class.

But wait, there is more Winking smile

You will notice that the DisplayAttribute is present in all of our snippets - its use is fairly repetitive, what if we could automate its inclusion into our code?

Enter PostSharp, instead of manually adding meta data, e.g. the display data annotation (among other things) to our code, its possible to bake these attributes into our classes compile time using the TypeLevelAspect - have a look at the ResourceTypeAttribute over here in Sample 3.

The amended snippet looks something like this.

[ResourceType(typeof(Resources.User))]
public class User
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    [EmailAddress(ErrorMessageResourceName = "Email_InValid")]
    [Required(ErrorMessageResourceName = "Email_Required")]
    public string Email { get; set; }
}


Not bad?

Note that these features are only included in the postsharp pay-for versions.

PostSharpTakeMyMoney

Just as a quick note (someone asked), if you want to see the localized output, simply change your default language of your browser to Afrikaans (assuming that you are using the git repository demo), lekker man, lekker Open-mouthed smile

Read More
PostSharp - Introducing Custom Attributes


Leave a Comment




Related Downloads

ASP.NET MVC playground