Duwamish初探简介

ASP.NET 同时被 2 个专栏收录
53 篇文章 0 订阅
22 篇文章 0 订阅

学习软件的时候,软件学院的老师就说了这个,一直没去深入关注过,一有些时间小小研究了下:

一、Duwamish 7.0的架构
Duwamish 7.0是vs.net中微软提供的一个企业级的示例,最近在学设计方面的东西,所以有时间边看边学这个示例。做了一些笔记,和大家一起讨论。
    学习Duwamish 7.0,首先要看的当然是它的一个整体的结构式,在msdn自带的帮助文件中,我们看到了它的一个整体的结构,如下图所示:

Duwamish 7.0分为四层,分别为:
l    Web层
相当于是用户界面层,直接与用户交互的web窗体,从源码中我们可以看到,它有以下的一些界面页:
页面名称    作用
book.aspx    用以显示图书的详细信息的页面
default.aspx    默认页,显示当天的精选书
categories.aspx    用于分类显示图书的页面,它由两部分组成,上半部分显示当天推荐的该分类的图书信息,下半部分显示该分类的
errorpage.aspx    是一个静态页面,显示一成不变的错误信息
searchresults.aspx    显示搜索结果页面,用了一个datalist控件显示搜索的结果;不支持分页
shoppingcart.aspx    购物车页,用于填写购书的订单,用datagrid控件操作,支持批量修改和更新。不支持删除,设为零时能删除;不用单击update按钮就自动更新了;update按钮用于修改订购书的数量后刷新价格。
viewsource.aspx    既然是示例,当然可以看源代码了,这一页是专门用于查看源代码的

下面的页面是用于管理用户及用户订单系统,微软专门把它放在secure文件夹下:
页面名称    作用
account.aspx    新客户注册页及客户修改个人信息页;
checkout.aspx    确认购买页面,填写收货人的详细地址和联系方式,填入信用卡的信息,列出购买的清单及总的费用信息。
order.aspx    显示用户的订单信息,以供用户打印该订单
在Duwamish 7.0中,大量的运用了用户控件,各个用户控件的功能不一,用户控件统一放在modules文件夹下:
用户控件名称    作用
accountmodule.ascx    对应于account.aspx页面,新客户注册页及客户修改个人信息
bannermodule.ascx    每一页都包含有该用户控件,它定义的页面的头部信息,在页面中看到的头上的哪片黑色的区域就是它了,包含一个图片,三个按钮。
categoriesmodule.ascx    每一页都包含有该用户控件,它显示了书籍的分类信息。在页面的左边的”Browse Categories”文字开始到” Behind The Scenes”文字结束就是该控件的界面内容了
checkoutmodule.ascx    对应于checkout.aspx页,因为checkout.aspx页是一个按步骤操作的页(用panel控件控制),每走一页,checkoutmodule.ascx控件中的箭头就往前走或往后退一格。在父页面中通过控制checkoutmodule.ascx控件的Stage属性来控制
dailypickmodule.ascx    用于显示推荐的图书信息,在default.aspx页和categories.aspx页中用到
searchmodule.ascx    搜索功能控件,每页的搜索功能都由这个控件实现
viewsourcemodule.ascx    查看源码功能控件,每页的查看源功能都是由这个用户控件实现
所有用户界面层就是上述的页面和用户控件,看起来其实也不多。
l    业务外观层
什么是业务外观层,这是四层结构里面新增的东西?有什么用呢?现在我也不知道,先让我们看看Duwamish 7.0中业务层中包含一些什么?打开BusinessFacade项目,这里面的东西就是Duwamish 7.0业务外观层了,看看里面有下面的这些文件组成:
文件名称    类作用
CustomerSystem.cs    CustomerSystem类是客户系统的业务外观层,它为客户子系统提供了一个简单的接口,该类支持远程处理的应用程序中跨应用程序域边界访问。它继承自MarshalByRefObject类。从Duwamish 7.0中提供的visio图上看,CustomerSystem类只有三个方法,分别是:GetCustomerByEmail方法(从email和密码获得客户的信息),UpdateCustomer方法(更新客户的信息,接收一个CustomerData对象),CreateCustomer方法(当然是用于创建一个新的客户了)
OrderSystem.cs    OrderSystem类用于处理订单的业务外观,它只有两个方法:GetOrderSummary方法(用于统计订单),AddOrder方法(用于新增一个订单)
ProductSystem.cs    ProductSystem类用于处理书的业务外观,它的方法比较多,有五个分别是:GetCategories方法(通过分类的id获得类别自身的信息);GetCategoryItems方法(通过分类的id获得该类下的所有的书的信息);GetDailyPickItems方法(通过分类的id获得该类下的推荐书的信息);GetItemById方法(通过书的id获得有关书的信息);GetSearchItems方法(根据指定的检索字段条件以及书名的关键字查询书的信息)
   
    看了上面业务层的类以后,我们发现所有的业务层类都只有方法,没有属性,我的理解是它是所有与用户界面有关的操作的一些方法的定义。
    这两天又到微软中国网站上看看,发现了卢彦写的几篇关于Duwamish 7.0的文章其中的一篇就是有关为什么要加业务外观层的,看了后,才完全理解,下面我们来看看卢彦的这篇文章的片断:
    在Web应用程序中,有部分操作只是简单的从数据库根据条件提取数据,不需要经过任何处理,而直接将数据显示到网页上,比如查询某类别的图书列表。而另外一些操作,比如计算定单中图书的总价并根据顾客的级别计算回扣等等,这部分往往有许多不同的功能的类,操作起来也比较复杂。我们可以先想象一下,如果我们采用三层结构,这些商业逻辑一般是会放在中间层,那么对内部的这些大量种类繁多,使用方法也各异的,不同的类的调用任务就完全落到了表示层。这样势必会增加表示层的代码量,将表示层的任务复杂化,和表示层只负责接受用户的输入并返回结果的任务不太相称,并增加了层与层之间的耦合程度。
    为了解决这个问题,我们先来看看《设计模式》一文中对Facade模式的描述:
