建立自定义的数据驱动的本地化资源provider

建立自定义的数据驱动的本地化资源provider

转自http://www.west-wind.com/presentations/wwdbresourceprovider/
作者:Rick Strahl.
改写:于宏伟
关键词:asp.net 资源,本地化, resource provider,resx.

本文探讨了自定义的本地化资源提供者.如果想用一个可替代系统的资源处理方案,例如把所有的资源放入数据库中,而不是放在分散的资源文件里,你可以自定义一个resource provider.
原文很长,为了便于阅读和理解,特将该文章改写成通俗易懂而且内容精炼的中文.

预备知识:系统默认的处理资源和本地化的方法是使用resx文件存储资源.

要使用自定义的resource provider,需要2个步骤:
 a) 修改web.config 文件,以便系统使用自定义的资源提供者
 b) 建立自定义资源提供者类,最少包括3个:
      1.ResourceProviderFactory,工厂类,用来建立ResourceProvider对象.
  2.ResourceProvider,实现IResourceProvider,IImplicitResourceProvider,IwwResourceProvider 接口.
  3.ResourceReader 实现IResourceReader.
 

修改web.config 文件,以使用自定义的资源提供者。

<configuration>
  <system.web>
    <globalization resourceProviderFactoryType="Westwind.Globalization.DbSimpleResourceProviderFactory,Westwind.Globalization" />
  </system.web>
</configuration>


建立自定义资源提供者类:
1.工厂类
[DesignTimeResourceProviderFactoryAttribute(typeof(DbDesignTimeResourceProviderFactory))]
public class DbSimpleResourceProviderFactory : ResourceProviderFactory
{
   
    public override IResourceProvider CreateGlobalResourceProvider(string classname)
    {
        return new DbSimpleResourceProvider(null, classname);
    }
 
  
    public override IResourceProvider CreateLocalResourceProvider(string virtualPath)
    {
       
        string ResourceSetName = DbResourceConfiguration.Current.StripVirtualPath(virtualPath);
        return new DbSimpleResourceProvider(null,ResourceSetName.ToLower());
    }
}

2.提供者类
public class DbSimpleResourceProvider : IResourceProvider, IImplicitResourceProvider
{  
   
    private string _ResourceSetName;       
 
 
    private IDictionary _resourceCache;
 

    private DbSimpleResourceProvider()
    { }
 

    public DbSimpleResourceProvider(string virtualPath, string className)
    {
        _ResourceSetName = className;           
    }
 

  
    private IDictionary GetResourceCache(string cultureName)
    {
        if (cultureName == null)
            cultureName = "";
 

        if (this._resourceCache == null)
            this._resourceCache = new ListDictionary();
 

        IDictionary Resources = this._resourceCache[cultureName] as IDictionary;
        if (Resources == null)
        {
            // *** DEPENDENCY HERE (#1): Using DbResourceDataManager to retrieve resources
 

            // *** Use datamanager to retrieve the resource keys from the database
            DbResourceDataManager Data = new DbResourceDataManager();
            Resources = Data.GetResourceSet(cultureName as string, this._ResourceSetName);
            this._resourceCache[cultureName] = Resources;
        }
 

        return Resources;
    }  
 

  
    public void ClearResourceCache()
    {
        this._resourceCache.Clear();
    }
 

   
    object IResourceProvider.GetObject(string ResourceKey, CultureInfo Culture)
    {
        string CultureName = null;
        if (Culture != null)
            CultureName = Culture.Name;
        else
            CultureName = CultureInfo.CurrentUICulture.Name;
 

        return this.GetObjectInternal(ResourceKey, CultureName);
    }
 

   
    object GetObjectInternal(string ResourceKey, string CultureName)
    {
        IDictionary Resources = this.GetResourceCache(CultureName);
       
        object value = null;          
        if (Resources == null)
            value = null;
        else
            value = Resources[ResourceKey];
                       
        // *** If we're at a specific culture (en-Us) and there's no value fall back
        // *** to the generic culture (en)
        if (value == null && CultureName.Length > 3)
        {
            // *** try again with the 2 letter locale
            return GetObjectInternal(ResourceKey,CultureName.Substring(0,2) );
        }
 

        // *** If the value is still null get the invariant value
        if (value == null)
        {
            Resources = this.GetResourceCache("");
            if (Resources == null)
              value = null;
            else
              value = Resources[ResourceKey];
        }
 

        // *** If the value is still null and we're at the invariant culture
        // *** let's add a marker that the value is missing
        // *** this also allows the pre-compiler to work and never return null
        if (value == null && string.IsNullOrEmpty(CultureName))
        {
            // *** No entry there
            value = "";
 

            // *** DEPENDENCY HERE (#2): using DbResourceConfiguration and DbResourceDataManager to optionally
            //                           add missing resource keys
 

            // *** Add a key in the repository at least for the Invariant culture
            // *** Something's referencing but nothing's there
            if (DbResourceConfiguration.Current.AddMissingResources)
                new DbResourceDataManager().AddResource(ResourceKey, value.ToString(), "", this._ResourceSetName);               
 

        }
 

        return value;
    }


3.Reader类

public class DbSimpleResourceReader : IResourceReader
{
    private IDictionary _resources;
 

    public DbSimpleResourceReader(IDictionary resources)
    {
        _resources = resources;
    }
    IDictionaryEnumerator IResourceReader.GetEnumerator()
    {
        return _resources.GetEnumerator();
    }
    void IResourceReader.Close()
    {
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return _resources.GetEnumerator();
    }
    void IDisposable.Dispose()
    {
    }
}
 
完毕。
本人没有测试过,待测试通过,献上最精炼的源代码.敬请稍候.

 

posted @ 2010-06-16 09:14  满堂金  阅读(472)  评论(0编辑  收藏  举报