Localizing / Customizing Entity Framework and ASP.NET MVC 3

In most demos that you see that involve entity framework code first and ASP.NET MVC 3, localization is not mentioned.  What if you want to make your data multi-language friendly?  Here is a simple example: I want to have title column to be at most 30 characters in my entity:

    [StringLength(30)]

    public string Title { get; set; }

 

If you run the form with this configuration and you enter more than 30 characters, you will get the following message: The field Title must be a string with a maximum length of 30.  This may be OK for some folks, but it does not follow proper English grammar.  So, let’s fix the problem.  First thing we need is create a resource file.  I typically put resources into its own assembly, so I am going to create new class library project, add new item of type Resource, and create new string key Title30Characters and appropriate value:

image

Now, let’s customize the attribute in the following manner:

    [StringLength(30,

      ErrorMessageResourceName = "Title30Characters",

      ErrorMessageResourceType = typeof(Resource))]

 

That is it.  One important thing to notice is that most attributes in Data Annotations namespace have the same two parameters used for localization: ErrorMessageResourceName and ErrorMessageResourceType.

 

    [StringLength(30,

      ErrorMessageResourceName = "Title30Characters",

      ErrorMessageResourceType = typeof(Resource))]

    [Required(

      ErrorMessageResourceName = "TitleRequired",

      ErrorMessageResourceType = typeof(Resource))]

    [Display(Name = "Title", ResourceType = typeof(Resource))]

    public string Title { get; set; }

 

Above you see the final version of the Title field attributes.  I am specifying maximum length, required field and display name, all coming from resources, specifically Resource class.  One interesting thing to notice is that I am using the same attributes to define messages in ASP.NET MVC and database structure.  Database does not care about messages I am adding to StringLength attribute, but it is using the value of 30 to define the size of the field.

Now, here is one more use case:  I want to handle parsing errors.  For example I have a Session Date field that maps to date time picker control in jQuery.  If I enter the following text 112121, here is what message will be generated:  The value ‘112121’ is not valid for Session Date.  Not friendly.  Here is how I can also customize all error messages in ASP.NET MVC.  I can do it in Controller (Create or Update) method.  In the example below I am using Create method, testing for errors, and putting in custom error for Session Date property:

 

    public ActionResult Create()

    {

      var view = View(new Session());

      view.ViewBag.Action = "Create";

      return view;

    }

 

   

    [HttpPost]

    public ActionResult Create(Session session)

    {

      if (ModelState.IsValid)

      {

        db.Sessions.Add(session);

        db.SaveChanges();

        return RedirectToAction("Index");

      }

      else

      {

        if (ModelState["SessionDate"].Errors.Count == 1)

        {

          string date = ModelState["SessionDate"].Value.AttemptedValue;

          DateTime test;

          if (!DateTime.TryParse(date, out test))

          {

            ModelState["SessionDate"].Errors.Clear();

            ModelState["SessionDate"].Errors.Add(new ModelError(Resource.DateInvalidInvalidFormat));

          }

        }

      }

      var view = View(session);

      view.ViewBag.Action = "Create";

      return view;

    }

 

As you can see above, I am checking for errors in ModelState, removing default error only if my parsing fails on proposed value, and putting in custom message from resources.

 

Alternatively, you can use “buddy classes” or MetadataType attribute to define your metadata in a “buddy” class.  I personally do not like this approach, it feels awkward to me.

That is all there is to it.

Thanks.

4 Comments

  1. [Required(ErrorMessageResourceName = “TitleRequired”,ErrorMessageResourceType = typeofResource))]

    I used the above code in my case(WPF). But nothing happens. But if I use,
    [Required(ErrorMessage=”hi”)] it is working perfectly. Why localization from the resource file didnt work?

  2. The EF code I provided is for ASP.NET MVC. I have not tried to use the same in WPF. Should work in theory. Did you double-check to make sure the resource is available and public for your WPF app? If you need help, please email a sample project, and I will try to take a look. My email address on contacts page.

  3. Hi Priya,
    I’ve encountered the same problem when trying to use resources defined in other assembly.

    I’m currently working on MVC application with model in a separate project. At first I used also a separate project for resources only. But it turned out that in such case the DataAnnotations such as Required or MaxLength were not applied in database. My solution was to move resources to the project with model and it worked as a charm! I suppose this is a kind of “feature” the EntityFramework team should look at 🙂

    If it is also your case (resources in different assembly), try to define resources in the same assembly as your DataAnnotations.

    HTH,
    tiggris.

  4. This is strange because in the demo I put togehter having resources in a separate assembly worked just fine. I think it might be because you do not define your resource’s visisbility as public. THere is a drop down on top of the resource editor that would allow you to set visibility to public.

Leave a Reply

Your email address will not be published. Required fields are marked *