May 29, 2017 by Christoff Truter 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.
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; } }
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { ModelMetadataProviders.Current = new ResourceTypeModelMetadataProvider();
[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
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?
Mr. March 18, 2020 by Kwan
Dear Sir, this is exactly what I need. Very neat and helpful. Will you be able to create one for .Net Core 3.1?