如何让ASP.NET默认的资源编程方式支持非.ResX资源存储

简介:

之前写了两篇文章《.NET资源并不限于.ResX文件》(上篇下篇),介绍了如何通过自定义ResourceManager的方式来扩展资源的存储形式。在那篇文章中,我定义了三种基于独立文件的ResourceManager(ResXResourceManager、BinaryResourceManager和XmlResoureManager)分别实现对.ResX,.Resource和.xml三种资源文件的访问。在本篇文章中我们将实现自定义ResourceManager和ASP.NET之间的集成,让ASP.NET现有的资源编程方式支持我们自定义的ResourceManager。

一、回顾一下之前创建的XmlResourceManager
二、创建自定义ResourceProvider
三、创建自定义ResourceProviderFactory
四、Global Resource编程
五、Local Resource编程

一、回顾一下之前创建的XmlResourceManager

本篇文章将会以我们之前创建的XmlResourceManager为例。通过自定义的XmlResourceManager,我们实现了将资源内容定义在了一个自定义结构的XML文件。该XML具有如下一个简单的结构。

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <resources>
   3:   <add name="Greeting4Chris" value="Merry Christmas!" />
   4:   <add name="Greeting4NewYear" value="Happy Chinese New Year!" />
   5: </resources>

image.ResX文件一样,为了提供多多语言的支持,我们用带有Culture Code后缀的文件名来区分资源文件所基于语言文化。如右图所示,我在一个Web Application中,定义了两套资源文件:Global Resource和Local Resource。两种资源类型的概念,不用多说你也应该知道。前者是一个全局意义的资源文件,供所有Web页共享;后者则是基于某个Web页单独使用的本地资源。

二、创建自定义ResourceProvider

要让ASP.NET现有的资源编程方式将我们添加的XML作为资源存储,必须了解ASP.NET内部采用的资源读取机制。实际上,ASP.NET在后台采用一个特殊的组件进行资源的读取,这个组件就是ResourceProvider。我们只需要创建一个基于XmlResourceManager的自定义ResourceProvider,并将它注册到ASP.NET中就可以了。

