PetShop之表示层设计

自拿温馨区分对待,到了本人之
年纪还有啊偶像情结呢?我既非会师去接机,也无相会让偶像了生日。我爱好一个文豪可以,歌手也好,只是一味地针对创作之玩味,剥离了针对产出者的民用心绪。我开得深好,娱乐圈的纷纷扰扰离我特别漫长,我不关心就是没打扰。

图片 1<asp:CreateUserWizard ID=”CreateUserWizard” runat=”server” CreateUserButtonText=”Sign Up” InvalidPasswordErrorMessage=”Please enter a more secure password.” PasswordRegularExpressionErrorMessage=”Please enter a more secure password.” 
图片 2RequireEmail=”False” SkinID=”NewUser”>
图片 3<WizardSteps>
图片 4            <asp:CreateUserWizardStep ID=”CreateUserWizardStep1″ runat=”server”>
图片 5   </asp:CreateUserWizardStp>
图片 6 </WizardSteps>
图片 7</asp:CreateUserWizard>

他由此生更同潮宣布他的痛苦,不知道暴发略人假若己,真的心疼了。也不精晓疼的人数碰面痛多长时间。我就了然自己爆发种植信念塌了,成年时卖力地活着在,也弥补不了童年不时的痛。

若用MVC格局拆解为老两只单身的一部分:Model、View、Controller,我们可通过GOF设计形式来实现与治本它们中的涉及。在系统架构设计中,业务逻辑层的天地对象与数额访问层的数据值对象还属于MVC模式的Model对象。倘若要治本Model与View之间的涉,可以运用Observer情势,View作为观看者,一旦Model的属于性值暴发变化,就会打招呼View基于Model的值举办更新。而Controller作为控制用户要/响应的目标,则能够Mediator情势,专门负责请求/响应任务中的调剂。而对View本身,在面向组件设计思想的底子及,大家平时将它们设计也罢组件或者控件,这个零件或者控件按照本人特色的不同,共同组成一栽类似于递归组合的靶子社团,由此我们得以选取Composite形式来计划View对象。

外丢弃了,我不想念以顿时由为吃简单的软弱。说自杀者脆弱的人口或者是“少年不知愁滋味”的春秋,也说不定是无受过不克愈合的侵害。“Crawling
in my skin,these wounds they will not
heal.”在各级一样寸皮肤游走,那些不能愈合的危。有些痛苦表面上会愈合,伤口会结痂,背后的故事会陈旧,再沉痛的故事啊会于不少软的茶余饭后消磨尽新鲜感,变得冷冷清清,只有当事者自己,永远不能忘记,看似愈合的伤口开抓捕挠着一身,密密麻麻地提醒在来往的疼痛。

当代表层中,可以动用页面的Profile属性访问用户的本性化属性,例如当ShoppingCart页面的codebehind代码ShoppingCart.aspx.cs中,调用Profile的ShoppingCart属性:

当我们得意、捶胸顿足地沉醉在重金属音乐被,跟着节奏对一成不变的生活怒吼时,我们兴奋、放肆,感受在无通常的律动。他也于平等举整个温习着痛苦,可重复努的嘶吼也不论用,赶不运动往事,吓不下降恐惧,更保养不了多年前很怯懦的小子。

各国一个及Master
Page相关的情节页必须于@Page指令的MasterPageFile属性中援引相关的Master
Page。例如PetShop 4.0面临的CheckOut内容页,其@Page指令的概念如下:

直到方才,我看见查斯特·贝宁顿的音讯,我之影响是震惊-不相信-证伪-悲伤。我难受得大呼小叫,又不便自已。我打开音乐软件,翻在和谐的已经起曲目,林肯(Lincoln)公园占了半壁江山,随机点开平曲Given
up,歌声离自己挺近,查斯特·贝宁顿离自己好远,好像相比往常复远了,悲伤却以心窝里。“I’ve
given up,I’m sick of feeling”,学爱沙尼亚语的炎黄口平日说“Never give
up”,林肯(Lincoln)公园的乐章却是自个儿割舍了,我看不惯这感觉,我直接认为立时是说正玩的,这是知耻后勇、绝处重生。我了解他的喊叫不仅仅是表彰技巧,是方法样式,我晓得那么是外发自肺腑的呼喊,对生的轰,对悲惨童年的难释怀。但自身非明了他会晤真的抛弃,他吐弃了。

《解剖PetShop》类此外六

代码中,InsertUser()方法就是承担用户之创设,而在事先虽说需要判定创制的用户是否曾在。InsertUser()方法的定义如下:

Profile的产出缓解了上述的不快,它可以以用户的个人化音信保存于指定的数据库中。ASP.NET
2.0底Profile效用默认襄助Access数据库暨SQL
Server数据库,要是欲协理其他数据库,可以编制相关的ProfileProvider类。Profile对象是强类型的,我们可为用户新闻建立属性,以PetShop
4.0乎条例,它起了ShoppingCart、WishList和AccountInfo属性。

图片 8图片 9private static bool InsertUser(OracleTransaction transaction, int userId, string email, string password, int passFormat, string passSalt, string passQuestion, string passAnswer, bool isApproved, DateTime dt) 图片 10{
图片 11
图片 12 string insert = “INSERT INTO MEMBERSHIP (USERID, EMAIL, PASSWORD, PASSWORDFORMAT, PASSWORDSALT, PASSWORDQUESTION, PASSWORDANSWER, ISAPPROVED, CREATEDDATE, LASTLOGINDATE, LASTPASSWORDCHANGEDDATE) VALUES (:UserID, :Email, :Pass, :PasswordFormat, :PasswordSalt, :PasswordQuestion, :PasswordAnswer, :IsApproved, :CDate, :LLDate, :LPCDate)”;
图片 13图片 14 OracleParameter[] insertParms = 图片 15{ new OracleParameter(“:UserID”, OracleType.Number, 10), new OracleParameter(“:Email”, OracleType.VarChar, 128), new OracleParameter(“:Pass”, OracleType.VarChar, 128), new OracleParameter(“:PasswordFormat”, OracleType.Number, 10), new OracleParameter(“:PasswordSalt”, OracleType.VarChar, 128), new OracleParameter(“:PasswordQuestion”, OracleType.VarChar, 256), new OracleParameter(“:PasswordAnswer”, OracleType.VarChar, 128), new OracleParameter(“:IsApproved”, OracleType.VarChar, 1), new OracleParameter(“:CDate”, OracleType.DateTime), new OracleParameter(“:LLDate”, OracleType.DateTime), new OracleParameter(“:LPCDate”, OracleType.DateTime) };
图片 16 insertParms[0].Value = userId;
图片 17 insertParms[1].Value = email;
图片 18 insertParms[2].Value = password;
图片 19 insertParms[3].Value = passFormat;
图片 20 insertParms[4].Value = passSalt;
图片 21 insertParms[5].Value = passQuestion;
图片 22 insertParms[6].Value = passAnswer;
图片 23 insertParms[7].Value = OracleHelper.OraBit(isApproved);
图片 24 insertParms[8].Value = dt;
图片 25 insertParms[9].Value = dt;
图片 26 insertParms[10].Value = dt;
图片 27
图片 28 if(OracleHelper.ExecuteNonQuery(transaction, CommandType.Text, insert, insertParms) != 1)
图片 29  return false;
图片 30 else
图片 31  return true;
图片 32}

