所谓Application Block,就是像搭积木一样将做好的模块拼凑起来,做成一个应用程序。当然这是理想状态,一般来说做不到100%的拼凑就可以成型的项目。那微软就做了这么一些小积木,供我们可以在自己的程序中经过配置后方便的使用。换句通俗的话说,Application Block就是一些可复用性很强的组件。
这里要讲的就是Exception Management Application Block,它要做到的简单点说就是将异常的处理最简单化,而且作为Application Block它的通用性与扩展性要非常强。那它是怎么做的呢?我就不讲解了,因为它的帮助文档已经很详细了,同样它的使用方法以及如何扩展都在文档中很好的介绍了,并且有示例,感兴趣的朋友可以在微软的网站上下载到(http://download.microsoft.com/)。简单的来说就是配置一些配置文件,然后在你的catch中调用ExceptionManager.Publish(Exception ex)将异常公布出去就可以了,根据你的配置文件,一个到多个公布者(Publisher)会将异常按照它们的方法处理掉(纪录下来)。
这里我提一下示例中的一个Bug,以及如何改进一下示例中的ExceptionPublisher以及ExceptionXMLPublisher来自己使用。示例中将异常写入到文件那一块有这么一段代码:
// Write the entry to the log file.
using ( FileStream fs = File.Open(m_LogName,
FileMode.Create,FileAccess.ReadWrite))
{
using (StreamWriter sw = new StreamWriter(fs))
{
sw.Write(strInfo.ToString());
}
}
问题很明显,如果只用FileMode.Create,那么下次在有异常需要纪录的话就不会被写入文件。这作为一个IExceptionPublisher绝对是个bug。还好我们有源代码,只要将这个线程的ExceptionPublisher改一下我们就可以将它拿来用了,另外我们还要对它加入一个必要的功能,那就是我们不能让日志文件无限的增长,我们必须设定一下界限,让它在达到界限时自动删掉以前的日志并再建一个新的出来。所以我们有了以下代码:
using System;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using Microsoft.ApplicationBlocks.ExceptionManagement;
namespace Microsoft.ApplicationBlocks.ExceptionManagement {
/// <summary>
/// Publishes exceptions to system file.
/// </summary>
public class FilePublisher : IExceptionPublisher {
private string m_LogName = AppDomain.CurrentDomain.BaseDirectory + @"\ErrorLog.txt";
private long _maxFileSize = 1024 * 1024; // Default to 1MB.
/// <summary>
/// Create a new instance.
/// </summary>
public FilePublisher() {}
// Provide implementation of the IPublishException interface
// This contains the single Publish method.
void IExceptionPublisher.Publish(Exception exception, NameValueCollection additionalInfo, NameValueCollection configSettings) {
// Load Config values if they are provided.
if (configSettings != null) {
if (configSettings["fileName"] != null &&
configSettings["fileName"].Length > 0) {
m_LogName = configSettings["fileName"];
}
if (configSettings["maxFileSize"] != null && configSettings["maxFileSize"].Length > 0) {
try {
_maxFileSize = long.Parse(configSettings["maxFileSize"]);
} catch {}
}
}
// Create StringBuilder to maintain publishing information.
StringBuilder strInfo = new StringBuilder();
// Record the contents of the AdditionalInfo collection.
if (additionalInfo != null) {
// Record General information.
strInfo.AppendFormat("{0}General Information{0}", Environment.NewLine);
strInfo.AppendFormat("{0}Additonal Info:", Environment.NewLine);
foreach (string i in additionalInfo) {
strInfo.AppendFormat("{0}{1}: {2}", Environment.NewLine, i, additionalInfo.Get(i));
}
}
// Append the exception text
strInfo.AppendFormat("{0}{0}Exception Information{0}{1}", Environment.NewLine, exception.ToString());
// Delete log file if is bigger than 1MB.
FileInfo logInfo = new FileInfo(m_LogName);
if (logInfo.Length > _maxFileSize) {
logInfo.Delete();
}
// Write the entry to the log file.
using (StreamWriter sw = new StreamWriter(m_LogName, true, Encoding.UTF8)) {
sw.Write(strInfo.ToString());
}
}
}
}
这段代码在ExceptionPublisher的基础上做了一些修改,改掉了bug,并且通过在配置文件中设定maxFileSize来限定日志的最大大小。当然读者喜欢,可以将maxFileSize的配置方法加以改变,比如我这里是以byte为单位,但实际应用中可能以KB为单位要好点。
这类异常管理方面的Application Block很实用,因为如果没有它的话我们在自己的项目中还是要自己写一套来做异常管理,只不过不一定是通用的,并且不一定是这么强大的。