意图:
    为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
适用性:
    当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过Facade层。
    客户程序与抽象类的实现部分之间存在着很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移植性。
    当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过Facade进行通讯,从而简化了它们之间的依赖关系。
结构图:

上文提出的这个矛盾,正好和设计模式中Facade模式中所描述的需要解决的问题非常吻合,在《设计模式》中提出的解决的办法就是引入一个Facade对象,让这个Facade来负责管理系统内部类的调用,并为表示层提供了一个单一而简单的接口。这个Facade对象,在我们的Duwamish的设计中,就是BusinessFacade(业务外观)层。
l    业务规则层
业务规则层包含各种业务规则和逻辑的实现,在Duwamish 7.0中业务规则层完成如客户帐户和书籍订单的验证这样的任务。它包含了两个类:
文件名称    类作用
Customer.cs    它有一个私有的常量REGEXP_ISVALIDEMAIL,用于验证客户的输入的email地址是否正确;insert方法用于验证和新建一条客户记录;update方法用于更新某个客户的信息;GetCustomerByEmail私有方法通过email验证是否已存在该客户的信息;Validate私有方法用于验证customer数据是否正确,它通过调用类内的IsValidEmail(验证email方法)和IsValidField(验证字段的内容是否超长字段规定的长度)来验证整个customer对象是否正确
Order.cs    私有的常量MINIMUM_SHIPPING_CHARGE,私有的常量STANDARD_ITEM_COUNT。CalculateTax方法用于计算税收。CalculateShipping用于计算购物的总价格。InsertOrder方法用于插入一个订单;IsValidField用于验证字段的正确性
    从上面的两个类设计来看,业务逻辑层的功能是对业务对象是否符合业务逻辑的验证,无需验证的对象则无需写其业务层,从业务外观层我们看到,CustomerSystem.类对应于Customer类,它对CustomerSystem.提交的CustomeData对象进行验证。Order类则对OrderSystem类提交的OrderData对象进行验证。但是我们看到没有对ProductSystem类的验证的对象,这是因为在Duwamish 7.0中没有提供对product(在这里是指书)对象的更新或新增操作。我想,如果它提供了对书的维护功能的话,它也肯定有这个业务规则对象。
    原文请看:http://www.microsoft.com/china/community/ ... icle/TechDoc/duwamish.asp