Control基类并没含UI的一定功能,如若要提供和UI相关的章程属性,就用由System.Web.UI.WebControls.WebControl类派生。该类实际上为是Control类的子类,但其附加了像ForeColor、BackColor、Font等性。

图片 33<%@ Page Language=”C#” MasterPageFile=”~/MasterPage.master” AutoEventWireup=”true” CodeFile=”CheckOut.aspx.cs” Inherits=”PetShop.Web.CheckOut” Title=”Check Out” %>

至于安排节属性的意思,可以参见MSDN等连锁文档。

图片 34public partial class CheckOut : System.Web.UI.Page图片 35
图片 36
图片 37图片 38    protected void wzdCheckOut_FinishButtonClick(object sender, WizardNavigationEventArgs e) 图片 39{
图片 40图片 41        if (Profile.ShoppingCart.CartItems.Count > 0) 图片 42{
图片 43图片 44            if (Profile.ShoppingCart.Count > 0) 图片 45{
图片 46
图片 47                // display ordered items
图片 48                CartListOrdered.Bind(Profile.ShoppingCart.CartItems);
图片 49
图片 50                // display total and credit card information
图片 51                ltlTotalComplete.Text = ltlTotal.Text;
图片 52                ltlCreditCardComplete.Text = ltlCreditCard.Text;
图片 53
图片 54                // create order
图片 55                OrderInfo order = new OrderInfo(int.MinValue, DateTime.Now, User.Identity.Name, GetCreditCardInfo(), billingForm.Address, shippingForm.Address, Profile.ShoppingCart.Total, Profile.ShoppingCart.GetOrderLineItems(), null);
图片 56
图片 57                // insert
图片 58                Order newOrder = new Order();
图片 59                newOrder.Insert(order);
图片 60
图片 61                // destroy cart
图片 62                Profile.ShoppingCart.Clear();
图片 63                Profile.Save();
图片 64            }
图片 65        }
图片 66图片 67        else 图片 68{
图片 69            lblMsg.Text = “<p><br>Can not process the order. Your cart is empty.</p><p class=SignUpLabel><a class=linkNewUser href=Default.aspx>Continue shopping</a></p>”;
图片 70            wzdCheckOut.Visible = false;
图片 71        }
图片 72    }
图片 73
图片 74

以至AJAX(Asynchronous JavaScript and
XML)的面世,整个层面才大为改观。即使AJAX技术带有几分“旧瓶装新酒”的意味,可是其自从出生之初,就所有了皇帝气象,大生席卷天下之势。各样协理AJAX技术之框架而沧澜江沙数一般纷纷吐生新芽,支撑由百花齐放的繁荣昌盛,气势汹汹地营造起唯AJAX独尊的千姿百态。目前,AJAX已经变为了Web应用之主流开发技术,许多业界大鳄都呲牙咧嘴起始了针对顿时同片新领地的抢滩登陆。例如IBM、Oracle、Yahoo等营业所还纷纷启动了开源之AJAX项目。微软也不甘落后,及时地出了ASP.NET
AJAX,那是一个基于ASP.NET的AJAX框架,它概括了ASP.NET
AJAX服务端组件和ASP.NET AJAX客户端组件,并集成以Visual
Studio中,为ASP.NET开发者提供了一个精锐的AJAX应用环境。

在面的相同截代码中,分外出众地发表了Model与View之间的涉及。它通过取得控件的属于性值,作为参数值传递给数据值对象OrderInfo,从而使页面上发出的订单消息成立订单对象,然后再一次调用领域对象Order的Inser()方法以OrderInfo对象插入到多少表中。此外,它还针对性世界对象ShoppingCart的数量项作出判断,固然其值等于0,就于页面中显示UI提醒音讯。此时,View的情决定了Model的值,而Model值反过来还要决定了View的示内容。

图6-3 PetShop 4.0的Master Page

图片 75<membership defaultProvider=”OracleMembershipProvider”>
图片 76 <providers>
图片 77  <clear/>
图片 78  <add name=”OracleMembershipProvider” 
图片 79   type=”PetShop.Membership.OracleMembershipProvider” 
图片 80   connectionStringName=”OraMembershipConnString” 
图片 81   enablePasswordRetrieval=”false” 
图片 82   enablePasswordReset=”false” 
图片 83   requiresUniqueEmail=”false” 
图片 84   requiresQuestionAndAnswer=”false” 
图片 85   minRequiredPasswordLength=”7″ 
图片 86   minRequiredNonalphanumericCharacters=”1″ 
图片 87   applicationName=”.NET Pet Shop 4.0″ 
图片 88   hashAlgorithmType=”SHA1″ 
图片 89   passwordFormat=”Hashed”/>
图片 90 </providers>
图片 91</membership>

图片 92private IList dataSource;
图片 93private int itemCount;
图片 94
图片 95图片 96override public object DataSource 图片 97{
图片 98图片 99    set 图片 100{
图片 101    //This try catch block is to avoid issues with the VS.NET designer
图片 102        //The designer will try and bind a datasource which does not derive from ILIST
图片 103图片 104        try 图片 105{
图片 106            dataSource = (IList)value;
图片 107            ItemCount = dataSource.Count;
图片 108        }
图片 109图片 110        catch 图片 111{
图片 112            dataSource = null;
图片 113            ItemCount = 0;
图片 114        }
图片 115    }
图片 116}

Master Page相当于是一切Web站点的合并模板,建立的Master
Page文件扩展名为.master。它可以蕴涵静态文本、html元素和服务器控件。Master
Page由特另外@Master指令识别,如:

