Silverlight Validation: Resource File
Posted
Tue, May 3 2011 0:04
by
Deborah Kurata
Resource files are a great way to manage strings, especially if you need to support multiple languages. This post demonstrates how to use a resource file with the validation attributes used by Silverlight and WCF RIA Services.
NOTE: This post is part of a set of validation posts which starts here and it uses the sample code from this prior post.
In this prior post, the code example demonstrated how to use the single property validation attributes available in Silverlight and WCF RIA Services. For example, to validate that a first name is entered and does not exceed 20 characters, the attributes look like this:
[Required(ErrorMessage="Please enter a first name.")]
[StringLength(20, ErrorMessage = "First name cannot exceed 20 characters.")]
public string FirstName { get; set; }
Notice how the validation error messages are hard-coded strings. This poses a challenge if you need to localize your application.
A better option is to add the strings to a resource file. The trick here is that the resource file needs to exist both on the server (in the Class Library project if you are using WCF RIA with your own business layer) and on the client (in the Silverlight project). This is done by a process called linking.
1) In the Class Library project containing your business layer, add a resource file (Add | New Item | Resources File).
I added mine to a Resources folder in the project.
NOTE: If you are not using your own business layer on the server, you can add the resource file directly to the Web project instead.
2) Enter a name for each string along with the string values. Optionally add a comment.
3) Set the Access Modifier for each resource string to Public.
The result should look something like this:

4) In the Silverlight project, link to that resource file by selecting Add | Existing Item and then clicking on Add As Link in the Add Existing Item dialog.

5) In the Silverlight project, link also to the associated Designer.cs file.
NOTE: The Add Existing Item dialog allows multiple selection. So you could link both the rex file and the Designer/cs file in one step.
6) Modify the attribute parameters in the business layer Class Library project to reference the resource file instead of using hard-coded strings. Be sure to add a using for the resource file's namespace:
using InStepValidationExample.BL.Resources;
[Required(ErrorMessageResourceType = typeof(ValidationErrorResources),
ErrorMessageResourceName = "FirstNameRequired")]
[StringLength(20,
ErrorMessageResourceName = "FirstNameLength",
ErrorMessageResourceType = typeof(ValidationErrorResources))]
public string FirstName { get; set; }
Instead of setting the ErrorMessage parameter to a hard-coded string, this code sets the ErrorMessageResourceType parameter to the type of the resource file (which is the resource file name). The ErrorMessageResourceName parameter specifies the name that you defined for the associated resource string in the resource file.
7) Now for the tricky part. By default, Visual Studio requires that the two resource files be in the same namespace. If they aren't, the application won't find the resources.
For example, if you use the Silverlight Business Application template, you can see that it puts the resource file in the BizApp.Web project under a Resources folder. The resources are then in the BizApp.Web.Resources namespace.
To access the resources from the BizApp Silverlight project, the file is put in a folder hierarchy with a Web folder and then a Resources folder so the resulting namespace is again BizApp.Web.Resources.

In the example for this post, however, the resources are in a Class Library in a business layer separate from the Web project:

The namespace of the resources in the business layer is InStepValidationExample.BL.Resources. The namespace of the resources in the Silverlight project is InStepValidatoinExample.SL.Resources.
So if you run the application at this point, it will crash with a "TargetInvocationException occurred" message. If you look at the exception detail it says "Could not find any resources appropriate for the specified culture or the neutral culture..." Basically, it cannot find the resource file.
Luckily, we know the secret handshake required to get this to work:
7a) Right-click on the Silverlight project and select Unload Project.
7b) Right-click on the Silverlight project again and select to edit the project file.
7c) Add a <LogicalName> element to the <EmbeddedResource> element in the project file and set it to the namespace and resource name. Mine looked like this:
<ItemGroup>
<EmbeddedResource Include="..\InStepValidationExample.BL\Resources\ValidationErrorResources.resx">
<Link>Resources\ValidationErrorResources.resx</Link>
<LogicalName>
InStepValidationExample.BL.Resources.ValidationErrorResources.resources
</LogicalName>
</EmbeddedResource>
</ItemGroup>
7d) Close the project file.
7e) Right-click on the Silverlight project and select Reload Project.
Now when you run, it should find your resource file.

Use a resource file any time you want better management of your strings, especially if you plan to localize your application.
Enjoy!