l    数据访问层
数据访问层负责对业务层提供数据操作,也就是它负责和底层的数据库打交道。业务层或者通用层中所有的对象都通过数据访问层的对象访问数据库。数据访问层中的类是按业务对象来组织的,每个业务对象中包含的数据可能存在不同的几种数据表中,它由数据访问类统一组织成一个概念中的对象,它相当于是一个面向对象的数据库层,负责映射面向对象与关系数据库间的关系。
对数据库的所有操作均由存储过程完成,数据层只是在前台调用后台的存储过程。
文件名称    类作用
Books.cs    Books类有许多的方法,构造函数Books首先创建了一个SqlDataAdapter对象,然后指定了该对象的SqlConnection对象。Books类实现了Idisposable接口,实现的Dispose方法,用于销毁该对象。下面的各个方法都是根据不同的参数获得BookData,包括:GetBooksByCategorId(对应于同名的存储过程,通过类别id获得bookdata数据集对象),GetDailyPickBooksByCategoryId(对应于同名的存储过程,通过类别id获得推荐的bookdata数据集对象),GetBookById(通过书的id取得书的信息),GetBooksByAuthor(通过作者名获得书的信息,可能有N条记录),GetBooksByISBN(通过isbn获得书的信息),GetBooksBySubject,GetBooksByTitle,上述的方法其它都是通过FillBookData(通过传进行存储过程名作参数和参数值执行SqlDataAdapter对象的fill方法填充bookdata对象)方法执行对应的存储过程来获得BookData。
Categories.cs    Categories类的方法比较少,除了构造函数和dispose方法外,就只有GetCategories方法(通过分类的id获得该类的父、本、子三级的分类对象)和FillCategoryData私有方法(为GetCategories方法从底层数据库中获取数据到CategoriesData)。
Customers.cs    Customers类除了构造函数和dispose方法外,有三个公开的方法,LoadCustomerByEmail方法(调用GetLoadCommand方法,获得sqlcommand对象后,执行GetCustomerByEmail存储过程,获得customerdata对象),UpdateCustomer方法(更新整个的customer对象,在UpdateCustomer存储过程中又调用了UpdateCustomerAddress存储过程来更新Addresses表。它有一个缺点就是每次更都会完全的更新两张表的所有的内容),InsertCustomer(与UpdateCustomer方法类似,它调用InsertCustomer和InsertAddress两个存储过程完成两个表的插入工作,唯一不同的插入操作是先插入主表,然后再插入从表。更新是先从表,后主表。),及三个私有的为前三个公开的方法服务的方法。GetLoadCommand方法(生成调用GetCustomerByEmail存储过程的sqlcommand命令返回),GetInsertCommand(生成调用InsertCustomer存储过程的sqlcommand命令返回,它用了sqlparameter对象的sourcecolumn属性映射对dataset的某个对象),GetUpdateCommand(它与GetInsertCommand方法类似)。
Orders.cs    Orders除了构造函数和dispose方法外,也只有一个公开的方法InsertOrderDetail方法(插入一个订单到数据库,详细的说明看源码注释)及一个私有方法GetInsertCommand(初始化DataAdapter对象的Insert命令参数集)
l    通用层
映射关系数据库表到实际应用的类(对象)层。相当于是一个面向对象的数据库层,把物理的数据库表的字段映射成业务对象:
文件名称    类作用
BookData.cs    BookData类继承自dataset类,创建了一个datatable表,用于存储书的数据。支持序列化。(序列化有什么用?它没有声明authors字段,但填充的时却有这个字段?)
CategoryData.cs     CategoryData类继承自dataset类,创建了一个datatable表,用于存储书分类的数据。支持序列化。
CustomerData.cs    CustomerData类继承自dataset类,创建了一个datatable表,用于存储书的数据。支持序列化。
OrderData.cs    OrderData类也继承自dataset类,但它包含了五个表,各个表字段不一样。
l    系统架构层
文件名称    类作用
ApplicationConfiguration   
DuwamishConfiguration   
太乱了,我把《项目总结》系列和这个打成包,要的,留个email!
三、编程技巧学习
1.    存储过程技巧
1)    输出参数可以当输入参数使用
2)    字符串字段的累加的方法
我们看看GetBookById存储过程的一段源码:
PROCEDURE GetBookById
    @BookId INT