ASP.NET控件的实践生命周期如表6-1所体现:

对此CustomGrid而言,DataSource属性有着不同的安装行为,因此在定义CustomGrid控件的时节,需要变更写DataSource虚属性,如下所示:

注意Master
Page页面不再接续自System.Web.UI.Page,而是继续System.Web.UI.MasterPage类。与Page类继承TemplateControl类不同,它是UserControl类的子类。因而,可以拔取在Master
Page上的实用指令和UserControl的可用指令相同,例如Auto伊芙(Eve)ntWireup、ClassName、CodeFile、EnableViewState、WarningLevel等。

6.4.4  Master Page特性

图片 117<membership defaultProvider=”SQLMembershipProvider”>
图片 118 <providers>
图片 119  <add name=”SQLMembershipProvider” type=”System.Web.Security.SqlMembershipProvider” connectionStringName=”SQLMembershipConnString” applicationName=”.NET Pet Shop 4.0″ enablePasswordRetrieval=”false” enablePasswordReset=”true” requiresQuestionAndAnswer=”false” requiresUniqueEmail=”false” passwordFormat=”Hashed”/>
图片 120 </providers>
图片 121</membership>

Page类实现了ProcessRequest()方法,通过其能够安装Page对象的Request和Response属性,从而完成对用户请求/相应的决定。然后Page类通过自Control类继承来之Load事件,将View与Model建立关系,如Products.aspx.cs所示:

6.4.3  ASP.NET登录控件

当啊Membership建立了Provider类后,还亟需以配置文件中配备相关的配置节,例如SqlMembershipProvider的安排:

使Master
Page可以啊网站建立一个联结之样式,且会以她好地成立同组控件和代码,然后将该应用为平组页。对于那一个体制和效率相似之页而言,利用Master
Page就好集中处理为Master
Page,一旦举办修改,就可当一个职务及举行更新。

图片 122<%@ Page AutoEventWireup=”true” Language=”C#” MasterPageFile=”~/MasterPage.master” Title=”Products” Inherits=”PetShop.Web.Products” CodeFile=”~/Products.aspx.cs” %>

图片 123

这边所谓的登录控件并无是据一个控件,而是ASP.NET
2.0初供的平等组用于解决用户登录的控件。登录控件与Membership举办集成,急迅便捷地促成用户登录的拍卖。ASP.NET登录控件包括Login控件、LoginView控件、LoginStatus控件、LoginName控件、PasswordRescovery控件、CreateUserWizard控件以及ChangePassword控件。
PetShop
4.0似一比照显示登录控件用法的圆满教程。大家得以由诸如SignIn、NewUser等页面被,看到ASP.NET登录控件的运方法。例如当SignIn.aspx中,用到了Login控件。在该控件被,可以涵盖TextBox、Button等品种的控件,用法如下所示:

6.4.1  Profile特性

鉴于大家改写了DataSource属性,因此改写Repeater类的OnDataBinding()方法吧固然势在必行。此外,CustomGrid还提供了分页的法力,大家也得实现分页的有关操作。与DataSource属性不同,Repeater类的OnDataBinding()方法其实是延续和改写了Control基类的OnDataBinding()虚方法,而我辈又以斯基础及改写了Repeater类的OnDataBinding()方法:

以安排文件中,针对ShoppingCart、WishList和AccountInfo(它们的序列分别吗PetShop.BLL.Cart、PetShop.BLL.Cart、PetShop.Model.AddressInfo)属性分别定义了ShoppingCartProvider、WishListProvider、AccountInfoProvider,它们的品类均为PetShop.Profile.PetShopProfileProvider类型。至于Profile的新闻到底是储存在何系列型的数据库被,则是因为以下的配置节决定:
<add key=”ProfileDAL” value=”PetShop.SQLProfileDAL”/>

图片 124public interface IPetShopProfileProvider 
图片 125图片 126图片 127
图片 128 AddressInfo GetAccountInfo(string userName, string appName);   
图片 129 void SetAccountInfo(int uniqueID, AddressInfo addressInfo);
图片 130 IList<CartItemInfo> GetCartItems(string userName, string appName, 
图片 131bool isShoppingCart);
图片 132 void SetCartItems(int uniqueID, ICollection<CartItemInfo> cartItems, 
图片 133bool isShoppingCart);
图片 134 void UpdateActivityDates(string userName, bool activityOnly, string appName);
图片 135 int GetUniqueID(string userName, bool isAuthenticated, bool ignoreAuthenticationType,
图片 136 string appName);
图片 137 int CreateProfileForUser(string userName, bool isAuthenticated, string appName);
图片 138 IList<string> GetInactiveProfiles(int authenticationOption, 
图片 139DateTime userInactiveSinceDate, string appName);
图片 140 bool DeleteProfile(string userName, string appName);   
图片 141 IList<CustomProfileInfo> GetProfileInfo(int authenticationOption, 
图片 142string usernameToMatch, DateTime userInactiveSinceDate, string appName, 
图片 143out int totalRecords);
图片 144}

概念了PetShop.Profile.PetShopProfileProvider类后,才足以当web.config配置文件中配备如下的配置节:

下了登录控件后,我们毋需编写和用户登录相关的代码,登录控件已经为大家就了有关的功力,这就二姨地简化了那一个系统的统筹以及落实。

OracleMembershipProvider类中对CreateUser()方法的定义如下:

图片 145<PetShopControl:shoppingcartcontrol id=”ShoppingCartControl1″ runat=”server”></PetShopControl:shoppingcartcontrol>

6.2  Page Controller情势的运

除,还有一个第一之接近是System.Web.UI.UserControl,即用户控件类,它同是Control类的子类。大家得以打定义有用户控件派生自UserControl,在Visual
Studio的Design环境下,我们得透过拖动控件的法将多连串型的控件组合成一个自定义用户控件,也可以于codebehind情势下,为自定义用户控件类添加新的特性和章程。

