自定义ResourceProviderFactory、IResourceProvider实现ASP.NET、ASP.NET MVC多语言支持

ASP.NET的默认资源分为Global、Local(ASP.NET Folder的App_GlobalResources、APP_LocalResources)。App_GlobalResources为全局共享资源、App_LocalResources根据虚拟路径对应到页面。如何获取这两类资源需要实现System.Web.Compilation.ResourceProviderFactory的两个函数:CreateGlobalResourceProvider、CreateLocalResourceProvider,两者都返回一个System.Web.Compilation.IResourceProvider的实现。本文主要描述如何实现加载外部资源,并不考虑针对virtualPath的映射。下面是一个ResourceProviderFactory的实现:

/// <summary>
/// 外部资源提供器工厂
/// </summary>
public sealed class ExternalResourceProviderFactory : ResourceProviderFactory
{
    /// <summary>
    /// 构造函数
    /// </summary>
    public ExternalResourceProviderFactory() { }

    /// <summary>
    /// 获取全局资源提供器
    /// </summary>
    /// <param name="classKey">类键值</param>
    /// <returns>资源提供器</returns>
    public override IResourceProvider CreateGlobalResourceProvider(String classKey)
    {
        return new GlobalExternalResourceProvider(classKey);
    }

    /// <summary>
    /// 获取本地资源提供器
    /// </summary>
    /// <param name="virtualPath">虚拟路径</param>
    /// <returns>资源提供器</returns>
    public override IResourceProvider CreateLocalResourceProvider(String virtualPath)
    {
        throw new NotSupportedException();
    }
}

ASP.NET默认的ResourceExpressionBuilder支持<%$ Resources:[ClassKey], [ResourceKey]%>格式语法,通过自定义ClassKey的规则加载一个外部程序集的资源类型:[AssemblyName]|[ResourceTypeName]。比如:<%$ Resources:MultiLangDemo1.Resources|Strings, Button_Click%>,根据这个规则编写一个支持规则的IResourceProvider实现:

/// <summary>
/// 全局外部资源提供器
/// </summary>
public sealed class GlobalExternalResourceProvider : IResourceProvider
{
    /// <summary>
    /// 分隔符-类键值
    /// </summary>
    private const Char SEPARATOR_CLASSKEY = '|';

    private Lazy<ResourceManager> _lazyResourceMangaer;

    private String _assemblyName;
    private String _typeName;

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="classKey">类键值</param>
    public GlobalExternalResourceProvider(String classKey)
    {
        String[] strArray = classKey.Split(SEPARATOR_CLASSKEY);

        if (strArray.Length == 0)
            throw new ArgumentException("格式不正确");

        _assemblyName = strArray[0];
        _typeName = strArray[1];
        _lazyResourceMangaer = new Lazy<ResourceManager>(CreateResourceManager);
    }

    /// <summary>
    /// 资源管理器
    /// </summary>
    private ResourceManager ResourceManager
    {
        get
        {
            return _lazyResourceMangaer.Value;
        }
    }

    /// <summary>
    /// 创建资源管理器
    /// </summary>
    /// <returns>资源管理器</returns>
    private ResourceManager CreateResourceManager()
    {
        Assembly assembly = Assembly.Load(_assemblyName);

        return new ResourceManager(String.Format(CultureInfo.InvariantCulture, "{0}.{1}", _assemblyName, _typeName), assembly);
    }

    #region IResourceProvider Members

    /// <summary>
    /// 获取资源对象
    /// </summary>
    /// <param name="resourceKey">资源键</param>
    /// <param name="culture">文化信息</param>
    /// <returns>资源对象</returns>
    public Object GetObject(String resourceKey, CultureInfo culture)
    {
        if (culture == null)
            culture = CultureInfo.CurrentUICulture;

        return this.ResourceManager.GetObject(resourceKey, culture);
    }

    /// <summary>
    /// 资源读取器
    /// </summary>
    public IResourceReader ResourceReader
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    #endregion
}

如果想要自定义表达式的语法,可以继承System.Web.Compilation.ExpressionBuilder。在Web.config中配置自定义的ResourceProviderFactory:

<configuration>
  <system.web>
    <compilation debug="true"
                 targetFramework="4.0" />
    <globalization uiCulture="auto"
                   culture="auto"
                   resourceProviderFactoryType="CustomResourceProviders.ExternalResourceProviderFactory, CustomResourceProviders" />
  </system.web>
</configuration>

在.aspx页面尝试访问某个外部程序集资源键值:

<asp:Button ID="btnClick" runat="server" Text="<%$ Resources:MultiLangDemo1.Resources|Strings, Button_Click %>"
    OnClick="btnClick_Click" />

ASP.NET MVC中继续使用这种方式,只需添加System.Web.Mvc.HtmlHelper<T>对应的扩展函数,访问HttpContextBase的GetGlobalResourceObject函数就可实现:

/// <summary>
/// HtmlHelper扩展函数
/// </summary>
public static class HtmlHelperExtension
{
    /// <summary>
    /// 获取全局资源对象
    /// </summary>
    /// <param name="html">Html辅助类</param>
    /// <param name="classKey">类键值</param>
    /// <param name="resourceKey">资源键</param>
    /// <returns>资源对象</returns>
    public static Object GetGlobalResourceObject<T>(this HtmlHelper<T> html, String classKey, String resourceKey)
    {
        return GetGlobalResourceObject(html, classKey, resourceKey);
    }

    /// <summary>
    /// 获取全局资源对象
    /// </summary>
    /// <param name="html">Html辅助类</param>
    /// <param name="classKey">类键值</param>
    /// <param name="resourceKey">资源键</param>
    /// <param name="culture">文化信息</param>
    /// <returns>资源对象</returns>
    public static Object GetGlobalResourceObject<T>(this HtmlHelper<T> html, String classKey, String resourceKey, CultureInfo culture)
    {
        if (culture == null)
            culture = CultureInfo.CurrentUICulture;

        return html.ViewContext.HttpContext.GetGlobalResourceObject(classKey, resourceKey, culture);
    }

    /// <summary>
    /// 获取全局资源字符串
    /// </summary>
    /// <param name="html">Html辅助类</param>
    /// <param name="classKey">类键值</param>
    /// <param name="resourceKey">资源键</param>
    /// <returns>资源对象</returns>
    public static String GetGlobalResourceAsString<T>(this HtmlHelper<T> html, String classKey, String resourceKey)
    {
        return GetGlobalResourceAsString(html, classKey, resourceKey, null);
    }

    /// <summary>
    /// 获取全局资源字符串
    /// </summary>
    /// <param name="html">Html辅助类</param>
    /// <param name="classKey">类键值</param>
    /// <param name="resourceKey">资源键</param>
    /// <param name="culture">文化信息</param>
    /// <returns>资源对象</returns>
    public static String GetGlobalResourceAsString<T>(this HtmlHelper<T> html, String classKey, String resourceKey, CultureInfo culture)
    {
        return GetGlobalResourceObject(html, classKey, resourceKey, culture) as String;
    }
}

在view中使用它:

<input type="button" value="@Html.GetGlobalResourceAsString("MultiLangDemo1.Resources|Strings", "Button_Click")" />
原文地址:https://www.cnblogs.com/junchu25/p/2769006.html