AS
    -- max size = 10 Authors
    DECLARE @AuthorList nvarchar(480)
    SET NOCOUNT ON
    -- initialize @AuthorList
    SELECT @AuthorList = ""
    -- build list of authors
    SELECT @AuthorList = @AuthorList + a.Name + ", "
      FROM Books b,
           BookAuthor ba,
           Authors a
     WHERE b.ItemId = @BookId
       AND ba.ItemId = b.ItemId
       AND a.PKId = ba.AuthorId
-- remove last comma
SELECT @AuthorList = LEFT(@AuthorList,LEN(@AuthorList) - 1)
      把这段单独拷出来,在查询分析器运行,我们发现这段是用来取某本书的作者的列表,一本书可能有多个作者,
SELECT @AuthorList = @AuthorList + a.Name + ", "
      FROM Books b,
           BookAuthor ba,
           Authors a
     WHERE b.ItemId = @BookId
       AND ba.ItemId = b.ItemId
                       AND a.PKId = ba.AuthorId
    就是把书的作者名一个个取出来,累加到@AuthorList变量中,各个作者用逗号隔开,最后一句SELECT @AuthorList = LEFT(@AuthorList,LEN(@AuthorList) - 1)把最后一个作者后的逗号去掉。
3)    存储过程参数与dataset中字段的映射
在Customers类中的GetInsertCommand方法中,我们看到了下面的代码:
sqlParams[PKID_PARM].SourceColumn = CustomerData.PKID_FIELD;
                    sqlParams[PKID_PARM].Direction = ParameterDirection.Output;
sqlParams[EMAIL_PARM].SourceColumn = CustomerData.EMAIL_FIELD;
        它运用了sqlparameter对象的SourceColumn属性,该属性用于指定sqlparameter对象的值与dataset中字段的映射。它是双向,即是输入值,也是输出值。sqlParams[EMAIL_PARM].SourceColumn = CustomerData.EMAIL_FIELD;这一句表示把CustomerData(dataset对象)的EMAIL_FIELD字段值映射成sqlParams[EMAIL_PARM]的参数值。