OracleMembershipProvider类的兑现所有最高的参考价值,虽然大家用定义自己之MembershipProvider类,可以参照该类的实现。
实际上OracleMemberShip类的兑现并无复杂,在此类中,紧假诺对用户以及用户安全而落实相关的表现。由于在父类MembershipProvider中,已经定义了有关操作的虚方法,由此我们用发的凡重写这个虚方法。由于与Membership有关的信息依旧储存在数据库被,因此OracleMembershipProvider与SqlMembershipProvider类的关键分依然在于对数据库的看。对于SQL
Server而言,我们用aspnet_regsql工具为Membership建立了有关的数据表以及存储过程。也许是盖文化产权的原故,Microsoft并没吗Oracle数据库提供类似之工具,由此需要大家协调失去创设membership的数据表。此外,由于无创制Oracle数据库的积存过程,由此OracleMembershipProvider类中的落实是直调用SQL语句。以CreateUser()方法吗条例,剔除这些乱的参数判断与安全性判断,SqlMembershipProvider类的贯彻如下:

Aspx页面继承自System.Web.UI.Page类。Page类对象通过连续System.Web.UI.Control类,从而有了Web控件的特色,同时她还实现了IHttpHandler接口。作为ASP.NET处理HTTP
Web请求的接口,提供了之类的概念:

图片 146public class CustomGrid : Repeater…
图片 147//Static constants
图片 148    protected const string HTML1 = “<table cellpadding=0 
图片 149cellspacing=0><tr><td colspan=2>”;
图片 150    protected const string HTML2 = “</td></tr><tr><td class=paging align=left>”;
图片 151    protected const string HTML3 = “</td><td align=right class=paging>”;
图片 152    protected const string HTML4 = “</td></tr></table>”;
图片 153    private static readonly Regex RX = new Regex(@”^&page=\d+”, 
图片 154RegexOptions.Compiled);
图片 155    private const string LINK_PREV = “<a href=?page={0}>< Previous</a>”;
图片 156    private const string LINK_MORE = “<a href=?page={0}>More ></a>”;
图片 157private const string KEY_PAGE = “page”;
图片 158    private const string COMMA = “?”;
图片 159    private const string AMP = “&”;
图片 160
图片 161图片 162override protected void Render(HtmlTextWriter writer) 图片 163{
图片 164
图片 165        //Check there is some data attached
图片 166图片 167        if (ItemCount == 0) 图片 168{
图片 169            writer.Write(emptyText);
图片 170            return;
图片 171        }
图片 172        //Mask the query
图片 173        string query = Context.Request.Url.Query.Replace(COMMA, AMP);
图片 174        query = RX.Replace(query, string.Empty);
图片 175        // Write out the first part of the control, the table header
图片 176        writer.Write(HTML1);
图片 177        // Call the inherited method
图片 178        base.Render(writer);
图片 179        // Write out a table row closure
图片 180        writer.Write(HTML2);
图片 181        //Determin whether next and previous buttons are required
图片 182        //Previous button?
图片 183        if (currentPageIndex > 0)
图片 184            writer.Write(string.Format(LINK_PREV, (currentPageIndex – 1) + query));
图片 185        //Close the table data tag
图片 186        writer.Write(HTML3);
图片 187
图片 188        //Next button?
图片 189        if (currentPageIndex < PageCount)
图片 190            writer.Write(string.Format(LINK_MORE, (currentPageIndex + 1) + query));
图片 191
图片 192        //Close the table
图片 193        writer.Write(HTML4);
图片 194    }

图片 195public virtual object DataSource
图片 196图片 197图片 198{
图片 199图片 200      get  图片 201{… }
图片 202      set
图片 203图片 204      图片 205{
图片 206            if (((value != null) && !(value is IListSource)) && !(value is IEnumerable))
图片 207图片 208            图片 209{
图片 210图片 211                  throw new ArgumentException(SR.GetString(“Invalid_DataSource_Type”, new object[] 图片 212{ this.ID }));
图片 213            }
图片 214            this.dataSource = value;
图片 215            this.OnDataPropertyChanged();
图片 216      }
图片 217}

虽说Master
Page大部分状下是因宣称格局创建,但咱呢堪创造一个类继承System.Web.UI.MasterPage,从而成就对Master
Page的编程式创设。但当用这种措施的以,应该又创立.master文件。此外针对Master
Page的调用也得以用编程的法门完成,例如动态地添加Master
Page,我们再写内容页的Page_PreInit()方法,如下所示:

“献丑不如藏拙”,作为艺术细胞缺少的自己,并无打算于用户界面的美术设计上大做作品,是盖本书略过不取。本章所关心之代表层设计,仍旧因架构设计的角度,演说于代表层设计受到对格局之应用,ASP.NET控件的规划及行使,同时还包了针对性ASP.NET
2.0初特色之牵线。

对OracleMembershipProvider而言,配置大致相似:

鉴于PetShop 4.0是基于.NET Framework
2.0阳台支付的电子商务系统,因此它当象征层也引入了累累ASP.NET
2.0底新特征,例如MemberShip、Profile、Master
Page、登录控件等特征。接下来,我用成PetShop
4.0之计划分别介绍她的落实。

假设内容页则足以依据事态对Parent.master或者Child.master页面。

图片 218图片 219public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object userId, out MembershipCreateStatus status) 图片 220{
图片 221    //前边的代码略;
图片 222 //Create connection
图片 223 OracleConnection connection = new OracleConnection(OracleHelper.ConnectionStringMembership);
图片 224 connection.Open();
图片 225 OracleTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);
图片 226图片 227 try 图片 228{
图片 229  DateTime dt = DateTime.Now;
图片 230  bool isUserNew = true;
图片 231
图片 232  // Step 1: Check if the user exists in the Users table: create if not    
图片 233  int uid = GetUserID(transaction, applicationId, username, true, false, dt, out isUserNew);
图片 234图片 235  if(uid == 0) 图片 236{ // User not created successfully!
图片 237   status = MembershipCreateStatus.ProviderError;
图片 238   return null;
图片 239  }
图片 240  // Step 2: Check if the user exists in the Membership table: Error if yes.
图片 241图片 242  if(IsUserInMembership(transaction, uid)) 图片 243{
图片 244   status = MembershipCreateStatus.DuplicateUserName;
图片 245   return null;
图片 246  }
图片 247  // Step 3: Check if Email is duplicate
图片 248图片 249  if(IsEmailInMembership(transaction, email, applicationId)) 图片 250{
图片 251   status = MembershipCreateStatus.DuplicateEmail;
图片 252   return null;
图片 253  }
图片 254  // Step 4: Create user in Membership table     
图片 255  int pFormat = (int)passwordFormat;
图片 256图片 257  if(!InsertUser(transaction, uid, email, pass, pFormat, salt, “”, “”, isApproved, dt)) 图片 258{
图片 259   status = MembershipCreateStatus.ProviderError;
图片 260   return null;
图片 261  }
图片 262  // Step 5: Update activity date if user is not new
图片 263图片 264  if(!isUserNew) 图片 265{
图片 266图片 267   if(!UpdateLastActivityDate(transaction, uid, dt)) 图片 268{
图片 269    status = MembershipCreateStatus.ProviderError;
图片 270    return null;
图片 271   }
图片 272  }
图片 273  status = MembershipCreateStatus.Success;
图片 274  return new MembershipUser(this.Name, username, uid, email, passwordQuestion, null, isApproved, false, dt, dt, dt, dt, DateTime.MinValue);
图片 275 }
图片 276图片 277 catch(Exception) 图片 278{
图片 279  if(status == MembershipCreateStatus.Success)
图片 280   status = MembershipCreateStatus.ProviderError;
图片 281  throw;
图片 282 }
图片 283图片 284 finally 图片 285{
图片 286  if(status == MembershipCreateStatus.Success)
图片 287   transaction.Commit();
图片 288  else
图片 289   transaction.Rollback();
图片 290  connection.Close();
图片 291  connection.Dispose();
图片 292 }
图片 293}

