Thursday, July 28, 2016

Making App_GlobalResources -> .RESX public


Regarding the previous post you may want to use strings from a global resources.resx file (App_GlobalResources) as error messages or descriptions in your attributes. This won’t work because global resource files are by default marked as internal and so you can’t access them from your controller or your model. Also the little “Access Modifier” dropdown menu in the resource editor is grayed out, so you can’t change the access level without further ado.

However there’s a way to change the access rights without editing the designer file by hand.
You just have to open the file properties of the resource file and change the “Custom Tool” from “GlobalResourceProxyGenerator” to “PublicResXFileCodeGenerator”, which is the default Tool for local resource files. Next you have to change the “Build Action” to “Embedded Resource”. You may also want to assign a proper Custom Tool Namespace like “Resources” in order to access the file properly, but this isn’t necessary.


Now rebuild the project and you should notice that the resource access is now public and you can access its contents from anywhere in your project.
E.g. like that:


[Required(ErrorMessageResourceType = typeof(Resources.Resource1)
, ErrorMessageResourceName = "Comment_Text")]
public string Myproperty { get; set; }

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 theGlobalResourceProxyGenerator 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 StringAttributeboth 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.

The difference between DisplayNameAttribute and MVC 3 new DisplayAttribute


You may already know that ASP.NET MVC 2 introduced the DisplayNameAttribute which is part of the System.ComponentModel namespace. This attribute allowed us to display the name of the customer as the “Customer Name” instead of the actual property name: “Name”.
mvc display name attribute
ASP.NET MVC 3 now supports DisplayAttribute in System.ComponentModel.DataAnnotation namespace. DisplayAttribute is new in .NET 4.
mvc display attribute
So what is the real difference between the “DisplayAttribute”, and the “DisplayNameAttribute”? They serve the same purpose, which is displaying a custom string, however the key difference is in the overloads they provide.
“DisplayAttribute” supports more overloads than the DisplayNameAttribute”.
display attribute param overload
DisplayNameAttribute” only supports a string which is the DisplayName.
display-name-attribute-param
Even though it doesn’t make sense to do so, what happens if we were to specify both attributes?
mvc display & display name attribute
In this situation, the new DisplayAttribute takes precedence over the DisplayNameAttribute. Instead of the “Customer name 2” we should see the “Customer name 1” displayed to the user.
Handing Resources
In some cases, we need the DisplayAttribute to be resource sensitive. For an example, instead of using non-localized resources, we might want to use the standard .NET resource provider to retrieve the localized resources. 
display-attribute
Below is a simple example on how to configure the resources so they can be displayed based on the localization.
resource-handling
image
As we did for the above DisplayAttribute, it is not straightforward to make DisplayNameAttribute to be resource sensitive. DisplayNameAttribute does not support a parameter for ResourceType. In that case, we need to subclass the DisplayNameAttribute and provide our own implementation similar to below.
image
Below is the usage of new sub classed attribute:
image