Introduction
This article would help you to create a custom resource reader if you are starting out. Resources are an application-building feature that allow you to place culture-specific items inside satellite files, rather than directly in your main application. When you build your application, you can identify aspects that are culture-specific, and make a different resource file for each culture where you think your application may be used. At run time, the appropriate set of resources will be loaded, based on the user's culture settings. The specific setting used is the CurrentUICulture
for your thread, which the user can set programmatically.
When you make your application, it is housed in an 'assembly'. An assembly consists of the following:
- The assembly metadata, also called the assembly manifest
- Type metadata
- The Microsoft Intermediate Language (MSIL) code that implements the types
- A set of resources
You may also put these resource files in an external repository like a database. For that, you have to create a custom resource reader for your application.
Using the Code
For this article, language specific resource elements are placed in the Microsoft SQL Server database. Create a SQL Server database with a single table Messages
. Its create
script would look like this:
CREATE TABLE [dbo].[Messages]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Key] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Default] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[de] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[mn] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
CONSTRAINT [PK_Messages] PRIMARY KEY CLUSTERED ([Id] ASC)WITH _
(IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
There are three steps to creating a custom resource reader. The first step is to create a class that implements IResourceReader
, which requires a Close
method and an implementation for GetEnumerator
.
public class DBResourceReader:IResourceReader
{
private string ConnectionString;
private string Language;
public DBResourceReader(string ConnectionString, CultureInfo Culture)
{
this.ConnectionString = ConnectionString;
this.Language = Culture.Name;
}
public IDictionaryEnumerator GetEnumerator()
{
Hashtable htLanguage = new Hashtable();
SqlConnection conn = new SqlConnection(ConnectionString);
SqlCommand command = conn.CreateCommand();
if (Language == "")
Language = "Default";
command.CommandText = "Select [key], [" + Language + "] from Messages";
try
{
conn.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
if (reader.GetValue(1) != System.DBNull.Value)
htLanguage.Add(reader.GetString(0), reader.GetString(1));
}
reader.Close();
}
catch {}
finally
{
conn.Close();
}
return htLanguage.GetEnumerator();
}
public void Close()
{ }
public void Dispose()
{ }
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
The next step is to generate a custom resource set. It stores all the resources localized for one particular culture. To do this, create a derived class of DBResourceSet
, and override GetDefaultReader
:
public class DBResourceSet:ResourceSet
{
public DBResourceSet(string ConnectionString, CultureInfo Culture):
base(new DBResourceReader(ConnectionString,Culture))
{}
public override Type GetDefaultReader()
{
return typeof(DBResourceReader);
}
}
The next step is to generate a custom resource manager that uses the custom reader. To do this, create a derived class of ResourceManager
, and override InternalGetResourceSet
to allow for the creation of the resource reader defined earlier. The following code example demonstrates a simple ResourceManager
:
public class DBResourceManager : ResourceManager
{
private string ConnectionString;
public DBResourceManager(string ConnectionString)
{
this.ConnectionString = ConnectionString;
ResourceSets = new Hashtable();
}
protected override ResourceSet InternalGetResourceSet(
CultureInfo culture, bool createIfNotExists, bool tryParents)
{
DBResourceSet rs = null;
if (ResourceSets.Contains(culture.Name))
{
rs = (DBResourceSet)ResourceSets[culture.Name];
}
else
{
rs = new DBResourceSet(ConnectionString, culture);
ResourceSets.Add(culture.Name, rs);
}
return rs;
}
}
Conclusion
This article explains how to create a custom resource reader by using SQL Server database as resource repository for storing localized resources. You can also implement resource reader interface by using a different resource repository.