Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / C#

T4 template for Silverlight apps to generate a class with literal strings defined in a .resx file

Rate me:
Please Sign up or sign in to vote.
4.50/5 (8 votes)
6 Sep 2010CPOL2 min read 26.4K   75   7   3
A T4 template for Silverlight apps that generates a class containing literal strings for all the resource strings defined in a .resx file. It helps make your Silverlight code much more maintainable.

Introduction

This article describes how to generate a class containing literal strings for the resources defined in a .resx resource file using a simple T4 template.

Background

When applying extra DataAnnotations like [Display] or [Required] to your business entities to add metadata resource texts to properties, a type error is easily made, and there is no way the compiler can help you in defining the problem. You'll only the see an error when running the Silverlight application.

Problem Description

I've created a default Silverlight Business Application using VS2010, which looks like this:

In this project, there is a User.shared.cs file which adds some DataAnnotations to define extra metadata for this entity.

The code looks as follows:

C#
public sealed partial class RegistrationData
{
    /// <summary />
    /// Gets and sets the user name.
    /// </summary />
    [Key]
    [Required(ErrorMessageResourceName = "ValidationErrorRequiredField", 
     ErrorMessageResourceType = typeof(ValidationErrorResources))]
    [Display(Order = 0, Name = "UserNameLabel", 
     ResourceType = typeof(RegistrationDataResources))]
    [RegularExpression("^[a-zA-Z0-9_]*$", 
     ErrorMessageResourceName = "ValidationErrorInvalidUserName", 
     ErrorMessageResourceType = typeof(ValidationErrorResources))]
    [StringLength(255, MinimumLength = 4, 
     ErrorMessageResourceName = "ValidationErrorBadUserNameLength", 
     ErrorMessageResourceType = typeof(ValidationErrorResources))]
    public string UserName { get; set; }

    ...

When running this Silverlight application, you see the following Register screen:

As you can see, everything looks correct.

But what happens when you make a type mistake (UserNameLabel_ instead of UserNameLabel)?

The project does compile correct, and no errors or warnings are shown. But when running the application, the Register screen has some errors:

The errors are:

  • UserName is displayed last instead of first.
  • UserName is not translated correctly anymore to 'User name'.

Solution for This Problem

My solution for this problem is to create a T4 template which will read the .resx file in the MyBusinessApplication.Web project and create a class which defines all the strings defined.

The simple T4 template looks like this:

ASP.NET
<#@ template debug="true" hostSpecific="true" #>
<#@ output extension=".cs" encoding="ASCII" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ Assembly Name="System.Xml.dll" #>
<#@ Assembly Name="System.Xml.Linq.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Xml.Linq" #>
<#
    string resourceFile = "RegistrationDataResources";
    string PostFix = ""; // String / Label
#>
//------------------------------------------------------------------------------
// <auto-generated>
//     This code was auto-generated at <#= DateTime.Now #>.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace MyBusinessApplication.Web.Resources
{
    using System;
    
    /// <summary>
    /// A static helper class which exposes all strings as const
    /// strings which are present in the resource file.
    /// </summary>
    [System.CodeDom.Compiler.GeneratedCodeAttribute(
      "RegistrationDataResources.shared.tt", "1.0.0.0")]
    public static class ResourceLiterals
    {
<#
        string filename = Path.Combine(Path.GetDirectoryName(this.Host.TemplateFile), 
                          resourceFile + ".resx");
        var names = (from e in XElement.Load(filename).Elements("data") 
                     select e.Attribute("name").Value).ToList();

    int idx = 0;
    string name = names[0];
#>
        /// <summary>
        /// The string <#=name#>
        /// </summary>
        public const string <#=name#><#=PostFix#> = "<#=name#>";
<#
        for (idx = 1 ; idx < names.Count(); idx++)
        {
            name = names[idx];
#>

        /// <summary>
        /// The string <#=name#>
        /// </summary>
        public const string <#=name#><#=PostFix#> = "<#=name#>";
<#
        }
#>
    }
}

Create a file called RegistrationDataResources.shared.t and add this to the solution. Copy the contents from above to this .tt file.

The solution looks like this now:

The file RegistrationData.cs can now be updated to use the static class 'ResourceLiterals':

C#
public sealed partial class RegistrationData
{
    /// <summary>
    /// Gets and sets the user name.
    /// </summary>
    [Key]
    [Required(ErrorMessageResourceName = "ValidationErrorRequiredField", 
     ErrorMessageResourceType = typeof(ValidationErrorResources))]
    [Display(Order = 0, Name = ResourceLiterals.EmailLabel, 
     ResourceType = ResourceLiterals.ResourceType)] [RegularExpression("^[a-zA-Z0-9_]*$", 
     ErrorMessageResourceName = "ValidationErrorInvalidUserName", 
     ErrorMessageResourceType = typeof(ValidationErrorResources))]
    [StringLength(255, MinimumLength = 4, 
     ErrorMessageResourceName = "ValidationErrorBadUserNameLength", 
     ErrorMessageResourceType = typeof(ValidationErrorResources))]
    public string UserName { get; set; }

    ...

Note: The file name must be *.shared*, else the Silverlight Presentation project cannot use it. (RIA Services will not generate client-side code.)

Conclusion

Now you have strongly typed resource literals. Use this T4 template as a starting point and adapt it to your own needs.

Source code can be found here.

History

  • First version posted on 2010-08-17.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Netherlands Netherlands
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 4 Pin
Eric Xue (brokensnow)6-Sep-10 10:18
Eric Xue (brokensnow)6-Sep-10 10:18 
GeneralMy vote of 4 Pin
anishmehta18-Aug-10 7:00
anishmehta18-Aug-10 7:00 
GeneralGood Work.. Pin
Md. Marufuzzaman16-Aug-10 20:43
professionalMd. Marufuzzaman16-Aug-10 20:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.