由ShoppingCartControl用户控件已经实现了用于展现购物车多少的逻辑,那么以ShoppingCart.aspx.cs中,就可以不用承担这多少个逻辑,在充足完成目的重用的进程遭到,同时还要达到了职责分开之目标。用户控件的设计者和页面设计者可以互不烦扰,分头完成好的宏图。特别是对页面设计者而言,他得以是单纯的UI设计人士角色,仅得关注用户界面是否赏心悦目及自己,对于代表层中对世界对象的调用与操作就可以不要理会,整个页面的代码也出示结构清晰、逻辑清楚,无疑为“干净”了无数。

表示层设计着极其着重之格局是MVC(Model-View-Controller,即模型-视图-控制器)格局。MVC形式极其早是由于SmallTalk语言研讨团指出的,被广泛应用在用户交互应用程序中。Controller依据用户要(Response)修改Model的性,此时伊夫nt(事件)被点,所有因让Model的View对象会自动更新,并遵照Model对象有一个响应(Response)音信,重临给Controller。MartinFowler在《公司应用架构形式》一挥毫被,显示了MVC情势应用之通通经过,如图6-1所显示: 

图片 294<profile automaticSaveEnabled=”false” defaultProvider=”ShoppingCartProvider”>
图片 295 <providers>
图片 296  <add name=”ShoppingCartProvider” connectionStringName=”SQLProfileConnString” type=”PetShop.Profile.PetShopProfileProvider” applicationName=”.NET Pet Shop 4.0″/>
图片 297  <add name=”WishListProvider” connectionStringName=”SQLProfileConnString” type=”PetShop.Profile.PetShopProfileProvider” applicationName=”.NET Pet Shop 4.0″/>
图片 298  <add name=”AccountInfoProvider” connectionStringName=”SQLProfileConnString” type=”PetShop.Profile.PetShopProfileProvider” applicationName=”.NET Pet Shop 4.0″/>
图片 299 </providers>
图片 300 <properties>
图片 301  <add name=”ShoppingCart” type=”PetShop.BLL.Cart” allowAnonymous=”true” provider=”ShoppingCartProvider”/>
图片 302  <add name=”WishList” type=”PetShop.BLL.Cart” allowAnonymous=”true” provider=”WishListProvider”/>
图片 303  <add name=”AccountInfo” type=”PetShop.Model.AddressInfo” allowAnonymous=”false” provider=”AccountInfoProvider”/>
图片 304 </properties>
图片 305</profile>

图片 306public partial class MasterPage : System.Web.UI.MasterPage {
图片 307
图片 308    private const string HEADER_PREFIX = “.NET Pet Shop :: {0}”;
图片 309
图片 310    protected void Page_PreRender(object sender, EventArgs e) { 
图片 311        ltlHeader.Text = Page.Header.Title;
图片 312        Page.Header.Title = string.Format(HEADER_PREFIX, Page.Header.Title);          
图片 313    }
图片 314    protected void btnSearch_Click(object sender, EventArgs e) {
图片 315        WebUtility.SearchRedirect(txtSearch.Text);    
图片 316    }
图片 317}

代码中,aspnet_Membership_CreateUser为aspnet_regsql工具也membership创制的贮存过程,它的机能就是是创造一个用户。

据此重新写Page_PreInit()方法,是坐Master
Page会在内容页开头化阶段展开联,也即凡是说凡是在PreInit阶段完成Master
Page的分红。
ASP.NET
2.0引入的新特色,并不仅仅限于上述介绍的内容。例如Theme、Wizard控件等新特点在PetShop
4.0负呢得到了汪洋底用。尽管ASP.NET
2.0应声地吐故纳新,对代表层的规划有立异,然则作为ASP.NET
2.0之里一些,它们只是是指向现有框架缺失的弥补与立异,属于“锦上添花”的层面,对于一切表示层设计技术而言,起至之推进成效却大少。

Master Page可以举办嵌套,例如大家成立了父Master
Page页面Parent.master,那么当子Master
Page中,可以利用master属性指定其父MasterPage:
<%@ Master Language=”C#” master=”Parent.master”%>

以比如说NewUser.aspx中针对CreateUserWizard控件的以:

贪图6-2 ASP.NET控件类的层次结构

事件机制刚是observer形式的落实,当ASPX页面的Load事件让激发后,系统通过WebUtility类(在第28节中来对WebUtility类的详尽介绍)的GetCategoryName()方法,获得Category值,并将该出示在页面的Title上。Page对象作为Controller,就吓似一个调停者,用于协调View与Model之间的涉嫌。

6.3  ASP.NET控件

图片 318void Page_PreInit(Object sender, EventArgs e)
图片 319图片 320图片 321{
图片 322    this.MasterPageFile = “~/NewMaster.master”;
图片 323}

图片 324<asp:Login ID=”Login” runat=”server” CreateUserUrl=”~/NewUser.aspx” SkinID=”Login” FailureText=”Login failed. Please try again.”>
图片 325</asp:Login>

由ASPX页面中尚好涵盖Web控件,这多少个控件对象同是用作View对象,通过Page类型对象好对她的支配。例如当CheckOut.aspx页面被,当用户有CheckOut的请后,作为System.Web.UI.WebControls.Winzard控件类型的wzdCheckOut,会在整整向导过程截止时,触发FinishButtonClick事件,并于拖欠事件中调用领域对象Order的Insert()方法,如下所示:

