Duwamish深入剖析

结构篇

摘要:
  
  本文深入详细的介绍了Duwamish网上电子书店例程的结构框架,并详细的分析了该结构的若干特点和设计模式。
  
  
  --------------------------------------------------------------------------------
  
  目录:
  
  引言
  
  Duwamish介绍
  
  结构分析
  
  设计思想
  
  代码示例
  
  总结
  
  作者
  
  
  --------------------------------------------------------------------------------
  
  引言:
  
  能够作为Visual Studio .Net附带的例子,Duwamish一定包含了微软.Net设计队伍希望向开发者传达的某些信息,而事实上,Duwamish也的确能够称作是一个.Net开发者学习的经典示例,无论是从其设计架构,编程技巧或代码风格,都向我们展示了一个标准的.Net企业级应用程序所应该具有的特点。所以,通过研究Duwamish示例,高手能够领悟到.Net应用架构的设计思想,低手能够学习到.Net的编程技巧,实在是老少皆宜。 :)
  
  不过,本文的目的更多的是针对中级.Net学习者,这类读者往往已经熟悉了C#或者是VB.NET的语法,会用一些基本的类库,并已经会做一些比较小的程序。但是当他们开始着手开发一个真正具有实用价值的企业级应用的时候,却有种无处下手的感觉。如果你正巧属于这类学习者,请跟着我深入到Duwamish的世界中去,相信你一定会得到收获。
  
  
  --------------------------------------------------------------------------------
  
  Duwamish介绍:
  
  Microsoft公司每次推出新技术,总是会相应的推出一些公开源代码的应用范例来说明该项新技术的特点,而开发者也能通过研究该范例的代码来达到迅速掌握新技术并与以实施的目的。Microsoft通过对一个虚拟的在网上销售图书的电子商务公司网上销售系统应用的创建,向用户展现了典型的网上购物实践中最为普遍的电子商务企业对客户 (B2C) 模式,它包括成员资格、帐户管理、购物车、搜索和结帐过程等基本功能。Duwamish经历了三个版本4.0,5.0和7.0版,每一个版本的发布都印证了技术进步的过程,每一个版本都代表了当时最先进的技术动向。这里将要研究和讨论的是Duwamish的最高版本7.0版,经历了COM/COM+技术以及Microsoft DNA架构的Duwamish,在最新的版本中完全采用了.Net技术及架构,比以前显得更加先进和成熟。
  
  
  
  
  如果您安装了Visual Studio .Net的话,您可以在您的VS.Net 的Enterprise Samples目录下找到并安装它,例如:C:\Program Files\Microsoft Visual Studio .NET\Enterprise Samples\,或者您还可以到http://astradigital.com/Duwamish7Vb/这个地址去看看它在Internet的一个演示实例。其它有关Duwamish的详细介绍资料请参考Visual Studio .Net附带的MSDN帮助,地址是:ms-help://MS.VSCC/MS.MSDNVS.2052/dwamish7/html/vtoriDuwamishBooks70.htm,这里不再赘述。
  
  
  --------------------------------------------------------------------------------
  
  Duwamish结构分析:
  
  Duwamish 7.0 是一个典型的N层架构,其结构分为四个逻辑层:
  
  Web 层
  
  Web 层为客户端提供对应用程序的访问。这一层是作为 Duwamish.sln 解决方案文件中的 Web 项目实现的。Web 层由 ASP.NET Web 窗体和代码隐藏文件组成。Web 窗体只是用 HTML 提供用户操作,而代码隐藏文件实现各种控件的事件处理。
  
  业务外观层
  
  业务外观层为 Web 层提供处理帐户、类别浏览和购书的界面。这一层是作为 Duwamish.sln 解决方案文件中的 BusinessFacade 项目实现的。业务外观层用作隔离层,它将用户界面与各种业务功能的实现隔离开来。除了低级系统和支持功能之外,对数据库服务器的所有调用都是通过此程序集进行的。
  
  业务规则层
  
  业务规则层是作为 Duwamish.sln 解决方案文件中的 BusinessRules 项目实现的,它包含各种业务规则和逻辑的实现。业务规则完成如客户帐户和书籍订单的验证这样的任务。
  
  数据访问层
  
  数据访问层为业务规则层提供数据服务。这一层是作为 Duwamish.sln 解决方案文件中的 DataAccess 项目实现的。
  
  比较令人困惑的是其中的业务外观层和业务规则层,很多人在学习N层结构开发的时候,听得最多的是三层结构,分别为:表示层,中间层和数据层。Duwamish的WEB层和数据访问层比较好理解,也就是传统意义上的表示层和数据层,那么业务外观层和业务规则层和我们熟悉的中间层有什么联系呢?
  
  
  --------------------------------------------------------------------------------
  
  设计思想:
  
  在Web应用程序中,有部分操作只是简单的从数据库根据条件提取数据,不需要经过任何处理,而直接将数据显示到网页上,比如查询某类别的图书列表。而另外一些操作,比如计算定单中图书的总价并根据顾客的级别计算回扣等等,这部分往往有许多不同的功能的类,操作起来也比较复杂。我们可以先想象一下,如果我们采用三层结构,这些商业逻辑一般是会放在中间层,那么对内部的这些大量种类繁多,使用方法也各异的不同的类的调用任务,就完全落到了表示层。这样势必会增加表示层的代码量,将表示层的任务复杂化,和表示层只负责接受用户的输入并返回结果的任务不太相称,并增加了层与层之间的耦合程度。
  
  为了解决这个问题,我们先来看看《设计模式》一文中对Facade模式的描述:
  
  意图:
  
  为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
  
  适用性:
  
  当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过Facade层。
  
  客户程序与抽象类的实现部分之间存在着很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
  
  当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过Facade进行通讯,从而简化了它们之间的依赖关系。
  
  结构图:
  
  
  
  
  上文提出的这个矛盾,正好和设计模式中Facade模式中所描述的需要解决的问题非常吻合,在《设计模式》中提出的解决的办法就是引入一个Facade对象,让这个Façade来负责管理系统内部类的调用,并为表示层提供了一个单一而简单的接口。这个Façade对象,在我们的Duwamish的设计中,就是BusinessFacade(业务外观)层。
  
  以下是Duwamish的结构关系图:
  
  
  
  
  我们从图中可以清楚的看到,浏览器首先调用的是表示层WEB,然后WEB将请求发送给业务外观层,业务外观层对请求进行初步的处理,判断是否需要调用业务规则层,还是直接调用数据访问层获取数据。最后由数据访问层访问数据库并按照来时的步骤返回结果到浏览器(对于图中涉及到其它的结构模块以后会分别予以详细介绍)。
  
  
  --------------------------------------------------------------------------------
  
  代码示例:
  
  以下是两种不同处理路径的代码示例:
  
  获取商品目录
  
  表示层调用业务外观层:
  
  productSystem = new ProductSystem();
  
  categorySet = productSystem.GetCategories(categoryID);
  
  业务外观层直接调用数据层:
  
  public CategoryData GetCategories(int categoryId)
  {
   if ( dsCommand == null )
   {
   throw new System.ObjectDisposedException( GetType().FullName );
   }
   return FillCategoryData("GetCategories", "@CategoryId", categoryId);
  }
  
  添加定单
  
  表示层调用业务外观层:
  
  public void AddOrder()
  {
   ApplicationAssert.CheckCondition(cartOrderData != null, "Order requires data", ApplicationAssert.LineNumber);
   ApplicationLog.WriteTrace("Duwamish7.Web.Cart.AddOrder:\r\nCustomerId: " +
   cartOrderData.Tables[OrderData.CUSTOMER_TABLE].Rows[0][OrderData.PKID_FIELD].ToString());
   cartOrderData = (new OrderSystem()).AddOrder(cartOrderData);
  }
  
  业务外观层调用业务规则层:
  
  public OrderData AddOrder(OrderData order)
  {
   ApplicationAssert.CheckCondition(order != null, "Order is required", ApplicationAssert.LineNumber);
  
   (new BusinessRules.Order()).InsertOrder(order);
   return order;
  }
  
  业务规则层调用数据层:
  
  public bool InsertOrder(OrderData order)
  {
   //此处省略复杂的处理逻辑
   if ( isValid )
   {
   using (DataAccess.Orders ordersDataAccess = new DataAccess.Orders())
   {
   return (ordersDataAccess.InsertOrderDetail(order)) > 0;
   }
   }
   else
   return false;
  }
  
  
  --------------------------------------------------------------------------------
  
  总结:
  
  通过分析Duwamish7的结构设计,我们掌握了Façade模式,并学习到了如何通过Façade模式对应用结构进行改进,同时了解了Duwamish7的基本概念和处理流程,为以后深入分析和学习Duwamish7的的其它部分打下了一个基础。
 