4)   
2.    Web 编程技巧
1)    运用ado.net中的dataview对已存在结果集进行再查询
在cart类的AddItem方法中我们可看到源码:
public void AddItem(int itemId, String itemDescription, Decimal itemPrice)
        {
            DataTable itemTable = OrderItems;
            DataView itemSource = new DataView(itemTable);
        
            //search for item, check to see if the item has already been ordered
            //通过itemid查找item,检查是否已预定该item,利用DataView的RowFilter属性,设置其过滤条件。
            //接下来用DataView的count属性执行查询并返回满足条件的记录数
            itemSource.RowFilter = "ItemNumber = " + itemId.ToString();
            
            //如果已经订了该书,增加数量
            if (itemSource.Count > 0)
            {
                DataRowView sourceRow = itemSource[0];
                short count = (short)(sourceRow[OrderData.QUANTITY_FIELD]);
                //maximum allowed for any specific item is 50
                //每种书最多允许订50本
                if (count

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

技术基础 New Folder 多样式星期名字转换 [Design, C#] .NET关于string转换的一个小Bug Regular Expressions 完整的在.net后台执行javascript脚本集合 ASP.NET 中的正则表达式 常用的匹配正则表达式和实例 经典正则表达式 delegate vs. event 我是谁?[C#] 表达式计算引擎 正式发布表达式计算引擎WfcExp V0.9(附源码) 运算表达式类的原理及其实现 #实现的18位身份证格式验证算法 身份证15To18 的算法(C#) 一组 正则表达式 静态构造函数 忽略大小写Replace效率瓶颈IndexOf 随机排列算法 理解C#中的委托[翻译] 利用委托机制处理.NET中的异常 与正则表达式相关的几个小工具 你真的了解.NET中的String吗? .NET中的方法及其调用(一) 如何判断ArrayList,Hashtable,SortedList 这类对象是否相等 帮助解决网页和JS文件中的中文编码问题的小工具 慎用const关键字 装箱,拆箱以及反射 动态调用对象的属性和方法——性能和灵活性兼备的方法 消除由try/catch语句带来的warning 微软的应试题完整版(附答案) 一个时间转换的问题,顺便谈谈搜索技巧 .net中的正则表达式使用高级技巧 (一) C#静态成员和方法的学习小结 C#中结构与类的区别 C#中 const 和 readonly 的区别 利用自定义属性,定义枚举值的详细文本 Web标准和ASP.NET - 第一部分 XHTML介绍 在ASP.NET页面中推荐使用覆写(Override)而不是事件处理(Event Handler) 常用编码工具类,支持base64,md5,des,crc32 也谈谈技术面试 在C#里把ArrayList转换为Array 或 把Array转换为ArrayList C# 2.0 在.NET 2.0中,让你的组件也可以绑定 .NET20 一种简单的窗口控件UI状态控制方法 翻译MSDN文章 —— 泛型FAQ:最佳实践 Visual C# 3.0 新特性概览 C# 2.0会给我们带来什么 泛型技巧系列:如何提供类型参数之间的转换 C#2.0 - Object Pool 简单实现 Attributes in C# 手痒痒,也来个c# 2.0 object pool 泛型技巧系列:用泛型打造可复用的抽象工厂 体验.net2.0的优雅(四):Provider、策略、控制反转和依赖注入 泛型最佳实践 asp.net 2.0下嵌套masterpage页的可视化编辑 C# 2.0与泛型 动态调用对象的属性和方法——性能和灵活性兼备的方法 泛型技巧系列:用泛型打造可复用的抽象工厂 泛型技巧系列:如何提供类型参数之间的转换 .NET 2.0 泛型Quiz Visual Studio 2005体验泛型编程 C++ 泛型编程系列讲座之实施 泛型技巧系列:简单类型选择器 C# 泛型简介 我眼中的C#2.0新功能特性 泛型技巧系列:避免基类及接口约束 New Article 不该用Generics实现Abstract Factory的理由 C#2.0-泛型 C#2.0-extern C#2.0-可空类型 C#2.0-分部类 C#2.0-迭代器 C#2.0 的新增功能学习 泛型的序列化问题 .NET 2.0 泛型在实际开发中的一次小应用 C#2.0 Singleton 的实现 .Net Framwork 强类型设计实践 通过反射调用類的方法,屬性,字段,索引器(2種方法) ASP.NET: State Server Gems 完整的动态加载/卸载程序集的解决方案 从NUnit中理解.NET自定义属性的应用(转载) 如何在.NET中实现脚本引擎 (CodeDom篇) .NET的插件机制的简单实现 我对J2EE和.NET的一点理解 难分难舍的DSO(一) InternalsVisibleToAttribute,友元程序集访问属性 Essential .NET 读书笔记 [第一部分] NET FrameWork的Collections支持 .NET的反射在软件设计上的应用 关于跨程序集的反射 实现C#和VB.net之间的相互转换 深入剖析ASP.NET组件设计]一书第三章关于ASP.NET运行原理讲述的补白 asp.net 运行机制初探(httpModule加载) 利用反射来查看对象中的私有变量 关于反射中创建类型实例的两种方法 ASP.Net应用程序的多进程模型 NET委托:一个C#睡前故事 [推荐] - [原创] Microsoft .NET策略及框架概述 卸载Class? Web Form 窗体 如何实现web页面的提
©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值