图片 326图片 327public partial class ShoppingCart : System.Web.UI.Page 图片 328{
图片 329
图片 330图片 331    protected void Page_PreInit(object sender, EventArgs e) 图片 332{
图片 333图片 334        if (!IsPostBack) 图片 335{
图片 336            string itemId = Request.QueryString[“addItem”];
图片 337图片 338            if (!string.IsNullOrEmpty(itemId)) 图片 339{
图片 340                Profile.ShoppingCart.Add(itemId);
图片 341                Profile.Save();
图片 342                // Redirect to prevent duplictations in the cart if user hits “Refresh”
图片 343                Response.Redirect(“~/ShoppingCart.aspx”, true);
图片 344            }
图片 345        }
图片 346    }
图片 347}

自前日尚无法预知AJAX技术以未来的走向,不过就从代表层设计之角度而言,AJAX技术同带了同样集全新的变革。我们或好期待将来的PetShop
5.0,可以在象征层设计及带来双重多之大悲大喜。

@Master指令的概念如下:

Page Controller情势是马丁(Martin)福勒在《集团应用架构形式》中极其根本之代表层模式有。在.NET平台下,Page
Controller形式的实现至极简单,以Products.aspx页面也例。首先以aspx页面被,举办如下的安装:

阶段

控件需要执行的操作
要重写的方法或事件
初始化 初始化在传入 Web 请求生命周期内所需的设置。 Init 事件(OnInit 方法)
加载视图状态 在此阶段结束时,就会自动填充控件的 ViewState 属性,控件可以重写 LoadViewState 方法的默认实现,以自定义状态还原。 LoadViewState 方法
处理回发数据 处理传入窗体数据,并相应地更新属性。
注意:只有处理回发数据的控件参与此阶段。
LoadPostData 方法(如果已实现 IPostBackDataHandler)
加载 执行所有请求共有的操作,如设置数据库查询。此时,树中的服务器控件已创建并初始化、状态已还原并且窗体控件反映了客户端的数据。 Load 事件(OnLoad 方法)
发送回发更改通知 引发更改事件以响应当前和以前回发之间的状态更改。
注意:只有引发回发更改事件的控件参与此阶段。
RaisePostDataChangedEvent 方法(如果已实现 IPostBackDataHandler)
处理回发事件 处理引起回发的客户端事件,并在服务器上引发相应的事件。
注意:只有处理回发事件的控件参与此阶段。
RaisePostBackEvent 方法(如果已实现 IPostBackEventHandler)
预呈现 在呈现输出之前执行任何更新。可以保存在预呈现阶段对控件状态所做的更改,而在呈现阶段所对的更改则会丢失。 PreRender 事件(OnPreRender 方法)
保存状态 在此阶段后,自动将控件的 ViewState 属性保持到字符串对象中。此字符串对象被发送到客户端并作为隐藏变量发送回来。为了提高效率,控件可以重写 SaveViewState 方法以修改 ViewState 属性。 SaveViewState 方法
呈现 生成呈现给客户端的输出。 Render 方法
处置 执行销毁控件前的所有最终清理操作。在此阶段必须释放对昂贵资源的引用,如数据库链接。 Dispose 方法
卸载 执行销毁控件前的所有最终清理操作。控件作者通常在 Dispose 中执行清除,而不处理此事件。 UnLoad 事件(On UnLoad 方法)

ASP.NET控件是View对象极其根本之局部,它充裕利用了面向对象的计划性思想,通过包与后续构建一个个控件对象,使得用户以支付Web页面时,能够用那个控件,甚至打定义自己之控件。在第8章中,我早已介绍了.NET
Framework中控件的设计思想,通过引入一种“复合模式”的Composite形式实现了控件树。在ASP.NET控件被,System.Web.UI.Control就是立时棵控件树的一干二净,它定义了有着ASP.NET控件共有的习性、方法和事件,并负责管理和操纵控件的全实施生命周期。

6.4  ASP.NET 2.0新特性

图6-1 典型的MVC模式

图片 348public partial class ShoppingCartControl : System.Web.UI.UserControl图片 349
图片 350       
图片 351图片 352    protected void Page_PreRender(object sender, EventArgs e) 图片 353{
图片 354图片 355        if (!IsPostBack) 图片 356{
图片 357            BindCart();                
图片 358        }
图片 359    }
图片 360图片 361    private void BindCart() 图片 362{
图片 363
图片 364        ICollection<CartItemInfo> cart = Profile.ShoppingCart.CartItems;
图片 365图片 366        if (cart.Count > 0) 图片 367{
图片 368            repShoppingCart.DataSource = cart;
图片 369            repShoppingCart.DataBind();
图片 370            PrintTotal();
图片 371            plhTotal.Visible = true;
图片 372        }
图片 373图片 374        else 图片 375{
图片 376            repShoppingCart.Visible = false;
图片 377            plhTotal.Visible = false;
图片 378            lblMsg.Text = “Your cart is empty.”;
图片 379        }
图片 380    }

图片 381图片 382override protected void OnDataBinding(EventArgs e) 图片 383{
图片 384
图片 385    //Work out which items we want to render to the page
图片 386    int start = CurrentPageIndex * pageSize;
图片 387    int size = Math.Min(pageSize, ItemCount – start);
图片 388
图片 389    IList page = new ArrayList();
图片 390    //Add the relevant items from the datasource
图片 391    for (int i = 0; i < size; i++)
图片 392        page.Add(dataSource[start + i]);
图片 393
图片 394    //set the base objects datasource
图片 395    base.DataSource = page;
图片 396    base.OnDataBinding(e);
图片 397}

6.4.2  Membership特性

以PetShop 4.0遇,建立了号称也MasterPage.master的Master
Page,它含有了header、LoginView控件、导航菜单与用于显示内容之html元素,如图6-3所呈现: 

是因为Profile效能要拜访数据库,由此在数码访问层(DAL)定义了同Product等数据表相似之模块结构。首先定义了一个IProfileDAL接口模块,包含了接口IPetShopProfileProvider:

图片 398图片 399public sealed class DataAccess 图片 400{
图片 401
图片 402    private static readonly string profilePath = ConfigurationManager.AppSettings[“ProfileDAL”];
图片 403图片 404    public static PetShop.IProfileDAL.IPetShopProfileProvider CreatePetShopProfileProvider() 图片 405{
图片 406 string className = profilePath + “.PetShopProfileProvider”;
图片 407 return (PetShop.IProfileDAL.IPetShopProfileProvider)Assembly.Load(profilePath).CreateInstance(className);
图片 408    }
图片 409}

