This article shows how ASP.NET Core localization can be used together with data annotations. The data annotations are used to decorate the data model, and when HTTP POST/PUT (also PATCH) Requests are sent with model errors, the error message is returned localized in the request culture.
Code: https://github.com/damienbod/AspNetCoreLocalization
Posts in this series
- ASP.NET Core MVC Localization
- Using DataAnnotations and Localization in ASP.NET Core MVC
- ASP.NET Core using SQL Localization
2018-12-05: Updated to ASP.NET Core 2.2
2017-08-19: Updated to ASP.NET Core 2.0
2017.02.10: Updated to VS2017 msbuild
2016.05.26: Bug fix Data Annotations Localization
2016.05.16: Updated to ASP.NET Core 1.0 RC2 dotnet
2015.11.20: Updated to ASP.NET Core 1.0 rc1
Localization Setup
In the Startup class, the AddDataAnnotationsLocalization is added in the ConfigureServices method.
services.AddMvc() .AddViewLocalization() .AddDataAnnotationsLocalization();
Now a model class can be created and the data annotations can be used. The Length property in this example has a range attribute, with an ErrorMessageResourceName and an ErrorMessageResourceType property set. The ErrorMessageResourceType is used to define the resource itself using the type and the ErrorMessageResourceName is used to define the resource identifier. Only the Length property has localized error messages implemented.
using System.ComponentModel.DataAnnotations; using System.Collections.Generic; using System.Globalization; using AspNet5Localization.Controllers; using Microsoft.Extensions.Localization; namespace AspNet5Localization.Model { public class Box { public long Id { get; set; } public double Height { get; set; } public double Width { get; set; } [Required(ErrorMessage = "BoxLengthRequired")] [Range(1.0, 100.0, ErrorMessage = "BoxLengthRange")] public double Length { get; set; } } }
Now a MVC 6 controller can be created which uses the model class. This controller implements POST and PUT action methods, which uses the ModelState to validate the request. If the model is invalid, the error message is returned with a localized value.
using AspNet5Localization.Model; using Microsoft.AspNetCore.Mvc; namespace AspNet5Localization.Controllers { [Route("api/[controller]")] public class BoxesController : Controller { [HttpGet("{id}")] public IActionResult Get(int id) { if (id == 0) { return NotFound(id); } return Ok(new Box() { Id = id, Height = 10, Length = 10, Width=10 }); } /// <summary> /// http://localhost:5000/api/boxes?culture=it-CH /// Content-Type: application/json /// /// { "Id":7,"Height":10,"Width":10,"Length":1000} /// </summary> /// <param name="box"></param> /// <returns></returns> [HttpPost] public IActionResult Post([FromBody]Box box) { if (!ModelState.IsValid) { return BadRequest(ModelState); } else { string url = Url.RouteUrl("api/boxes", new { id = 11111 }, Request.Scheme, Request.Host.ToUriComponent()); return Created(url, box); } } [HttpPut("{id}")] public IActionResult Put(int id, [FromBody]Box box) { if(id == 0) { return NotFound(box); } if (!ModelState.IsValid) { return BadRequest(ModelState); } else { return Ok(box); } } [HttpDelete("{id}")] public IActionResult Delete(int id) { if (id == 0) { return NotFound(id); } return new NoContentResult(); } } }
Now the POST method can be called in Fiddler or Postman. Underneath is an example of a HTTP POST Request using the it-CH culture. The length property is outside the range and will return an model state error.
http://localhost:5000/api/boxes?culture=it-CH User-Agent: Fiddler Host: localhost:5000 Content-Length: 46 Content-Type: application/json { "Id":7,"Height":10,"Width":10,"Length":1000}
HTTP Response with a it-CH localized error message:
HTTP/1.1 400 Bad Request Date: Sat, 24 Oct 2015 17:15:28 GMT Content-Type: application/json; charset=utf-8 Server: Kestrel Transfer-Encoding: chunked {"Length":["The box length should be between 1 and a 100 it-CH"]}
Localization can be used in data annotations like previous versions of MVC or Web API and provides a simple way of validating your data inputs.
Links:
Microsoft Docs: Globalization and localization
https://github.com/aspnet/Localization
https://github.com/aspnet/Localization/issues/286#issuecomment-249708911
https://github.com/aspnet/Tooling/issues/236
http://www.jerriepelser.com/blog/how-aspnet5-determines-culture-info-for-localization
https://github.com/WeebDo/WeebDo.CMF
https://github.com/joeaudette/cloudscribe
https://github.com/aspnet/Mvc/tree/dev/test/WebSites/LocalizationWebSite
Example of localization middleware for culture in route
http://weblogs.asp.net/jeff/beating-localization-into-submission-on-asp-net-5
[…] Using DataAnnotations and Localization in ASP.NET 5 MVC 6 – damienbod continues his look at localisation in ASP.NET 5 / MVC 6 with a look at how DataAnnotations and Localization can be handled together […]
Hi Damien
thanks for your great articles 🙂 ; i have a quick question how you manage the localisation in the layout and partial pages ; by injecting IViewLocalizer , i canno’t use the layout resource files; always the views resources will be loaded
Kind Regards
Hi rakrouki
Thanks for your comment. This doesn’t seem to work either, here’s one issue on gitHub (see the last comment)
https://github.com/aspnet/Localization/issues/150
There is also another issue about this in the MVC repo. Localization in aspnet5 is still in early development yet (even though its rc1…), its not in a usable state yet.
Looks like you’ll have to implement it yourself by implementing the IStringLocalizerFactory and/or IStringLocalizer.
https://github.com/aspnet/Mvc/issues/2767
https://github.com/aspnet/Mvc/issues/3659
Greetings Damien
I tried using data annotation and localization as shown in Web Application not API application and it does not work. Specifically this example and approach does not work.
[Required(ErrorMessageResourceName = “BoxLengthRequired”, ErrorMessageResourceType = typeof(AmazingResource))]
[Range(1.0, 100.0, ErrorMessageResourceName = “BoxLengthRange”, ErrorMessageResourceType = typeof(AmazingResource))]
public double Length { get; set; }
I would appreciate an example also with Display attribute.
“The runtime doesn’t look up localized strings for non-validation attributes”
so how we should localize the display attribute
Thanks a lot
and sorry for duplicate the old replay was on the wrong post
How can i do this using sql ?
I just took the latest version https://github.com/damienbod/AspNet5Localization, but the post mehtod on BoxesController that where supposd to return the localized string just returned “BoxLengthRange”. Sorry to tell but you sln dont work
Hi Helge , This should work, I’ll check to make certain. I’ll get back to you.
Greetings Damien
Hi Helge. I see the problem. I have not added this localization to the database, only to the resource file. If you switch to use resource resx files, it will work again, or add the record to the database.
services.AddSqlLocalization(options => options.UseTypeFullNames = true);
//services.AddLocalization(options => options.ResourcesPath = “Resources”);
I’ll add this to the database later.
Greetings and thanks for the info, Damien
Grate job, man! This article save my project here in Brazil!
thanks
Greetings Damien
Always nice to return to this site for localization info. Very handy, merci!
thanks