Sunday, June 9, 2013

Solve Cannot retrieve property 'Name' because localization failed. Type 'YourResourceFile' is not public or does not contain a public static string property with the name 'YourItemName'.

Data Annotations are a great thing. They allow you to add information to your model quickly and easily. However, if you have an application that is designed for multiple cultures, you cannot add a Name to your annotation and have it display appropriately for other cultures. It is easy to use App_GlobalResources to hold your global strings, however, you may encounter the following message when using an App_GlobalResources folder in Asp.Net MVC -

        [Required(
            ErrorMessageResourceName = "Required_PleaseSelectA",
            ErrorMessageResourceType = typeof(StringResources))]
        [StringLength(100,
            ErrorMessageResourceName = "Length_YourMustBeACombination",
            ErrorMessageResourceType = typeof(StringResources),
            MinimumLength = 6)]
        [Display(
            ResourceType = typeof(LocalizedResources),
            Name = "CategoryName",
            Description = "CategoryName")]
        public string CategoryName { get; set; }
Cannot retrieve property 'Name' because localization failed.  Type 'Resources.StringResources' is not public or does not contain a public static string property with the name 'CategoryName'.

In this particular example, I set up resources for a property called CategoryName.
This error is VERY simple to solve. The resource file needs to be made public.
To do this, you will need to change the TYPE of tool used to generate the resource file.

In Asp.Net MVC 4, when you add a App_GlobalResources folder and create a resource file in it, by default the resource file is set up as internal and given the GlobalResourceProxyGenerator as a tool. That internal designation creates a problem for the DisplayAttribute annotation because it checks to see if the ResourceType is visible. In fact, it actually uses Type.IsVisible. This creates a problem because the internal class is NOT visible to it.

Now here is an interesting thing to note. The RequiredAttribute and StringAttribute both inherit from ValidationAttribute. The DisplayAttribute does NOT. The Required and String Attributes utilize a different mechanism to connect with the resource files. You can see subtle differences when you look at how the items are set up again -

        [Required(
            ErrorMessageResourceName = "Required_PleaseSelectA",
            ErrorMessageResourceType = typeof(StringResources))]
        [StringLength(100,
            ErrorMessageResourceName = "Length_YourMustBeACombination",
            ErrorMessageResourceType = typeof(StringResources),
            MinimumLength = 6)]

        [Display(
            ResourceType = typeof(StringResources),
            Name = "CategoryName",
            Description = "CategoryName")]

        public string CategoryName { get; set; }
Notice that each resource file in the photo of App_GlobalResources above has a .cs file attached to it.When you click on that resource file,  you see that all of the classes are internal. If you change the CustomTool to PublicResXFileCodeGenerator and rebuild your application, you will see the .cs file go from internal to public and your DisplayAttribute will be able to connect with the resource file now. In fact, if you click on the .cs file to open it AND change then go over to properties and change the CustomTool, all of the items in the file will automagically change from internal to public.

Smooches,

Kila Morton