表示层(Presentation
Layer)的统筹可以为系统客户最直白的体验以及最足的自信心。正而人口及人之交相识一样,初次碰面的痛感总是永难忘怀的。一桩交给受客户以的产品,倘使在用户界面(User
Interface,UI)上紧缺吸引人之特色,界面不友好,操作不够珍重,虽然就桩产品性能大优异,架构设计合理,业务逻辑都满足了客户的急需,却仍然难以讨得客户之欢心。俗语说:“佛要金装,人要衣装”,特别是对此Web应用程序而言,Web网页就吓于人口的衣,代表正在布满类此外地点和脸面,是揽客“顾客”的最为深卖点。

图片 410public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
图片 411图片 412图片 413{
图片 414      MembershipUser user1;
图片 415      //后边的代码略;
图片 416      try
图片 417图片 418      图片 419{
图片 420            SqlConnectionHolder holder1 = null;
图片 421            try
图片 422图片 423            图片 424{
图片 425                  holder1 = SqlConnectionHelper.GetConnection(this._sqlConnectionString, true);
图片 426                  this.CheckSchemaVersion(holder1.Connection);
图片 427                  DateTime time1 = this.RoundToSeconds(DateTime.UtcNow);
图片 428                  SqlCommand command1 = new SqlCommand(“dbo.aspnet_Membership_CreateUser”, holder1.Connection);
图片 429                  command1.CommandTimeout = this.CommandTimeout;
图片 430                  command1.CommandType = CommandType.StoredProcedure;
图片 431                  command1.Parameters.Add(this.CreateInputParam(“@ApplicationName”, SqlDbType.NVarChar, this.ApplicationName));
图片 432                  command1.Parameters.Add(this.CreateInputParam(“@UserName”, SqlDbType.NVarChar, username));
图片 433                  command1.Parameters.Add(this.CreateInputParam(“@Password”, SqlDbType.NVarChar, text2));
图片 434                  command1.Parameters.Add(this.CreateInputParam(“@PasswordSalt”, SqlDbType.NVarChar, text1));
图片 435                  command1.Parameters.Add(this.CreateInputParam(“@Email”, SqlDbType.NVarChar, email));
图片 436                  command1.Parameters.Add(this.CreateInputParam(“@PasswordQuestion”, SqlDbType.NVarChar, passwordQuestion));
图片 437                  command1.Parameters.Add(this.CreateInputParam(“@PasswordAnswer”, SqlDbType.NVarChar, text3));
图片 438                  command1.Parameters.Add(this.CreateInputParam(“@IsApproved”, SqlDbType.Bit, isApproved));
图片 439                  command1.Parameters.Add(this.CreateInputParam(“@UniqueEmail”, SqlDbType.Int, this.RequiresUniqueEmail ? 1 : 0));
图片 440                  command1.Parameters.Add(this.CreateInputParam(“@PasswordFormat”, SqlDbType.Int, (int) this.PasswordFormat));
图片 441                  command1.Parameters.Add(this.CreateInputParam(“@CurrentTimeUtc”, SqlDbType.DateTime, time1));
图片 442                  SqlParameter parameter1 = this.CreateInputParam(“@UserId”, SqlDbType.UniqueIdentifier, providerUserKey);
图片 443                  parameter1.Direction = ParameterDirection.InputOutput;
图片 444                  command1.Parameters.Add(parameter1);
图片 445                  parameter1 = new SqlParameter(“@ReturnValue”, SqlDbType.Int);
图片 446                  parameter1.Direction = ParameterDirection.ReturnValue;
图片 447                  command1.Parameters.Add(parameter1);
图片 448                  command1.ExecuteNonQuery();
图片 449                  int num3 = (parameter1.Value != null) ? ((int) parameter1.Value) : -1;
图片 450                  if ((num3 < 0) || (num3 > 11))
图片 451图片 452                  图片 453{
图片 454                        num3 = 11;
图片 455                  }
图片 456                  status = (MembershipCreateStatus) num3;
图片 457                  if (num3 != 0)
图片 458图片 459                  图片 460{
图片 461                        return null;
图片 462                  }
图片 463                  providerUserKey = new Guid(command1.Parameters[“@UserId”].Value.ToString());
图片 464                  time1 = time1.ToLocalTime();
图片 465                  user1 = new MembershipUser(this.Name, username, providerUserKey, email, passwordQuestion, null, isApproved, false, time1, time1, time1, time1, new DateTime(0x6da, 1, 1));
图片 466            }
图片 467            finally
图片 468图片 469            图片 470{
图片 471                  if (holder1 != null)
图片 472图片 473                  图片 474{
图片 475                        holder1.Close();
图片 476                        holder1 = null;
图片 477                  }
图片 478            }
图片 479      }
图片 480      catch
图片 481图片 482      图片 483{
图片 484            throw;
图片 485      }
图片 486      return user1;
图片 487}

于ShoppingCart页面下,我们得以投入该用户控件,如下所示:

以上述的代码中,Profile属性的值从何而来?实际上,在我们也web.config配置文件被针对Profile举办部署后,启动Web应用程序,ASP.NET会按照拖欠配置文件被的有关安排创立一个ProfileCommon类的实例。该类继承自System.Web.Profile.ProfileBase类。然后调用从父类继承来的GetPropertyValue和SetPropertyValue方法,检索和安装配置文件之属性值。然后,ASP.NET将成立好的ProfileCommon实例设置也页面的Profile属性值。由此,我们好透过智能感知获取Profile的ShoppingCart属性,同时也得使ProfileCommon继承自ProfileBase类的Save()方法,遵照属性值更新Profile的数据源。

图片 488<%@ Master Language=”C#” CodeFile=”MasterPage.master.cs” Inherits=”MasterPage” %>

是因为CustomGrid继承自Repeater控件,由此它们以还继承了Repeater的DataSource属性,这是一个虚属性,它默认的set访问器属性如下:

