使用XML序列化创建一个留言簿






4.60/5 (11投票s)
本文介绍了一种使用 ASP.NET 和 XML 序列化创建留言簿的简便方法。
引言
本文介绍了一种使用 ASP.NET 和 XML 序列化构建留言簿的简便方法。该留言簿是一个简单的“后进后出”日志,条目数量限制为 20 条。当提交第 21 条条目时,列表中的第一条将被删除。为了格式化数据,我使用了 Visual Studio .NET 自带的 DataList
控件。本文旨在演示以下技术:
- ASP.NET Web Forms
DataList
控件- 对象的 XML 序列化
- Generics
留言簿应在 Visual Studio 2005 或 2008 中创建一个网站项目。以下是完成后的留言簿外观:
代码
GuestBookEntry 类
首先,我们将创建一个名为 GuestBookEntry
的新类文件。该类将包含留言簿条目的代码。稍后,GuestBookEntry
对象的数组将被序列化为 XML 并存储在服务器上。
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
/// <summary>
/// The class containing data and funtionality for one
/// guest book entry.
/// </summary>
public class GuestBookEntry
{
public string Message;
public string Name;
public DateTime Date;
public string IPAddress;
/// <summary>
/// Public parameterless constructor required by XML serialization.
/// </summary>
public GuestBookEntry()
{
}
public GuestBookEntry(string message, string name, DateTime date, string ipAddress)
{
this.Message = message;
this.Name = name;
this.Date = date;
this.IPAddress = ipAddress;
}
public override string ToString()
{
return "<b>" + Message + "</b><br>" + "Name: <b>"
+ Name + "</b><br>" + "Date: " + Date.ToString();
}
}
请注意对 ToString()
方法的重写。在 .NET 中,每个类都继承自 Object
,因此继承了多个方法的实现。其中一个方法是 ToString()
,它返回一个代表当前对象的字符串。但是,默认实现并不是很有用。如果您不重写 ToString()
,调用它将返回类名。
在此实现中,我们重写了 ToString()
以获得 GuestBookEntry
对象的 HTML 表示形式。我们还为每个条目存储了提交者的 IP 地址。此信息未在留言簿中显示,但可用于在留言簿被篡改时阻止特定地址。
GuestBookHandler 类
我们将创建的第二个类是 GuestBookHandler
。该类的主要职责是将留言簿以 XML 格式存储到服务器。该类还负责将条目数量限制为 20 条,并将文本编码为 HTML(将换行符替换为 <br />)。
该类包含以下代码:
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
using System.Web.Hosting;
/// <summary>
/// The GuestBook handler will take care
/// of serializing the GuestBookEntry objects
/// to XML and storing it to the server.
/// </summary>
public class GuestBookHandler
{
private List<GuestBookEntry> entrys = new List<GuestBookEntry>();
private const string fileName = "~\\App_Data\\GuestBook.xml";
// Configurable number of entries in the log.
private const int maxNumberOfEntries = 20;
// Static object used for locking critical section.
private static object writeLock = new object();
public GuestBookHandler()
{
Load(); // Read data from XML file.
}
// Returns array of Guestbook entries to presentation layer.
public GuestBookEntry[] Entrys {
get { return entrys.ToArray(); }
}
// Method to add a guestbook entry.
public void Add(string message, string name, DateTime date, string ipAddress)
{
if (entrys.Count >= maxNumberOfEntries) {
entrys.RemoveAt(0); // Remove first entry.
}
// Add new entry.
GuestBookEntry ge = new GuestBookEntry(message.Replace(Environment.NewLine,
"<br />"),
name, date, ipAddress);
entrys.Add(ge);
}
public void Save()
{
// Use shared lock to assure only one user at a time
// has access to the file for writing.
lock(writeLock) {
// Create a new XmlSerializer instance with the type of the test class
XmlSerializer serializerObj = new XmlSerializer(entrys.GetType());
// Create a new file stream to write the serialized object to a file
StreamWriter writeFileStream = null;
try {
string mappedPath = HostingEnvironment.MapPath(fileName);
writeFileStream = new StreamWriter(mappedPath);
serializerObj.Serialize(writeFileStream, entrys);
writeFileStream.Flush();
}
finally {
// Cleanup
if (writeFileStream != null) {
writeFileStream.Close();
}
}
}
}
private void Load()
{
// Create an instance of the XmlSerializer specifying type and namespace.
XmlSerializer serializer = new XmlSerializer(typeof(List<GuestBookEntry>));
// A FileStream is needed to read the XML document.
FileStream fs = null;
try {
try {
fs = new FileStream(HostingEnvironment.MapPath(fileName), FileMode.Open);
}
catch (System.IO.FileNotFoundException) {
// No entrys to load.
return;
}
XmlReader reader = XmlReader.Create(fs);
// Use the Deserialize method to restore the object's state.
entrys = (List<GuestBookEntry>)serializer.Deserialize(reader);
}
finally {
if (fs != null) {
fs.Close();
}
}
}
}
请注意源代码中使用泛型列表:List<GuestBookEntry>
。
泛型是 .NET 2.0 引入的一项新功能,它在编译时提供了类型安全性。泛型允许您创建数据结构,而不必在设计时将代码指定为特定数据类型。在编译时,编译器会确保与数据结构一起使用的数据类型符合类型安全。换句话说,泛型在不损失性能或代码臃肿的情况下提供了类型安全。泛型类似于 C++ 中的模板,尽管实现方式大不相同。
GuestBookHandler
类还使用 XML 序列化将数据存储到服务器。序列化是将对象持久化到磁盘的过程。另一个应用程序可以反序列化您的对象,它将处于序列化之前的状态。本教程使用 XML 序列化。包含适用于此类序列化的类和方法的命名空间是 System.Xml.Serialization
。
为了序列化一个对象,我们首先创建一个 XmlSerializer
对象。我们还创建一个将写入或读取文件的流。然后,调用适当的序列化方法,将您创建的流对象传递进去。要反序列化您创建的 XML 序列化对象,只需调用 Deserialize
方法,将从 XML 文档读取的流传递进去。最后一步是将对象强制转换为正确的类型。
与标准序列化技术相比,XML 提供了以下优势:
- 互操作性更强:XML 是一种基于文本文件的格式,所有现代操作系统和开发环境都包含处理此类文件的库。
- 对管理员友好:通过以 XML 格式存储对象,管理员有机会查看和编辑 XML 文件。因此,管理员可以轻松修改您的对象或排除故障。
- 更好的前向兼容性:XML 序列化的对象是自描述的。当您需要用新版本替换应用程序时,过渡将非常顺利。
GuestBook.aspx 文件
GuestBook.aspx 文件包含以下 HTML 代码:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="GuestBook.aspx.cs"
Inherits="GuestBook" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h1>
Simple Guestbook</h1>
<asp:DataList ID="DataList1" runat="server" CellPadding="4"
ForeColor="#333333" Width="100%">
<ItemTemplate>
<%# Container.DataItem %>
</ItemTemplate>
<FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
<AlternatingItemStyle BackColor="White" />
<ItemStyle BackColor="#EFF3FB" />
<SelectedItemStyle BackColor="#D1DDF1" Font-Bold="True"
ForeColor="#333333" />
<HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
</asp:DataList><br />
</div>
Message<br />
<asp:TextBox ID="txtMessage" runat="server" Height="75px" Width="301px"
TextMode="MultiLine"></asp:TextBox><br />
<br />
Name<br />
<asp:TextBox ID="txtName" runat="server" Width="138px"></asp:TextBox>
<br />
<br />
<asp:Button ID="butSubmit" runat="server" Text="Submit" OnClick="butSubmit_Click" />
</form>
</body>
</html>
请注意 DataList
标记下的以下代码。
<asp:DataList ID="DataList1" runat="server" CellPadding="4" Width="305px">
<ItemTemplate>
<%# Container.DataItem %>
</ItemTemplate>
</asp:DataList>
<%# %>
表示这是一个数据绑定表达式,Container.DataItem
是数据源中当前项的别名。换句话说,当我们将数据绑定到对象集合时,Container.DataItem
就是该集合中的当前行。
代码隐藏:Guestbook.aspx.cs
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
public partial class GuestBook : System.Web.UI.Page
{
private GuestBookHandler guestBookHandler;
protected void Page_Load(object sender, EventArgs e)
{
guestBookHandler = new GuestBookHandler();
BindData();
}
protected void butSubmit_Click(object sender, EventArgs e)
{
if (txtMessage.Text != "" && txtName.Text != "") {
guestBookHandler = new GuestBookHandler();
guestBookHandler.Add(txtMessage.Text,
txtName.Text, DateTime.UtcNow,
HttpContext.Current.Request.UserHostAddress);
guestBookHandler.Save();
txtMessage.Text = "";
txtName.Text = "";
// Re-bind data since the data has changed.
BindData();
}
}
private void BindData()
{
DataList1.DataSource = guestBookHandler.Entrys;
DataList1.DataBind();
}
}
结论
如您所见,在 .NET 中创建一个留言簿并非难事。此留言簿基于 XML 序列化,是一个“后进后出”的留言簿。它可以作为开发您自己具有更高级功能的留言簿的基础代码。稍作修改,此留言簿也可以实现“先进先出”的功能。欢迎所有评论和改进建议。
历史
- 2008年11月22日:文章首次发布。
- 2009年1月14日:更新以支持输入中的换行符并改进了错误处理。