Search code examples
localizationasp.net-mvc-3data-annotationsembedded-resourceresx

DataAnnotations and Resx in class library


For my application (ASP.NET MVC 3.0 RTM, Razor View Engine), I would like to use DataAnnotations for my models. If I keep the model classes within the web project, I can have resx resources in App_GlobalResources or App_LocalResources without embedding the .resx into .resources files.

Ignoring newly spawned AppDomains and other considerations, this is ideal because changing something minor in a localized resource like a typo or incorrect translation doesn't require compilation.

However, after moving my models to a class library I don't see any way to keep .resx files as the output and still use DataAnnotations attributes. Am I missing something?

The problem lies in the way the attributes find resources. For instance, a "Name" property might look like this:

    [Display(Name = "MyEntity_Name", ResourceType = typeof(Validations))]
    [Required(ErrorMessageResourceName="MyEntity_Name_Required", 
       ErrorMessageResourceType = typeof(Validations))]
    [StringLength(150, MinimumLength = 2)]
    public string Name { get; set; }

This requirement for a strongly-typed resource wrapper has become the bane of my existence over the past 24 hours.

I've tried to genericize the wrapper, but it seems like the validation attributes specifically look for a property on the wrapper called MyEntity_Name for the DisplayAttribute and MyEntity_Name_Required for the RequiredAttribute. I haven't dug any deeper into the DataAnnotations code to see if there is some magic I can pull off. I was hoping someone else encountered this and had any ideas.

The Question
Is it possible to use DataAnnotations ValidationAttributes (including DisplayAttribute) in a class library without embedding the resx files into .resources files?

The Gotchas :(
In the future, I'd like to move from resx to database-driven resources with very minimal coding effort. I can't do that right now because of limited resources (no pun intended). So, I want to avoid bypassing the ResourceProvider. Also, I want to avoid rewriting or wrapping all of the attributes in the System.ComponentModel.DataAnnotations namespace.


Solution

  • Am I missing something?

    Yes, you are missing View Models. Controller actions take/pass view models from/to views and not models. View models are classes which are specifically tailored to the needs of a given view. They contain the only the required properties and the proper formatting for the given view. A view model could be a subset of a model or an aggregation of multiple models (it depends on the requirements of the view). View models are always defined in the web project because they are very tightly coupled to views. So it is view models that you should localize/globalize with resources.

    Example of workflow:

    1. The controller action is invoked and it queries the repository to fetch a model
    2. The controller maps the model to the corresponding view model (AutoMapper could you here)
    3. The controller passes the view model to the view and the view displays it with the proper formating/localization.

    Conclusion: models should not be formatted/localized or they become more difficult to reuse.