另外,CustomGrid控件类还多了广大属自己之性质和方,例如PageSize、PageCount属性以及SetPage()方法齐。正是因ASP.NET控件引入了Composite模式及Template
Method情势,当大家以由定义控件时,就得经连续和改写的不二法门来形成控件的计划性。自定义ASP.NET控件一方面可依照系统的需要实现特定的功用,也克太丰硕限度地实现目的的录用,既可以减编码量,同时也惠及将来对程序的扩充及改。
当PetShop
4.0受到,除了从定义了上述WebControl控件的分层控件外,最重点的仍然采纳了用户控件。在Controls文件夹下,一共定义了11独用户控件,内容包含客户地址音信、信用卡音讯、购物车音讯、期望列表(Wish
List)消息和导航音信、搜索结果音信等。它们卓殊给是一对结合控件,除了含有了分控件的章程以及性能外,也定义了有些不可或缺的UI实现逻辑。以ShoppingCartControl用户控件为例,它会当该控件被呈现(Render)从前,做片数额准备干活,获取购物车多少,并作为数据源绑定到其下的Repeater控件:

图片 489<%@ Master Language=”C#” AutoEventWireup=”true” CodeFile=”MasterPage.master.cs” Inherits=”PetShop.Web.MasterPage” %>

图片 490public partial class Products : System.Web.UI.Page 
图片 491图片 492图片 493{
图片 494    protected void Page_Load(object sender, EventArgs e) 
图片 495图片 496    图片 497{
图片 498        //get page header and title
图片 499        Page.Title = WebUtility.GetCategoryName(Request.QueryString[“categoryId”]);
图片 500    }
图片 501}
图片 502

Master Page同样利用codebehind技术,以PetShop 4.0的Master
Page为条例,codebehind的代码放在文件MasterPage.master.cs中:

以工作逻辑层(BLL)中,单独定义了模块Profile,它上加了针对BLL、IProfileDAL和ProfileDALFactory模块的先后集。在拖欠模块中,定义了隐秘封类PetShopProfileProvider,它继续自System.Web.Profile.ProfileProvider类,该类作为Profile的Provider基类,用于在打定义配置文件中贯彻相关的布置文件服务。在PetShopProfileProvider类中,重写了父类ProfileProvider中之组成部分法,例如Initialize()、GetPropertyValues()、SetPropertyValues()、DeleteProfiles()等措施。此外,还吧ShoppingCart、WishList、AccountInfo属性提供了Get和Set方法。至于Provider的具体贯彻,则调用工厂类DataAccess创制的有血有肉项目对象,如下所示:
private static readonly IPetShopProfileProvider dal =
DataAccess.CreatePetShopProfileProvider();

六 PetShop之表示层设计

当此间,控件设计使用了Template
Method格局,Control基类提供了大部分protected虚方法,留得其子类改写这格局。以PetShop
4.0啊条例,就定义了区区个ASP.NET控件,它们都属System.Web.UI.WebControls.WebControl的子类。其中,CustomList控件派生自System.Web.UI.WebControls.DataList,CustomGrid控件则派生自System.Web.UI.WebControls.Repeater。

发明6-1 ASP.NET控件的实施生命周期

当装的value对象值不也IList类型时,set访问器就拿捕获卓殊,然后将dataSource字段设置也null。

6.1  MVC模式

PetShop
4.0连从未动Membership的高等级功用,而是直接为Membership特性和ASP.NET
2.0初加的记名控件举办绑定。由于.NET Framework 2.0都定义了针对性SQL
Server的SqlMembershipProvider,因而对此PetShop
4.0而言,实现Membership比的实现Profile要简明,仅仅要呢Oracle数据库定义MembershipProvider即可。在PetShop.Membership模块中,定义了OracleMembershipProvider类,它继续自System.Web.Security.MembershipProvider抽象类。

Profile提供的功力是本着用户之个性化服务。在ASP.NET
1.x本时,大家好采纳Session、Cookie等模式来存储用户的状态信息。但是Session对象是有生存期的,一旦生存期停止,该目的保留的值就是会失效。Cookie将用户音信保存于客户端,它富有自然的安全隐患,一些要的信不可知积存于Cookie中。一旦客户端禁止使用Cookie,则该意义就将去利用之意。

图片 503[AspNetHostingPermission(SecurityAction.InheritanceDemand, 
图片 504Level=AspNetHostingPermissionLevel.Minimal), 
图片 505AspNetHostingPermission(SecurityAction.LinkDemand, 
图片 506Level=AspNetHostingPermissionLevel.Minimal)]
图片 507public interface IHttpHandler
图片 508图片 509图片 510{
图片 511      void ProcessRequest(HttpContext context);
图片 512图片 513      bool IsReusable 图片 514{ get; }
图片 515}
图片 516

可在.NET平台下,我们并不需要自己去落实MVC形式。对于View对象而言,ASP.NET已经提供了常用的Web控件,大家也得以由此持续System.Web.UI.UserControl,自定义用户控件,并下ASPX页面组合Web控件来兑现视图。ASP.NET定义了System.Web.UI.Page类,它分外给MVC形式的Controller对象,能够处理用户之呼吁。由于采纳了codebehind技术,使得用户界面的突显与UI实现逻辑完全分开,也不怕是说,View对象同Controller对象变成相对独立的少数组成部分,从而利于代码的重用性。相比ASP而言,这种编程情势重新符合开发人士的编程习惯,同时方便开发人士与UI设计人士的分工和协作。至于Model对象,则也作业逻辑层的园地对象。此外,.NET平台经过ADO.NET提供了DataSet对象,便于与Web控件的数据源绑定。

出于这简单独控件都转了该父类控件的显示情势,故而,咱们可以经过更写父类的Render虚方法,完成控件的自定义。例如CustomGrid控件:

以PetShop 4.0本子分别襄助SQL
Server和Oracle数据库,由此其分别定义了少于个例外之PetShopProfileProvider类,实现IPetShopProfileProvider接口,并放在两单不同之模块SQLProfileDAL和OracleProfileDAL中。具体的兑现请参见PetShop
4.0底源代码。
同的,PetShop
4.0乎Profile引入了工厂情势,定义了模块ProfileDALFActory,工厂类DataAccess的概念如下:

综观PetShop的代表层设计,丰硕利用了ASP.NET的艺特点,通过Web页面与用户控件控制和显现视图,并动用codebehind技术将业务逻辑层的园地对象在到表示层实现逻辑中,一个超人的Page
Controller情势呼之欲出。

图片 517

合ASP.NET控件类的层次结构如图6-2所著: 

图片 518

要键值为ProfileDAL的价值,正是Profile的工厂类PetShop.ProfileDALFactory.DataAccess在行使反射技术创建IPetShopProfileProvider类型对象时取之。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图