Duwamish代码分析篇
Duwamish代码分析篇
Written by: Rickie Lee
Nov. 02, 2004
继续前面的2篇POST《Duwamish架构分析篇》和《Duwamish部署方案篇》,这里在代码层次上分析Duwamish 7.0范例,主要目的是解析Duwamish范例中值得推荐的编码风格和提炼出可以重用的代码或Class。
1,读取配置文件类-SystemFramework\ApplicationConfiguration.cs
ApplicationConfiguration类用来读取web.config文件中自定义section的配置信息,初始化一些基本设置。
ApplicationConfiguration类实现IconfigurationSectionHandler接口,并需要实现[C#]
object Create(
object parent,
object configContext,
XmlNode section
)方法,以分析配置节的 XML。返回的对象被添加到配置集合中,并通过 GetConfig 访问。
部分代码片断解释:
(1)Code Snippet 1 – ApplicationConfiguration. OnApplicationStart()方法
public static void OnApplicationStart(String myAppPath)
{
appRoot = myAppPath;
System.Configuration.ConfigurationSettings.GetConfig("ApplicationConfiguration");
System.Configuration.ConfigurationSettings.GetConfig("DuwamishConfiguration");
System.Configuration.ConfigurationSettings.GetConfig("SourceViewer");
}
ConfigurationSettings 类还提供了一个公共方法ConfigurationSettings.GetConfig() 用于返回用户定义的配置节的配置设置,传入的参数section name,如"ApplicationConfiguration",表示要读取的配置节。
NameValueCollection nv=new NameValueCollection();
//实例化NameValueCollection 类对象
nv=(NameValueCollection)ConfigurationSettings.GetConfig("ApplicationConfiguration ");
//返回用户定义的配置节的设置
return nv["SystemFramework.Tracing.Enabled"].ToString();
//返回特定键值,如SystemFramework.Tracing.Enabled
不过,ConfigurationSettings.GetConfig()方法在调用时,自动调用Create()方法,可以看到ApplicationConfiguration.Create()方法正是用来读取指定section的配置,并初始化设置参数。
Global.asax 的 Application_OnStart 事件处理程序向 SystemFramework 的ApplicationConfiguration 类 OnApplicationStart 方法发出调用,正是上述的代码片断。
(2)Code Snippet 2 - Global.asax中Application_OnStart()方法
void Application_OnStart()
{
ApplicationConfiguration.OnApplicationStart(Context.Server.MapPath( Context.Request.ApplicationPath ));
string configPath = Path.Combine(Context.Server.MapPath( Context.Request.ApplicationPath ),"remotingclient.cfg");
if(File.Exists(configPath))
RemotingConfiguration.Configure(configPath);
}
该方法肩负二大任务:(1)调用ApplicationConfiguration.OnApplicationStart()方法,并传入application的根目录(Root Directory)。(2)检测Client端的remoting配置文件是否存在(其实是web server端),如果存在,则读取并初始化remoting配置信息,如配置通道Channel等等,详见《Duwamish部署方案篇》。
2,读取web.config中Duwamish相关的一些配置-Common\DuwamishConfiguration.cs
Common\DuwamishConfiguration.cs也实现IconfigurationSectionHandler接口,与SystemFramework\ApplicationConfiguration.cs类相似。
DuwamishConfiguration配置节包括如下一些配置信息:
Database connection string(Database连接串)Duwamish.DataAccess.ConnectionString,是否允许页面缓存Duwamish.Web.EnablePageCache,页面缓存过期时间Duwamish.Web.PageCacheExpiresInSeconds,是否允许SSL连接Duwamish.Web.EnableSsl等等。
如上所述,调用DuwamishConfiguration Class 是由SystemFramework\ApplicationConfiguration.cs的OnApplicationStart()方法完成的:
System.Configuration.ConfigurationSettings.GetConfig("DuwamishConfiguration");
看看页面缓存配置在web page中如何使用的(web\book.aspx.cs文件为例):
//
// If everything succeeded, then enable page caching as indicated
// by the current application configuration.
//
if ( DuwamishConfiguration.EnablePageCache )
{
//Enable Page Caching...
Response.Cache.SetExpires ( DateTime.Now.AddSeconds(DuwamishConfiguration.PageCacheExpiresInSeconds));
Response.Cache.SetCacheability(HttpCacheability.Public);
}
在Page_Load事件中最后判断是否允许页面缓存。
3,验证数据合法性类-SystemFramework\ApplicationAssert.cs
SystemFramework\ApplicationAssert.cs Class用来进行错误检测,并调用SystemFramework\ApplicationLog.cs Class记录错误日志。
学习其中的部分代码片断:
(1)Code Snippet 1 – Check Method
[ConditionalAttribute("DEBUG")]
public static void Check(bool condition, String errorText, int lineNumber)
{
if ( !condition )
{
String detailMessage = String.Empty;
StringBuilder strBuilder;
GenerateStackTrace(lineNumber, out detailMessage);
strBuilder = new StringBuilder();
strBuilder.Append("Assert: ").Append("\r\n").Append(errorText).Append("\r\n").Append(detailMessage);
ApplicationLog.WriteWarning(strBuilder.ToString());
System.Diagnostics.Debug.Fail(errorText, detailMessage);
}
}
[ConditionalAttribute("DEBUG")]定义Check()方法为conditional method,如果预处理符号(preprocessor symbol)没有定义,compiler不仅忽略该方法,而且忽略对该方法的调用,和#if DEBUG / #else / #endif有些类似。
该方法用来判断条件condition是否为true,如果为false,则调用SystemFramework\ApplicationLog.WriteWarning()方法记录错误日志。
(2)Code Snippet 2 – CheckCondition Method
public static void CheckCondition(bool condition, String errorText, int lineNumber)
{
//Test the condition
if ( !condition )
{
//Assert and throw if the condition is not met
String detailMessage;
GenerateStackTrace(lineNumber, out detailMessage);
Debug.Fail(errorText, detailMessage);
throw new ApplicationException(errorText);
}
}
该方法一般用来在进行前置条件判断,如condition为false,则抛出exception。
4,log日志类-SystemFramework\ApplicationLog.cs
ApplicationLog 类实现 Duwamish 7.0 中的记录和跟踪。Web.Config 文件中的配置设置确定是输出到 EventLog 文件、跟踪日志文件还是两者。下面是 Web.Config 文件中的 <ApplicationConfiguration> 节,它指定 EventLog 设置:
<ApplicationConfiguration>
<!-- Event log settings -->
<add key="SystemFramework.EventLog.Enabled" value="True" />
<add key="SystemFramework.EventLog.Machine" value="." />
<add key="SystemFramework.EventLog.SourceName" value="Duwamish7" />
<add key="SystemFramework.EventLog.LogLevel" value="1" />
<!-- Use the standard TraceLevel values:
0 = Off
1 = Error
2 = Warning
3 = Info
4 = Verbose -->
Web.Config 文件的同一节还指定跟踪配置。Duwamish 7.0 跟踪日志的默认位置是:[安装 Visual Studio .NET 的驱动器号]:\Program Files\Microsoft Visual Studio .NET 2003\Enterprise Samples\Duwamish 7.0 CS\Web\DuwamishTrace.txt
在实际的应用系统开发中,用来提供Log功能的类应该比这个ApplicationLog类要好,这样就不去分析了,如Microsoft Exception Management Application Block就不错。
5,Web.config配置文件-使用Web.congfig文件存储application设置
Duwamish 7.0 通过使用 Forms 身份验证来实现安全性。Forms 身份验证将未经授权的用户重定向到Web 窗体,该窗体提示用户输入其电子邮件地址和密码。
(1)配置 Forms 身份验证
Web.config 文件中的设置配置 Forms 身份验证。对于 Duwamish 7.0,Web.Config 文件按如下所述指定 Forms 身份验证的使用:
<authentication mode="Forms">
<forms name=".ADUAUTH" loginUrl="secure\logon.aspx" protection="All">
</forms>
</authentication>
<authorization>
<allow users="*" />
</authorization>
authentication元素只能在计算机、站点或应用程序级别声明。如果试图在配置文件中的子目录或页级别上进行声明,则将产生分析器错误信息。
如上所示,Web.Config 将 .ADUAUTH 指定为身份验证 Cookie 的名称。当用户请求受限资源时,公共语言运行库将未经授权的用户重定向到在上面的 Web.Config 设置中指定的Login.aspx。protection="All" 设置指定应用程序使用数据验证和加密来保护 Cookie。若要进一步限制资源,Duwamish 7.0 会将安全资源放置到名为 secure 的子文件夹中并使用额外的 Web.Config 文件(在secure文件夹),在该文件中指定只有经过身份验证的用户才可访问该子文件夹的内容。
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
<deny users="?" /> 标记指定拒绝对所有匿名用户的访问。<allow users="*" /> 标签允许访问所有已验证身份的用户。
经过secure\logon.aspx认证通过的请求,重新定向最初的URL。
// 将已验证身份的用户重定向回最初请求的 URL。
FormsAuthentication.RedirectFromLoginPage("*", false);
(2)用户定义的配置节
<configSections>
<section name="ApplicationConfiguration" type="Duwamish7.SystemFramework.ApplicationConfiguration, Duwamish7.SystemFramework" />
<section name="DuwamishConfiguration" type="Duwamish7.Common.DuwamishConfiguration, Duwamish7.Common" />
<section name="SourceViewer" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</configSections>
section元素包含配置节声明,name 指定配置节的名称,type 指定从配置文件中读取节的配置节处理程序类的名称。配置节处理程序(即实现 IConfigurationSectionHandler 接口的类)读取设置。
上面定义了3个配置节处理程序:Duwamish7.SystemFramework.ApplicationConfiguration
Duwamish7.Common.DuwamishConfiguration
System.Configuration.NameValueSectionHandler
前面两个配置节处理程序是由application提供的,后面的System.Configuration.NameValueSectionHandler是.Net Framework提供的,该类也实现了IconfigurationSectionHandler接口,用来提供配置节中的名称/值对配置信息。
6,web\PageBase.cs基类
最后谈谈web\PageBase.cs基类吧,所有 Duwamish 7.0 中的所有web页都继承名为 PageBase 的基类,该类实现 Duwamish 7.0 应用程序的 ASP.Net 页中使用的常见属性和方法,这种设计方法值得推荐。
Code Snippet分析:
/// <summary>
/// Handles errors that may be encountered when displaying this page.
/// <param name="e">An EventArgs that contains the event data.</param>
/// </summary>
protected override void OnError(EventArgs e)
{
ApplicationLog.WriteError(ApplicationLog.FormatException(Server.GetLastError(), UNHANDLED_EXCEPTION));
base.OnError(e);
}
重载OnError方法,使application遭遇到未处理错误的时候,自动调用ApplicationLog.WriteError()来记录错误日志。
另外,觉得Duwamish的password处理有些特别,是以byte形式存放在Database中,避免明文的方式,以提高安全性(将在《Duwamish密码分析篇》进行中分析)。
Reference:
1, MSDN, Duwamish 7.0
2, Rickie, Duwamish架构分析篇
3, Rickie, Duwamish部署方案篇