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")" />