为此我创建了如下一个XmlResourceProvider,它实现了IResourceProvider。IResourceProvider具有一个GetObject方法和一个ResourceReader只读属性。前者实现了对指定键值的资源条目的读取,后者则返回一个ResourceReader。在GetObject方法中,我们利用自定义的XmlResourceManager进行资源的获取,而ResourceReader属性的实现中,我们返回的我们之前创建的XmlResourceReader。

   1: public class XmlResourceProvider:IResourceProvider
   2:    {
   3:        public XmlResourceManager ResourceManager { get; private set; }
   4:  
   5:        public XmlResourceProvider(string directory, string baseName)
   6:        {
   7:            this.ResourceManager = new XmlResourceManager(directory, baseName);
   8:        }
   9:  
  10:        public object GetObject(string resourceKey, CultureInfo culture)
  11:        {
  12:            return this.ResourceManager.GetObject(resourceKey, culture);
  13:        }
  14:  
  15:        public IResourceReader ResourceReader
  16:        {
  17:            get
  18:            { 
  19:                return new XmlResourceReader(Path.Combine(this.ResourceManager.Directory,this.ResourceManager.BaseName+".xml"));
  20:            }
  21:        }

三、创建自定义ResourceProviderFactory

XmlResourceProvider创建完毕,但是它不能直接被注册,我们需要创建一个对应的工厂类。为此,如下一个名称为XmlResourceProviderFactory类被创建出来。

   1: public class XmlResourceProviderFactory:ResourceProviderFactory
   2: {
   3:     public override IResourceProvider CreateGlobalResourceProvider(string classKey)
   4:     {
   5:         string directory = HttpContext.Current.Server.MapPath("GlobalResources");
   6:         return new XmlResourceProvider(directory, classKey);
   7:     }
   8:  
   9:     public override IResourceProvider CreateLocalResourceProvider(string virtualPath)
  10:     {
  11:         string directory = HttpContext.Current.Server.MapPath(VirtualPathUtility.GetDirectory(virtualPath));
  12:         string baseName = VirtualPathUtility.GetFileName(virtualPath);
  13:         return new XmlResourceProvider(directory, baseName);
  14:     }
  15: }

XmlResourceProviderFactory继承自抽象类ResourceProviderFactory,并实现了两个抽象方法CreateGlobalResourceProvider和CreateLocalResourceProvider。这两个方法均返回一个ResourceProvider对象,它们分别用于基于Global Resource和Local Resource的读取。在XmlResourceProviderFactory中,这两个方法均返回一个XmlResourceProvider对象。所不同的是,CreateGlobalResourceProvider方法返回的XmlResourceProvider基于的资源文件是一个存储在GlobalResources目录下指定名称(classKey)的XML文件,而CreateLocalResourceProvider返回的XmlResourceProvider基于的资源则是和当前访问.aspx文件处于同级目录下,并且名称和.aspx文件同名的XML文件。

在web.config中,XmlResourceProviderFactory通过<system.web>/<globalization>配置节进行注册,下面是相应的配置。

   1: <?xml version="1.0"?>
   2: <configuration>
   3:     <system.web>
   4:         <globalization uiCulture="zh-CN" resourceProviderFactoryType="Artech.ResourceAppBlock.XmlResourceProviderFactory, Artech.ResourceAppBlock.Lib"/>
   5:         <compilation debug="true"/></system.web>
   6: </configuration>

四、Global Resource编程

现在我们来验证以下通过ASP.NET原生的资源编程模式是否能够正常读取我们指定的XML。我们先来演示Global Resource的读取,为此我们创建了一个Web项目,并进行了如上的配置。如上面途中所示,我们在GlobalResources目录下添加了3个XML文件,其中GreetingMessages.xml作为语言文化中性的资源文件,而GreetingMessages.en-US.xml和GreetingMessages.zh-CN.xml则基于美式英语和简体中文。GreetingMessages.xml和GreetingMessages.en-US.xml具有相同的内容。

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <resources>
   3:   <add name="Greeting4Chris" value="Merry Christmas!" />
   4:   <add name="Greeting4NewYear" value="Happy Chinese New Year!" />
   5: </resources>

而GreetingMessages.zh-CN.xml则为中文。

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <resources>
   3:   <add name="Greeting4Chris" value="圣诞快乐!" />
   4:   <add name="Greeting4NewYear" value="新年快乐!" />
   5: </resources>
现在我们创建一个文件名称为Defualt.aspx的Web页,并在其中放置两个Label控件相应的HTML如下所示。
   1: <body>
   2:     <form id="form1" runat="server">
   3:     <div>
   4:         <asp:Label id="LabelGreeting4NewYear" runat="server"  />
   5:         <br/>
   6:         <asp:Label id="LabelGreeting4Chris" runat="server"/>
   7:     </div>
   8:     </form>
   9: </body>

在Page加载的时候,通过如下的代码将两个Label和相应的资源条目进行绑定。

   1: protected void Page_Load(object sender, EventArgs e)
   2: {
   3:     this.LabelGreeting4NewYear.Text = this.GetGlobalResourceObject("GreetingMessages", "Greeting4NewYear").ToString();
   4:     this.LabelGreeting4Chris.Text = this.GetGlobalResourceObject("GreetingMessages", "Greeting4Chris").ToString();
   5: }

在浏览器中访问页面,你会得到如下的文字。

   1: 新年快乐! 
   2: 圣诞快乐!

如果当前的语言文化为en-US,或者其它非zh-CN,页面的文字将显示为英文。比如,你通过如下的配置将默认的UI Culture替换成en-US,你将在页面中得到如下的显示。

   1: <?xml version="1.0"?>
   2: <configuration>
   3:     <system.web>
   4:         <globalization uiCulture="en-US" resourceProviderFactoryType="Artech.ResourceAppBlock.XmlResourceProviderFactory, Artech.ResourceAppBlock.Lib"/>
   5:         <compilation debug="true"/></system.web>
   6: </configuration>

实现结果:

   1: Happy Chinese New Year! 
   2: Merry Christmas!

实际上对于Global Resource的读取,你可以采用更为简洁的编程方式,就是以内联的方式,以<%$ Resources:ClassKey, ResourceKey%>的形式直接写在HTML中。在本例中,你可以不用编写任何代码,直接将HTML改成如下的形式即可。

   1: <body>
   2:     <form id="form1" runat="server">
   3:     <div>
   4:         <asp:Label id="LabelGreeting4NewYear" runat="server" Text="<%$ Resources:GreetingMessages, Greeting4NewYear%>" />
   5:         <br/>
   6:         <asp:Label id="LabelGreeting4Chris" runat="server" Text="<%$ Resources:GreetingMessages, Greeting4Chris%>" />
   7:     </div>
   8:     </form>
   9: </body>

五、LocalResource编程

上面演示了读取或者绑定Global Resource的编程方式,现在来看看Local Resource。Local Resource,顾名思义,就是每个.aspx页面对应一个独自使用的资源文件。按照如上图所示的结构,我为Default.aspx添加了三个本地资源文件:Default.aspx.xml、Default.aspx.zh-CN.xml和Default.aspx.en-US.xml。

由于Local Resource中的资源条没有自动和页面中某个控件的某个属性进行绑定。在本例中,我们希望资源文本自定义绑定到两个Label的Text属性上,所以我们需要在ResourceKey中加上属性名(Text)后缀,下面是基于英文和中文的内容。

Default.aspx.xml & Default.aspx.en-US.xml

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <resources>
   3:   <add name="Greeting4Chris.Text" value="Merry Christmas!" />
   4:   <add name="Greeting4NewYear.Text" value="Happy Chinese New Year!" />
   5: </resources>

Default.aspx.zh-CN.xml

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <resources>
   3:   <add name="Greeting4Chris.Text" value="圣诞快乐!" />
   4:   <add name="Greeting4NewYear.Text" value="新年快乐!" />
   5: </resources>

那么资源的绑定通过meta:resourcekey=”…” 直接写在定义控件的HTML中即可。所以我们的Default.aspx可以进行如下的改写,便从基于Global Resource的绑定转变成针对Local Resource的绑定。

   1: <body>
   2:     <form id="form1" runat="server">
   3:     <div>
   4:         <asp:Label id="LabelGreeting4NewYear" runat="server" meta:resourcekey="Greeting4NewYear" />
   5:         <br/>
   6:         <asp:Label id="LabelGreeting4Chris" runat="server" meta:resourcekey="Greeting4Chris" />
   7:     </div>
   8:     </form>
   9: </body>

实际上,我们也可以通过代码的方式获取本地资源,我们只需要调用Page的GetLocalResourceObject方法即可。上面针对本地资源的绑定与下面的代码是等效的。

   1: protected void Page_Load(object sender, EventArgs e)
   2: {
   3:     this.LabelGreeting4NewYear.Text = this.GetLocalResourceObject ("Greeting4NewYear.Text").ToString();
   4:     this.LabelGreeting4Chris.Text = this.GetLocalResourceObject("Greeting4Chris.Text").ToString();
   5: }

 

.NET的资源并不限于.resx文件,你可以采用任意存储形式[上篇]
.NET的资源并不限于.resx文件,你可以采用任意存储形式[下篇]
如何在ASP.NET应用中使用自定义资源存储形式


作者:蒋金楠
微信公众账号:大内老A
微博: www.weibo.com/artech
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号 蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
相关文章
|
2月前
|
存储 JSON 开发工具
Visual Studio编程效率提升技巧集(提高.NET编程效率)
Visual Studio编程效率提升技巧集(提高.NET编程效率)
Visual Studio编程效率提升技巧集(提高.NET编程效率)
|
3天前
|
开发框架 前端开发 .NET
究竟是什么让.NET 开发者社区拥有如此强大的力量?资源、分享还是成长的秘密?
【8月更文挑战第28天】.NET开发者社区为成员提供了丰富的资源、积极的分享氛围和广阔的成长空间,是一个充满活力的知识宝库。在这里,从前沿的开源项目到深入的技术解析应有尽有,无论你是新手还是专家,都能找到适合自己的学习与交流机会,共同推动.NET技术的发展。
15 5
|
3天前
|
大数据 开发工具 开发者
从零到英雄:.NET核心技术带你踏上编程之旅,构建首个应用,开启你的数字世界探险!
【8月更文挑战第28天】本文带领读者从零开始,使用强大的.NET平台搭建首个控制台应用。无论你是新手还是希望扩展技能的开发者,都能通过本文逐步掌握.NET的核心技术。从环境搭建到创建项目,再到编写和运行代码,详细步骤助你轻松上手。通过计算两数之和的小项目,你不仅能快速入门,还能为未来开发更复杂的应用奠定基础。希望本文为你的.NET学习之旅开启新篇章!
12 1
|
27天前
|
存储 C#
揭秘C#.Net编程秘宝:结构体类型Struct,让你的数据结构秒变高效战斗机,编程界的新星就是你!
【8月更文挑战第4天】在C#编程中,结构体(`struct`)是一种整合多种数据类型的复合数据类型。与类不同,结构体是值类型,意味着数据被直接复制而非引用。这使其适合表示小型、固定的数据结构如点坐标。结构体默认私有成员且不可变,除非明确指定。通过`struct`关键字定义,可以包含字段、构造函数及方法。例如,定义一个表示二维点的结构体,并实现计算距离原点的方法。使用时如同普通类型,可通过实例化并调用其成员。设计时推荐保持结构体不可变以避免副作用,并注意装箱拆箱可能导致的性能影响。掌握结构体有助于构建高效的应用程序。
46 7
|
3天前
|
传感器 数据采集 物联网
探索未来:.NET nanoFramework引领嵌入式设备编程革新之旅
【8月更文挑战第28天】.NET nanoFramework 是一款专为资源受限的嵌入式设备设计的轻量级、高性能框架,基于 .NET Core,采用 C# 进行开发,简化了传统底层硬件操作的复杂性,极大提升了开发效率。开发者可通过 Visual Studio 或 Visual Studio Code 快速搭建环境并创建项目,利用丰富的库和驱动程序轻松实现从基础 LED 控制到网络通信等多种功能,显著降低了嵌入式开发的门槛。
13 0
|
3月前
|
存储 分布式计算 大数据
MaxCompute操作报错合集之自定义udf的函数,引用了import net.sourceforge.pinyin4j.PinyinHelper;但是上传资源后,出现报错,是什么原因
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
|
4月前
|
JSON 编解码 Go
Golang深入浅出之-HTTP客户端编程:使用net/http包发起请求
【4月更文挑战第25天】Go语言`net/http`包提供HTTP客户端和服务器功能,简化高性能网络应用开发。本文探讨如何发起HTTP请求,常见问题及解决策略。示例展示GET和POST请求的实现。注意响应体关闭、错误处理、内容类型设置、超时管理和并发控制。最佳实践包括重用`http.Client`,使用`context.Context`,处理JSON以及记录错误日志。通过实践这些技巧,提升HTTP编程技能。
53 1
|
4月前
|
Go 开发者
Golang深入浅出之-HTTP客户端编程:使用net/http包发起请求
【4月更文挑战第24天】Go语言的`net/http`包在HTTP客户端编程中扮演重要角色,但使用时需注意几个常见问题:1) 检查HTTP状态码以确保请求成功;2) 记得关闭响应体以防止资源泄漏;3) 设置超时限制,避免长时间等待;4) 根据需求处理重定向。理解这些细节能提升HTTP客户端编程的效率和质量。
48 1
|
4月前
|
开发框架 .NET Java
ASP.NET Core高级编程--C#基本特性(一)
本文章简略介绍C#的部分特性
|
4月前
|
人工智能 机器人 C#
Windows编程课设(C#)——基于WPF和.net的即时通讯系统(仿微信)
一款参考QQ、微信的即时通讯软件。采用CS结构,客户端基于.Net与WPF开发,服务端使用Java开发。