配置篇

摘要:
  
  本文详细介绍了Duwamish网上电子书店的Web.config配置文件的结构处理方式以及用途,阐述了配置文件的各功能模块中的作用。
  
  
  --------------------------------------------------------------------------------
  
  目录:
  
  引言
  
  配置节处理程序声明
  
  自定义配置节
  
  配置节处理程序
  
  总结
  
  参考资料
  
  作者
  
  
  --------------------------------------------------------------------------------
  
  引言:
  
  几乎在每本介绍Asp.Net编程的书里,在谈到如何管理数据库连接字符串的时候,都是采用将数据库连接字符串以如下形式放在Web.Config文件中
  
  < appSettings>
  
  < add key="ConnectionString" value="data source=localhost;initial catalog=Database;user id=;password="/>
  
  </appSettings>
  
  然后在程序中采用以下方式访问:
  
  System.Configuration.ConfigurationSettings.AppSettings["ConnectionString"]
  
  这样做的好处非常明显:当数据库有变动的时候,只需要改变web.config中的连接字符串,而不需要重新编译整个应用程序,给应用的部署和移植带来非常大的方便。
  
  如果你以为web.config的作用仅限于此的话,那你就错了,web.config的配置功能非常强大,它可以支持使用自己的 XML 配置标记扩展标准的 ASP.NET 配置设置集,在Duwamish中一定程度上的体现了它的功能,下面我将要详细分析Duwamish的web.config文件,让大家能了解到开发一个典型的.Net WEB应用程序的配置技术。
  
  
  --------------------------------------------------------------------------------
  
  配置节处理程序声明
  
  在Duwamish解决方案中,Web.config文件是放在WEB项目下,因为web.config需要IIS和Asp.Net Runtime的管理和支持,所以它应该放在一个虚拟目录下,我们先来看看它的第一部分:
  
  <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.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> </configSections>
  
  这里定义了三个配置节处理程序声明(Section),按照规定它们必须出现在配置文件顶部 <configSections> 和 </configSections> 标记之间,在这里,它们只用到了name和type属性,其中,name属性定义了指定配置节的名称,而type属性则规定了指定从配置文件中读取节的配置节处理程序类的名称,有两个部分,前面为处理程序的类名,后面为Assembly名(Assembly必须位于bin目录中)以及版本号,公匙等信息。
  
  他们具体表示什么意思呢?比如第一个section,意思就是告诉Asp.Net系统,当在程序中使用System.Configuration.ConfigurationSettings.GetConfig("ApplicationConfiguration")这个静态方法来读取ApplicationConfiguration配置节的时候,会调用Duwamish7.SystemFramework.ApplicationConfiguration这个类来对这个配置节进行处理。关于配置节处理类,我们会在后面详细讨论,我们先继续往下看web.config文件。
  
  
  --------------------------------------------------------------------------------
  
  自定义配置节
  
  在<system.web>节点之后,我们可以看见以下的XML元素(关于system.web节点的说明已经有大量文章介绍,这里不再重复):
  
  <ApplicationConfiguration>
   <!-- Trace file settings -->
   <add key="SystemFramework.Tracing.Enabled" value="False" />
   <!-- Set this to the file with the trace settings. This file should be relative
   to the root application directory. -->
   <add key="SystemFramework.Tracing.TraceFile" value="DuwamishTrace.txt" />
   <!-- The TraceLevel for this switch. -->
   <add key="SystemFramework.Tracing.TraceLevel" value="4" />
   <!-- This switch name. The trace level for this name can be set through
   environment variables or the registry -->
   <add key="SystemFramework.Tracing.SwitchName" value="DuwamishTraceSwitch" />
   <!-- This description of the Tracing.SwitchName switch -->
   <add key="SystemFramework.Tracing.SwitchDescription" value="Error and information tracing for Duwamish" />
   <!-- Event log settings
   Note: The default Duwamish7 event source name is created in the local machine during setup. If you wish to log events to a different event source
   that event source must exist.
   -->
   <add key="SystemFramework.EventLog.Enabled" value="True" />
   <add key="SystemFramework.EventLog.Machine" value="." />
   <add key="SystemFramework.EventLog.SourceName" value="Duwamish7" />
   <!-- Use the standard TraceLevel values:
   0 = Off
   1 = Error
   2 = Warning
   3 = Info
   4 = Verbose -->
   <add key="SystemFramework.EventLog.LogLevel" value="1" />
   </ApplicationConfiguration>
   <DuwamishConfiguration>
   <!-- Settings specific to the Duwamish application -->
   <add key="Duwamish.DataAccess.ConnectionString" value="server=LUYAN\NetSDK;User ID=Duwamish7_login;Password=password;database=Duwamish7;Connection Reset=FALSE" />
   <add key="Duwamish.Web.EnablePageCache" value="True" />
   <add key="Duwamish.Web.PageCacheExpiresInSeconds" value="3600" />
   <add key="Duwamish.Web.EnableSsl" value="False" />
   </DuwamishConfiguration>
   <SourceViewer>
   <!-- Valid directories for source browsing. Keep these lower case. -->
   <add key="." value=" " />
   <add key="modules" value=" " />
   <add key="..\common\data" value=" " />
   <add key="..\systemframework" value=" " />
   <add key="..\business\facade" value=" " />
   <add key="..\business\rules" value=" " />
   <add key="..\dataaccess" value=" " />
   <add key="secure" value=" " />
   <add key="docs\common" value=" " />
   <add key="docs\dataaccess" value=" " />
   <add key="docs\facade" value=" " />
   <add key="docs\rules" value=" " />
   <add key="docs\web" value=" " />
   </SourceViewer>
  
  配置节信息分为两个主区域:配置节处理程序声明区域和配置节设置区域,这里就是刚才定义的三个section的配置节设置区域,它包含实际的配置设置,其用途说明请参见注释,所有配置信息都必须驻留在 <configuration> 和 </configuration> 根 XML 标记之间,配置节设置区域位于 <configSections> 区域之后。
  
  
  --------------------------------------------------------------------------------
  
  配置节处理程序
  
  前面已经介绍了,section里定义了处理配置节的类:Duwamish7.SystemFramework.ApplicationConfiguration和Duwamish7.Common.DuwamishConfiguration,他们分别位于SystemFramework和Common项目中,.net规定,所有能够处理配置节的类必须要实现IConfigurationSectionHandler接口,而IConfigurationSectionHandler接口很简单,只有一个object Create(object parent,object configContext,XmlNode section)方法,这个方法不需要主动调用,它是在ConfigurationSettings.GetConfig这个静态方法的时候自动调用的,也就是说,当你在程序中使用ConfigurationSettings.GetConfig来获取配置节的时候,.net会根据改配置节声明中所定义的类名和路径自动实例化配置节处理类,并调用Create方法。下面是Duwamish的处理类调用流程:
  
  1、在global.asax的Application_OnStart方法里面调用ApplicationConfiguration.OnApplicationStart静态方法,并获得应用程序根的绝对路径。
  
   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);
   }
  
  
  2、ApplicationConfiguration.OnApplicationStart静态方法里调用System.Configuration.ConfigurationSettings.GetConfig方法处理配置节:
  
   public static void OnApplicationStart(String myAppPath)
   {
   appRoot = myAppPath;
   System.Configuration.ConfigurationSettings.GetConfig("ApplicationConfiguration");
   System.Configuration.ConfigurationSettings.GetConfig("DuwamishConfiguration");
   System.Configuration.ConfigurationSettings.GetConfig("SourceViewer");
   }
  
  大家已经注意到了,Duwamish并没有获取GetConfig返回的值,因为前面已经说过,GetConfig方法会引发配置节处理程序的Create方法,所以,只需要在Create方法中将配置值取出来就行了。
  
  3、配置读取示例:Duwamish7.Common.DuwamishConfiguration类
  
  public Object Create(Object parent, object configContext, XmlNode section)
  {
  
   NameValueCollection settings;
  
   try
   {
   NameValueSectionHandler baseHandler = new NameValueSectionHandler();
   settings = (NameValueCollection)baseHandler.Create(parent, configContext, section);
   }
   catch
   {
   settings = null;
   }
  
   if ( settings == null )
   {
   dbConnectionString = DATAACCESS_CONNECTIONSTRING_DEFAULT;
   pageCacheExpiresInSeconds = WEB_PAGECACHEEXPIRESINSECONDS_DEFAULT;
   enablePageCache = WEB_ENABLEPAGECACHE_DEFAULT;
   enableSsl = WEB_ENABLESSL_DEFAULT;
   }
   else
   {
   dbConnectionString = ApplicationConfiguration.ReadSetting(settings, DATAACCESS_CONNECTIONSTRING, DATAACCESS_CONNECTIONSTRING_DEFAULT);
   pageCacheExpiresInSeconds = ApplicationConfiguration.ReadSetting(settings, WEB_PAGECACHEEXPIRESINSECONDS, WEB_PAGECACHEEXPIRESINSECONDS_DEFAULT);
   enablePageCache = ApplicationConfiguration.ReadSetting(settings, WEB_ENABLEPAGECACHE, WEB_ENABLEPAGECACHE_DEFAULT);
   enableSsl = ApplicationConfiguration.ReadSetting(settings, WEB_ENABLESSL, WEB_ENABLESSL_DEFAULT);
   }
  
   return settings;
  }
  
  这里可以看到,Duwamish其实并没有自己手工从一个XmlNode里面读取数据,而是直接将数据转给一个NameValueSectionHandler做实际的配置读取,它自己所做的工作只是检查是否有实际定义的配置值,如果没有的话,就赋给默认值。
  
  
  --------------------------------------------------------------------------------
  
  总结:
  
  至此,web.config中的配置值就被读到了配置类的静态变量中,以后在程序的其它地方就可以使用配置类的静态变量来直接访问配置值了,例如,在程序的任何地方,只要输入Duwamish7.Common.DuwamishConfiguration.ConnectionString就可以得到:server=LUYAN\NetSDK;User ID=Duwamish7_login;Password=password;database=Duwamish7;Connection Reset=FALSE这个字符串。更为理想的是,你可以扩展自己的配置节和配置节处理程序,对比较复杂的自定义配置进行预处理。
  
  
  -------------------------------------------------------------------------------- 
   come from:http://www.cnblogs.com/goodspeed/articles/5018.html
posted @ 2009-11-05 22:50  ChouKei  阅读(331)  评论(0编辑  收藏  举报