【震驚】中国电信接管CDMA业务,內部FAQ (注意有所括弧的內容)

 

原文:
一、 中国电信CDMA 通知诠释口径     (一)服务重头戏变更
    1.客户:我动用的是CDMA
手机,听说不属于联通了,将来本人利用过程中有题目是你们电信处理啊?
    答:您好! 10 月1 日起CDMA
客户就是中国电信的上流客户了,中国电信将为您提供系数优质的服务!
    (二)联通各渠道截至提供劳动
    2.客户:我是CDMA 客户,为何联通客服让我打你们电信10000 号?
    答:您好,经政坛经理部门批准,自2008 年10 月1
日起,CDMA业务的经纪重点将由中国联通变更为中国电信。由此,二〇〇八年3月1日起,中国电信客户服务热线10000
为CDMA用户提供咨询、查询等人为服务;话费查询等自助服务暂由中国联通客户服务热线继续提供至12月31日。由此给您带来的忙绿,敬请谅解!中国电信将为你提供系数优质的劳动!
    (三)业务服务办理
    3.客户:听说C 网划给电信了,会不会潜移默化我们办理工作和查费缴费?
    答:您好,中国电信和中国联通将严苛按照国家法律法规,共同做好CDMA
业务交易的连续工作,确保CDMA业务和劳务的百色久安过渡,保障广大用户的合法权益。这次过渡中除系统交割期间截止业务办理外另外时间将不会影响你的使用,中国电信对广大用户的支撑和相信表示衷心感谢。感谢您的宽容与帮忙!
    4.客户:电信承接C 网将来,原C
网客户如何是好理工作,查询话费,业务咨询等?
    答:10 月1 日后,中国电信营业厅 、10000 号等足以为C
网客户提供上述服务。假使你有工作问题或投诉可以拨打中国电信10000
号客服热线,大家24 刻钟为您服务。
    (四)充值缴费(联通老卡、电信新卡)
    5.客户:我原是联通C
网用户,一贯采纳联通充值卡,现在转到电信了,原来卡上的通话费是否还可采纳?
    答:1月1日起,您仍可采用四川联通缴费卡为用户帐户充值。中国电信在系统割接后为CDMA用户拔取中国电信缴费卡充值服务,届时,中国联通将适可而止对CDMA号码提供缴费卡充值服务。对于从未充值并在有效期内的陕西联通缴费卡,用户可继承对广东联通GSM号码(130、131、132、155、156)举办充值,或至中国联通指定营业厅举行退、换卡。原来卡上的话费还可利用。
    (五)用户协议
    6.客户:为何不经我我同意,就随意将自我转为中国电信客户?
   
答:依照工业和新闻化部、国家发展和改进委员会、财政部发布的连带文件精神,中国电信向中国联通收购CDMA
业务。经政党经理部门批准,自2008 年10 月1 日起,CDMA
业务的经营重点将由中国联通变更为中国电信,相关服务由中国电信全部承接。
    (六)债权债务
    7.客户:我原先预存的话费和联通赠送的通话费仍是可以连续选用呢?
    答:自2008 年10 月1 日起,由中国电信承接并继承实施CDMA
用户与中国联通原有的用户协议,以及该等协商项下的中国联通原与CDMA
用户的预存话费、赠送话费、积分、欠费、押金等权利和无偿关系。您的预存话费、赠送话费继续有效。
    8.客户:我原先的积分仍可以应用呢?怎么着兑换?
   
答:尊崇的客户您好,自8月1日起CDMA业务老板重点变更为中国电信,您原有的CDMA积分将由中国电信全额承接,我们将为您提供越来越优质超值的积分服务,同时为确保您积分资料的真实和规范,将暂停积分兑换工作,具体的兑换时间和兑换地点另行通知,由此给您带来的劳碌,敬请谅解!
    (七)套餐和支出
    9.客户:我的套餐和特惠还连续有效吗?
    答:经政坛主管部门批准,自2008 年10 月1 日起,CDMA
    业务的经营重点将由中国联通变更为中国电信。原协议未到期的CDMA
套餐或任何优惠(包括短信)仍按原协议履行,协议到期后,您可以重复购置中国电信新的套餐,享受新的优胜。
    二、 资费政策
    (一)原有CDMA
后付费套餐资费政策(含无线上网卡资费)是否继续使用?
    答:在CDMA 用户签订的业务协议到期前,仍旧沿用原有CDMA
套餐资费政策。
    (二)CDMA 用户的无绳电话机补贴政策未到期,是否继续执行?
    答:您现在所拔取的手机补贴政策得以继续执行协议到有效期末。
    (三)新入网的CDMA 用户,是否可以享用原有手机补贴政策?
   
答:自二〇〇八年九月1日起,针对公众客户将动用话费补贴政策替代原有的顶点补贴政策,对公司用户和严重性用户可享用大家现推出的顶峰补贴政策。
   
(四)我资费套餐到期了,是否可以延续套用原来的套餐?假如不可以继承政策是咋样?
   
答:场景1:若原套餐属于精简在售的推广套餐,回答:可以持续沿用;场景2:若原套餐不属于精简在售的放大套餐,回答:原有的套餐已吊销,大家按照你的消费状态为您推荐新的套餐供采纳。
    (五)我的CDMA
租机协议到期了,能否持续办理“二次租机”?假使无法继承政策是何等? CDMA
资费政策有哪些新的变通?
    答:我们对租机到期的老客户可以提供二次租机业务。
    (六)对于CDMA 公免用户,资费政策是否会有照应调整?
    答:按照中国电信有关政策,需要对CDMA
公免用户进行再次认证,若你符合条件,可继续享受中国电信公免用户服务。若您不符合条件,指出你更改为此外开销。
    (七)CDMA 手机能否延续拨打17911 IP 电话?资费标准有变动吧?
    答:如今,您可以继承拨打17911 IP
电话,资费不变。中国电信高效会为你提供 17901 主叫IP 业务。
   
(八)我的资费套餐是拨打国内长途时加拨17911,免收本地通话费,现在是不是还实施原有资费政策?
    答:近期,您可以延续拨打17911 IP
电话,资费不变。中国电信很快会为您提供 17901 主叫IP 业务。
    (九)CDMA 手机用户如何利用中国电信IP 电话,是否优于?
    答:CDMA 手机用户可以利用17901 或17909(南方省份)主叫IP
电话工作,遵照中国电信IP
电话费用打折。但眼前尚不可以运用,估量8月份将绽放意义,具体日子另行公告,欢迎使用。
    (十)我本来套餐中的业务怎么称呼改成了?
    答:CDMA
网络归属中国电信后,原有业务的总经理主体变更,需要对相关事情的实际名称举行变更。名称变更不会潜移默化您的连续采纳,我们会给你提供更好的劳动。(如掌中宽带改为无线宽带、炫铃改为七彩铃音、联通在信改为短信定制、联通丽音改为168、互动视界改为互联星空、神奇宝典改为手机下载、流媒体改为手机电影等。)
   
(十一)我是套餐到期用户,现在想延续办理套餐,怎么发现一些土生土长的事体不可能预订了?
    答:因为CDMA 网络与业务主任主体的变通,中国电信对CDMA
业务套餐举办优化,将为你提供更好的套餐供您选用。
    (十二)CDMA 用户给中国联通GSM
用户发短信、亲友号码通话优惠等的收款标准是否暴发变化?
    答:自2008 年10 月1 日起,CDMA 用户与中国联通GSM
用户之间的通信由网内通信变更为网间通信,资费改为按照网间资费执行。原劳动协议中涉及的有关收费标准在两边系统移交前保障不变。系统移交的求实时间将另行提前告之。
    (十三)国内旅游标准资费有无变化?
   
答:国内旅游标准资费暂无变化,继续执行漫游主叫0.60元/分钟,漫游被叫为0.40
元/分钟,以上专业含国内长途通话费。
    (十四)国际漫游标准资费有无变化?
    答:国际漫游标准资费暂无变化。
    (十五)原中国联通生产的CDMA 预付费如意畅听资费是否继续有效?
    答:
倘诺你在中国电信起初应用中国电信充值缴费卡服务通知时间点此前,已购置的CDMA
如意畅听卡并充值成功的,可以持续利用如意畅听资费。在此之后,将依据中国电信推出CDMA预付费业务充值卡激活套餐举行。
    三、 业务办理
    (一)中国联通营业厅仍是可以够办理CDMA 业务呢?
   
答:自二零零六年1月1日起,中国联通营业网点将继承为CDMA用户提供咨询、缴费、业务办理等有关服务。
   
自二〇〇八年十月1日起,中国联通营业网点截至为CDMA用户提供咨询、业务办理等劳动;同时继续为CDMA用户提供缴费和自助服务,直至中国电信系统割接后结束服务。
    (二)中国电信营业厅哪一天可以办理CDMA 业务?
   
答:自二〇〇八年十月1日起,中国电信营业厅将为CDMA用户提供咨询、缴费、业务办理等有关服务。
    (三)中国电信营业厅具体地点在哪个地方?
    答:(注:请10000号人士直接询问后报告客户。清单请家客部提供。)
    (四)中国电信网上营业厅何时为CDMA
用户提供劳动?中国联通网上营业厅还提供对应CDMA 业务服务呢?
   
答:自二零零六年1月1日起,中国电信网上营业厅将向CDMA用户提供业务介绍、咨询等劳务。
   
自二零零六年10月1日起,中国联通网上营业厅将持续向CDMA用户提供业务介绍、咨询等劳动。
   
自二〇〇八年十二月1日起,中国联通网上营业厅停止向CDMA用户提供工作介绍、咨询等劳务,同时继续为CDMA用户提供查询服务,直至中国电信系统割接后终止服务。
    (五)中国电信短信营业厅什么时候为CDMA
用户提供服务?中国联通短信营业厅还提供对应CDMA 业务服务啊?
    答:如今两者省公司正商定中,具体日子另行通知。
    (六)CDMA 预付费业务还足以拨打1013388 办理相关事务呢?
    答:目前,您仍可以拨打1013388
办理有关作业(如添加亲情号码、来话筛选等)(系统割接后另行公告)。
    (七)我的CDMA 手机坏了,去什么地方举办售后保修?
   
答:1、用户可以自行采用华盛公司(现中国电信终端公司)售后服务网点或厂商授权的本地社会维修点联系处理。具体详尽附件1。
   
2.对此县区用户,若当地尚未相关售后网点,可以去中国电信县营业厅联系处理。
   
(八)我原本的客户主管仍可以继承为自身办理有关事情呢?有新的客户老董为自我提供服务呢?
    答:随着CDMA
网络与事务经营重点的改动,与其相关的人手也会暴发变化,因而,您事先的客户总经理可能不再为你提供相关服务。我们会安排新的客户总裁,他会积极与你取得联系。
    四、 业务使用
    (一)电信收购C 网后,用户是否要换号?
    答:不需要更换手机号码。
    (二)CDMA 用户是否可以申请双模卡业务呢?
    答:自2008 年10 月1 日先河,中国电信将临时截止受理CDMA
用户双模卡的报名,并将在适当的时候提供新的双模卡业务,请你保持关注。
    (三)原中国联通CDMA 双模卡用户能够继续使用么?
    答:原中国联通CDMA 双模卡用户可以继承运用原来各项工作和效果。
    (四)原中国联通CDMA 双模卡用户的费用标准是否暴发变化?
    答:原中国联通CDMA 双模卡用户的开支标准,在2008 年10 月1
日从此保持不变,直至用户与原中国联通的磋商期限到期。
    (五)双模卡丢失后,可以补办一张新的双模卡吗?
    答:不可以。只可以补办一张CDMA 单模卡。
    (六)原中国联通CDMA 双模卡用户的交款地点是否发生变化?
   
答:自二零零六年三月1日至中国电信系统割接,中国电信将承载原中国联通提供的CDMA
网络及劳动,原中国联通CDMA
双模卡用户既可到中国电信的缴费网点拓展缴费,也可到中国联通的交款网点举办缴费。
    (七)请问已开展CDMA 国际漫游的国度有咋样?
    答:CDMA 在17
个国家和地面可以拓展国际漫游:Hong Kong、阿里格尔、扶桑、甘肃、大韩民国、泰国、印度、印度尼西亚、越南、关岛、加拿大、美利坚同盟国、巴西、墨西哥、澳大喀布尔、新西兰、以色列。
    (八)10 月1 日从前入网的CDMA 用户是否需要更换UIM卡?(徐国富)
    答:不需要。老用户采纳原UIM
卡仍可正常使用话音、点对点短信等各项事情,可是有局部增值业务或者不能继续接纳。
    (九)原来的充值卡是否可以持续利用?
   
答:二〇〇八年1月1日起,133/153用户仍使用陕西联通缴费卡为用户帐户充值。中国电信在系统割接后为CDMA用户拔取中国电信缴费卡提供充值服务,届时,中国联通将适可而止对CDMA号码提供缴费卡充值服务。对于没有充值并在有效期内的浙江联通缴费卡,用户可连续对甘肃联通GSM号码(130、131、132、155、156)举行充值,或至中国联通指定营业厅进行退、换卡。
    (十)在通知后不曾利用的充值卡能够怎么处理?
   
答:对于从未充值并在有效期内的甘肃联通缴费卡,用户可继承对广东联通GSM号码(130、131、132、155、156)举办充值,或至中国联通指定营业厅举行退、换卡。
    (十一)原中国联通用户的UIM 卡是否足以在中国电信的定制手机中运用?
    答:可以,中国电信定制的无绳电话机均经过与原中国联通用户的UIM
卡兼容性测试。
    (十二)中国电信发行的UIM 卡是否可以在原中国联通的CDMA
定制手机中采取?
    答:可以,中国电信发行的UIM
卡均经过与原中国联通CDMA定制手机兼容性测试。
    (十三)使用中国电信发行的UIM 卡与原中国联通发行的UIM 卡有何区别?
    答:使用中国电信发行的UIM
卡与原中国联通发行的UIM卡,均可以健康使用话音、点对点短信等各样事务,但是在卡菜单中提供的一些业务有所差异。
    (十四)CDMA 后付费用户/准预付费用户今后怎么着行使充值卡缴费?
   
答:二〇〇八年十月1日至中国电信系统割接,133/153用户仍采纳青海联通缴费卡(除C网专用缴费卡外)为用户帐户充值。中国电信在系统割接后为CDMA用户提供中国电信缴费卡充值服务。
    (十五)CDMA 预付费用户(如意133 用户)今后如何运用充值卡缴费?
   
答:二〇〇八年2月1日至中国电信系统割接,133/153用户仍使用海南联通缴费卡(含C网专用缴费卡、G/C混合缴费卡)为用户帐户充值。中国电信在系统割接后为CDMA用户接纳中国电信缴费卡提供充值服务。
    (十六)CDMA 用户能够在他乡购买充值卡进行充值或缴费么?
   
答:近年来,CDMA用户可以购买地方陕西联通充值缴费卡对吉林CDMA用户(预付费和后付费充值范围见上)举行异地充值,中国电信发行的充值缴费卡使用验证另行布告。
    (十七)中国电信的充值电话号码是什么样?
   
答:(注:系统割接后)中国电信的充值电话为11888,包括后付费与预付费CDMA
用户的充值服务。
    (十八)中国电信CDMA 用户的IP 电话对接号码是咋样?
    答:(注:系统割接后)中国电信CDMA 用户的IP 电话对接号码为17901。
    (十九)中国电信CDMA 用户的长距离减价接入码是咋样?
    答:(注:系统割接后)中国电信CDMA 用户的中距离让利接入码为11808。
   
(二十)我原来定制的增值业务是否可以继续使用?定制形式是否暴发变化?(联通在信、掌上股市、彩E、WAP、IVR、如意邮箱等)
   
答:原有定制增值业务的效劳可以连续采用,但各自工作因合作伙伴退出将不能提供劳务,届时中国电信将以短信通知用户。裁撤/定制情势在交接期间均不会发生改变。
    (二十一) 我的CDMA 手机上的热键和法力菜单还是可以够继承行使呢?
    答:可以继续应用,其相应的效用不变。
    五、 客户权益
    (二十二) 电信新生产XX
增值业务,在自我的无绳电话机上无法定制,该怎么化解?
    答:某些增值业务如备份工作,初期只针对189
用户开放,待系统割接完成后,将对133、153 用户开放。
    (二十三) CDMA 短信增值业务定制是否还需要用户的“二次确认”?
    答: CDMA 短信增值业务定制需要用户上行短信举办“二次认同”。
    (二十四) 原CDMA 用户可以通过拨打10150
举办炫铃业务开展与铃音的变换吗?现CDMA 用户咋样开展七彩铃音业务?
   
答:原CDMA用户和现CDMA用户在过渡期均可拨打10150展开炫铃业务的开展、销户、定制及铃音管理。
    (二十五)
已在联通系统开通炫铃业务,已定制的炫铃歌曲现在并未了,为何?
   
答:请核实您购买的铃音是否已到有效期,若未到有效期,可能因为系统割接造成,大家透过审定后,将按照你的渴求为您免费提供一首新歌。
    (二十六) 原开明的中国联通10198
秘书服务,现在是否能延续提供劳动?
    答:原中国联通10198 秘书服务将由118114
号码百事通继续为您提供劳务,服务内容和收费标准不变。(注:割接日后,联通秘书服务10198接入码将会暴发变化。具体内容另行通知)
    (二十七) 大家单位接纳C 网和G
网手机的都有,互相之间只要拨短号就能打电话,话费还不行有利于。C
网归电信后,原有的应用格局与优化仍能保存吗?
   
答:福建电信和江苏联通将妥善处理CG混合虚拟网的拆分工作,在规范拆分前,会向公司客户单位联络员发送公告函,并会由此短信向用户通报,用户在尚未吸收公告前,CG混合虚拟网的效用和让利政策暂不会转移。陕西电信与浙江联通完成系统割接后,将对现有的CDMA进行优化、扩容、升级、改造,并将为客户量身定做依照固话、小灵通和CDMA
业务综合组网方案,为客户提供越来越灵活、促销的资费套餐与便利的利用办法,满意客户新的通信需求。贵单位可以遵照实际使用意况选用适合的套餐。
    五、 客户权益
    (一)与联通签订的用户协商还未到期,是否继续有效?
    需要与电信重新协定用户协议呢?
    答:您所签订的用户协商持续有效。随着CDMA
业务老总重点变更,中国电信将自行承接您与中国联通原有的用户协议,不需要与中国电信双重签订协议。
    (二)我与联通签订的用户协商还未到期,能否提前终止协议?
   
答:如原协议中已预约协议提前截止条款,则按协议约定履行。如原协议中从未预定的,则不可以提前截止协议(除不可抗力因素),若客户单方面终止协议,要各负其责协议中约定的违约责任。
    (三)我是联通133
租机用户,前年说道才到期,请问我的押金/保证金如何退还?
   
答:协议到期后,若按协议约定符合退还押金条件的用户可以辅导押金/保证金收据、有效身份证件到指定中国电信营业厅办理押金退还。
    (四)原联通承诺的馈赠话费是否继续有效?
   
答:原中国联通答应的捐赠话费继续有效。(各省注意,在实际操作中所承诺的话费以系列赠款账户记录的多少为准,智能网SCP
系统预存款账户中的赠款以赠款文件和赠款记录为基于。)
    (五)我的预存款是否可以继承利用?
    答:CDMA 用户的预存款继续有效。
    (六)我是133
/153用户,与130编号(或任何联通号码)合并帐单,并由自己133/153数码统一付费,请问,该帐单下的预存款怎么处理?以后是否还足以由我联合付费?
    答:您是主付费帐户,C、G
合并帐单分拆后,预存款余额将保存给你,但您不得以再为G 网号码付费了。
    (七)我是133 /153用户,与某130
号码(或其他联通号码)合并帐单,并由该130数码(或另外联通号码)统一付费。现130
号码(或任何联通号码)上有预存款,为啥自己的数码会停机?
    答:对于G、C
两网统一帐单的,需要开展帐单拆分。拆分后预存款余额保留在主付费帐户并用于其连续消费。因您的133号码非主付费号码,帐单拆分后你的手机上尚未预存款,但对于拆分后24钟头内,无论你各号码的账户余额多少,咱们将保险你健康使用,为力保你将来连续可以正常使用,请你及时查询各号码的余额,并为余额不足的数码缴费。
    (八)咋样办理G、C 两网联合帐单拆分?
    答:2008 年10 月1 日往日,您可以到中国联通营业厅办
    理C、G 两网合并帐单的拆分。
    (九)CDMA 用户的信用额度是否会有变动?
    答:CDMA
用户的信用额度和授信规则暂时不会暴发变化。(注:各省关注本地CDMA
用户的信用额度和授信规则,并搞好培训)
    (十)CDMA 用户原本的积分是否延续有效?
    答: 您的积分在有效期内连续有效。
    (十一)咋样举办积分的询问?
   
答:您可以因此中国电信营业厅、客户服务热线10000/10001、网厅等渠道展开积分的询问。
   
    (十二)是否足以拓展积分兑换?通告
   
答:从二零零六年五月1日起至系统割接完成前,CDMA用户的积分规则保持不变,用户可到当地中国电信营业厅举行查询。在系统割接完成后,中国电信将为期或不定期开展积分兑换活动。
    (十三)积分有效期是否暴发变化?
    答:近期,您的积分有效期不发生变化。
    (十四)2008 年10 月1 日后,原联通客户俱乐部会员卡是否管用?
    答:您的客户俱乐部会员卡将持续有效至有效期末,若您的会员卡在2008
年10 月1 日至12 月31 日里面到期,可延长有效期至2008 年12 月31 日。
    (十五)原联通飞机场/火车站藏粉红色通道是否对CDMA 会员开放?
    答:原中国联通地面银卡以上及外地金卡以上的CDMA
会员可以继续选用中国联通飞机场/火车站黑色通道。(注:按照中国电信与中国联通缔结工作转让详细协议。)
    (十六)CDMA 会员在原联通公司服务联盟消费是否享受原有促销政策?
    答: CDMA
会员可以使用原联通公司服务联盟。(注:按照中国电信与中国联通签订工作转让详细协议)
    (十七)原联通俱乐部会员服务标准是否暴发变动?
    答:2008 年10 月1 日过后,原中国联通CDMA
会员服务由中国电信承担承接,会员服务专业按中国电信会员服务规范举办(详见公司新颁发的《过渡期CDMA
客户服务标准》)。注:《过渡期CDMA 客户服务规范》尚未下发
   
(十八)原联通俱乐部会员,漫游至另外城市或地区,请问是不是仍可以动用外地飞机场/火车站等黑色通道?
   
答:原联通俱乐部钻石卡、金卡会员可以利用外地飞机场/火车站等青色通道。(注:暂时互不结算。)
    (十九)原中国联通CDMA
俱乐部会员可以采取中国电信飞机场贵宾休息室吗?
    答:现有中国电信飞机场贵宾休息室对原133、153
用户开放,服务目的为原本地金卡以上会员及外地钻石卡会员,服务内容与服务专业按中国电信现有服务内容与业内举行。
    六、 客户服务
    (一)CDMA 客户是不是可以持续拨打联通10010
进行提问、投诉?是否收费?
   
答:自二〇〇八年3月1日起,中国联通客户服务热线10010/10011将持续为CDMA用户提供咨询、查询等人为服务及自助服务,
直至八月31日止。
    从十月1日起到中国电信系统割接,CDMA 用户拨打当地10010
号是免费的,若在当地加拨区号拨打异地10010号需要收取国内长途通话费,若漫游状态下加拨区号拨打归属地或任什么地方方10000
则另需收取漫游通话费。
    (二)C 网用户拨打中国电信10000 是免费的吗?
    答:CDMA 用户拨打当地10000 号是免费的,若在地头加拨区号拨打异地10000
号需要接受国内长途通话费,若漫游状态下加拨区号拨打归属地或其他地点10000
则需要收费漫游通话费。
    (三)10000 能提供什么服务?
   
答:中国电信客户服务热线10000可以为CDMA用户提供咨询、查询、业务办理、投诉处理等电信服务。
    (四)CDMA 用户在出境游状态下,是否足以拨打当地10000
号举行工作咨询或投诉?
   
答:CDMA用户在观光状态下直接拨打10000,我们将遵照你所提的题目及授予解决。(区别处理:①省内巡游用户拨打10000登时处理;②省外旅游用户拨打当地10000,简单业务咨询等得以回答的直接回答,答复或解决不了的请用户拨打码号归属当地区号+10000,由地点受理处理;③国际漫游用户可以免费拨打13010199999
CDMA国际漫游客户服务电话。)
    (五)CDMA 用户在观光状态下,是否足以拨打归属地10000
号举行工作咨询和投诉?
   
答:CDMA用户在观光状态下,可以拨打归属地10000,我们将按照你所提的题材,随后予以解决。(注:如若CDMA用户在旅游状态下拨区号+10000,则连接该区号所在地客户服务热线,收取漫游费,所提问题由该客户服务热线负责最后化解。)
    (六)CDMA 用户是否可以继承拨打10109696 进行增值业务投诉?
    答:您可以拨打中国电信客户服务热线10000,由其为你提供SP
业务的询问、定制、撤消等服务。同时你还可以够拨打中国联通SP
服务监督电话10109696,提供有关服务。
    (七)原在中国联通总部和省分行的网站上得以查询SP
厂商音讯,包括服务提供商的商店名称、业务名称、业务描述、资费描述、客户服务电话、服务接通代码等,现在事关SP
厂商的信息在何处可以查询?
    答:遵照SP 合作协议签约的速度,在省集团及公司网站上分批举行公布。
    (八)联通“话费差错,双倍返还”的答应是否延续有效?
   
答:“话费差错、双倍返还”仍将延续有效(不要对用户积极宣传)。(注:话费差错即对移动电话业务中存在的“错收的超长超短话单”、“不该收费的口音指示和免费电话”、“未按工作办理单据中客户采用的业务费用标准收费”、“错收的短信定制业务音信费”等四项计费误差举行双倍返还。“双倍返还”的定义是“错一,还一,赔一”。)
    (九)CDMA 用户投诉处理期限是稍微?
    答:一般投诉:即时回答,最长不超越24 时辰;省级投诉:平均24
时辰回应,最长不领先48 刻钟;全国级投诉:平均48钟头回应,最长不超越72
刻钟。申诉处理不超过7 个工作日。
    (十)各省级公司是否设立劳务质地监控举报电话?
    答:各省由客户服务热线10000 承担服务质地监督举报的任务。
    (十一)CDMA 用户能否拨打全国服务质地监控举报电话
    010-66504315 实行投诉?
    答:用户可以拨打010-66504315
举办投诉。您可以拨打10000开展相关业务投诉(注:4008810000
暂不对外广泛宣传,可以指引用户至10000
号,假设客户必须要总部的投诉电话,能够告知客户拨打4008810000
举行有关作业投诉)。
    (十二)CDMA 国际漫游服务号码是哪些?是否免费拨打?
   
答:CDMA用户国际漫游时得以免费拨打13010199999国际漫乘客户(境外)服务热线举行咨询和投诉。
    (十三)原中国联通CDMA 用户出国前需要编制好短信“PRL”发
    送到165 更新UIM 卡PRL 列表(0.1 元/条),今后是否还亟需更新UIM 卡PRL
列表?
    答:CDMA
用户在出国前需要到营业厅开通国际漫游权限后,并由用户编辑短信“PRL”发送至165,举办PRL
列表更新。
    七、 增值业务
    (一)七彩铃音业务(原炫铃业务)
    1.七彩铃音是什么样?
   
答:七彩铃音业务是一项由被叫客户为呼叫自己移动电话的另外主叫客户设定特别音效
( 音乐、歌曲、故事情节、人物对话等 )
的回铃音的事务,即:在三回电话呼叫过程中,被叫客户摘机应答前,主叫客户听到的将不再是枯燥的
“ 嘟 …嘟 …”
普通的回铃指示音,而是被叫客户已经定制好的个性化的特种音效的回铃音。
    2.咋样申请七彩铃音业务?
   
答:过渡期本机拨打“10150”,依据指示后开展注册或本地拨打10000,由客服人士为您举行开通。
    3.七彩铃音业务怎么收费?
   
答:七彩铃音业务使用“功效费+新闻费”的样式展开收费。效能费按月吸收,音信费取决与所定制的铃音。以下是七彩铃音的开支标准:
    收费项目 收费标准
    铃音新闻费 不领先3
元/首,铃音包月租费不超过10元/月。注:过渡期沿用原资费个人彩铃月租每月3元/月,公司客户依照具体签订协议约定;过渡期后费用将再次发表。
    功能费 5 元/月
    用户定制暴发的短
    信费、流量费 短信:0.1 元/条
    WAP:按流量费标准
    4.自家怎么选取自己欢喜的七彩铃音?
    答:您七彩铃音开户成功后假设没有进展七彩铃音设置,
   
那系统会自行为您提供一首默认铃音。过渡期您可经过本机拨打10150依据提醒进行七彩铃音设置,采纳你喜爱的七彩铃音。189用户可记名七彩铃音网站http://
www.118100.cn(WEB 登录) 或http://
    wap.118100.cn(WAP 登录) 或用手机平昔拨打 118100
举办七彩铃音设置,选用你喜欢的七彩铃音 。
    5.安装七彩铃音播放顺序?
    答:近期七彩铃音设置条件共 2 种
    1)设置默认铃音:分为单选,或多选几种,多选的铃音可以循环播放;
   
2)设置群组铃音:能够给你的爱人设置独立播放的铃音,它的预先于你此前安装的默认铃音播放。
    6.铃音版权是否享有有效期?
   
答:为了更好的保安文化产权和血脉相通版权人的补益,七彩铃音业务的每首铃音都标注了有效期,该有效期是内容提供商从相关版权人处得到的该七彩铃音作品的有效许可使用年限。使用七彩铃音业务的客户将七彩铃音音乐下载入
” 个人铃音库 ”
后,只要不删除,且未到达该七彩铃音音乐版权的有效期,即可使用;若该七彩铃音音乐版权有效期限届满,则被删去且被系统设置默认的七彩铃音音乐代替,但在客户成功撤销” 七彩铃音 ”
业务前,将延续按照预约标准缴纳七彩铃音业务的月功用费。到期后的铃音已从曲库中删去,需内容提供商重新上传后,用户重新定制才得以应用。
    7.我记不清自己本来安装的密码,该肿么办?
   
答:过渡期客户忘记密码能够透过登录网站http://www.xl.ah165.net的遗忘密码按钮来收获密码。首先在首页左面输入客户手机号码,再点击获取密码按钮,七彩铃音系统将会以短信的主意来把作业密码发送到客户手机上。189用户可以透过中国电信七彩铃音网站首页的遗忘密码按钮来赢得密码。
    8.哪些是默认铃音、群组铃音?
    答:默认回铃音,每个七彩铃音用户可以安装一条默认回铃音,当有用户 A
呼叫七彩铃音用户时,假如没有为用户 A
找到个人回铃音和群组回铃音,系统将给用户 A
播放默认回铃音。群组回铃音,七彩铃音用户可以建立一个群组,并将一些对讲机添加到该群组中,然后能够为该群组设置群组回铃音,当群组内的电话机呼叫该七彩铃音用户时,系统将播放群组回铃音。
    9.自己举行了销户、改号的作业变更时是否需要重新申请七彩铃音?
    答:是。当你举行了销户、改号时,需要再行申请七彩铃音业务。
    10.自己主动报停或者欠费停机复机后,是否需要再行申请七彩铃音?
   
答:不需要。当您复机后不要重新申请即可享受七彩铃音业务。且报停或欠费停机期间不会收到您的七彩铃音月租费用。
    11.自家打朋友的电话,一听到歌曲,是否曾经收费了?
   
答:在您拨打的客户未接听电话在此之前,都是不收费的,当对方接通电话,即起来收受通话费。
    12.七彩铃音包含哪些回铃音内容?
   
答:七彩铃音回铃音重要不外乎歌曲、乐曲、自然音效(如鸟鸣)、公司七彩铃音和
DIY 等,假设回铃音长度很短,将给予重复播放。
    13.七彩铃音业务设置上有哪些基本功用?
    答:近年来七彩铃音业务设置上有以下基本功用:
   
(1)按主叫号码设置回铃音:可针对不同主叫号码或号码组播放不同的回铃音;
   
(2)提供缺省回铃音:假使不开展专门设置,主叫客户听到默认回铃音,客户可更换默认回铃音;
    (3)网站订购铃音:通过拜访七彩铃音网站来预订自己的铃音。
   
(4)客户密码修改:客户到地面营业厅或登录七彩铃音网站修改个人密码;
   
(5)客户密码得到:客户在网站上定购铃音和改动自己的铃音设置时,需要输入自己的密码,如若客户忘记密码,可以经过网站首页的
“ 忘记密码 ” 来再度得到,系统会由此短信发送密码到客户的无绳电话机上。
    14.得以经过祥和的手机为朋友设置七彩铃音吗?
    答:不可以,过渡期拨打10150拓展铃音设置(过渡期后拨打 118100)
举办铃音设置时只能使用本机举行操作。但可通过本机为外人赠送铃音,即为旁人付出某首铃音的音讯费,以上操作可在七彩铃音网站上实现。
    15.假诺本人想赠送某个七彩铃音给某个朋友,可以呢?
   
答:要是您想把你的某个七彩铃音给一定的意中人(该对象必须是七彩铃音用户),你可以直接在你的私家铃音库中采取这些铃音的赠与,然后输入要捐赠的数码,即可赠送。一旦赠送,所需音讯费用由你出资,而你的情侣不付任何费用。
   
16.节日七彩铃音/分组七彩铃音/间段七彩铃音/缺省七彩铃音有怎么样区别?
   
答:当你选拔了多种七彩铃音业务时,它们播放的预先顺序为:回忆日七彩铃音
> 分组七彩铃音 > 时间段七彩铃音 >默认七彩铃音;*
默认七彩铃音:除了您设置的“时间段和节日”,并且除了你设在“分组七彩铃音”里的编号,当有人拨打你的无绳电话机时将听到这多少个七彩铃音音。
    * 时间段七彩铃音:您可以安装8
个时间段。除了设在你“分组七彩铃音”里的号子,其他设在你时间段号码里的人拨打你的无绳电话机时将听到这些七彩铃音音。
    * 分组七彩铃音:您可以设置8 个分组,每组最多可安装20
个电话号码。您可以将多少个不等的电话号码设在同样主叫组中,然后为该主叫组设置分组七彩铃音,该组中的朋友拨打你的无绳电话机将听到同样的七彩铃音。
    * 记念日七彩铃音:您可以设置5
个节日七彩铃音,为你生活中特意的小日子扩大色彩。在这些特另外小日子里,所有拨打您手机的人,都将听到你特别设置的七彩铃音!
    18.自身登记了七彩铃音业务,为啥登录网站指示我从不登记?
    答:您的七彩铃音业务或者仍在登记中,请耐心等待,借使24
时辰仍力不从心登陆,请向10000 咨询,客服人士会帮你处理。
   
19.用户铃音库能够存放多少首七彩铃音和音乐盒?铃音库满了后还想购买新的七彩铃音或音乐盒如何做?
    答:过渡期用户铃音库能够存放10 首七彩铃音歌曲或铃音盒。
铃音库满将来,需要删除当前铃音库中的七彩铃音或音乐盒才能再购买新的七彩铃音或音乐盒。
    20.如何是铃音编组?铃音编组有什么效劳?
   
答:七彩铃音系统增添了铃音编组功效,用户可以友善将铃音库中的歌曲成立成不同的铃音编组,每用户可以创造5
个不同的铃音编组。
每个铃音编组可以看成一个完整,设置成为“默认七彩铃音”、“时间段七彩铃音”、“分组七彩铃音”或记忆日七彩铃音等。
    21. 咋样设置七彩铃音?
   
答:过渡期您需要本机拨打10150,按指示举行安装。过渡期后您可以本机拨打七彩铃音业务接入码118100
进入语音管理您的选择。您可以为每条铃音添加主叫号码,未来那么些编号的主人拨打你的电话机时,就会听到你特别设定的动听的音乐呀。您还可以登录七彩铃音业务网站,举办更多的铃音采纳。系统为您提供各种新型流行音乐、古典音乐、超人气排名榜的上榜音乐,让拨打你电话的爱侣时时感受到你特此外品尝。
    22.忘了安装七彩铃音肿么办?
   
答:没关系,系统现已为您设置了默认铃音。您成为七彩铃音用户后,尽管没有为来电设置七彩铃音,系统将应用默认的七彩铃音。
    23.什么注销七彩铃音?
   
答:没问题,过渡期您可以本机拨打10150依照语音提醒,拔取注销即可。过渡期后拨打七彩铃音业务接入码118100(或登录七彩铃音业务网站),选拔注销即可。注销七彩铃音业务成功后,自下个月起,将不再收取七彩铃音效能费和铃音音信费。
    24.如何是七彩铃音的分组功用?
   
答:您可以把把不同主叫号码分成不同的组,不同的组可以安装不同的铃声,这样您就足以让不同的心上人在拨打您的手机时听取不同的回铃音,分组效用对所有用户所有默认开通。
    具体数额分配为:默认铃音可设置1
个(不切合所有安装规范时播放),除默认分组外您还足以设置5 个分组。
    25.铃声的版权期限为多长期?
   
答:每一首七彩铃音都有自然的版权有效期,在您购买定制后,参与“我的七彩铃音”,只要不删除,且未到达七彩铃音的版权有效期,即可长时间拔取,若到达版权有效期限,中国电信有权将该铃声以体系默认铃声代替。
    26.怎么申请了七彩铃音业务而对方没有听到音乐铃声?
   
答:1)假如七彩铃音用户呼叫转移到任何没有七彩铃音业务的号码上时,此时该用户的七彩铃音业务无法启动,主叫方听正常回铃音;
    2)系统升级或网络拥堵时长期内临时听不到七彩铃音。
    27.主叫用户听七彩铃音时收通话费吗?
   
答:七彩铃音是把原来传统的回铃音用其余音源代替,由此,在尚未打电话前,主、被叫用户都不会收通话费。
    28.是否落实漫游播放?
   
答:可以。在你环游到其他城市时,您的七彩铃音业务仍旧有效,外人拨打你的电话时,将听到你设置的七彩铃音。
    注:具体情状以本地为准
    (二)手机炒股业务(原掌上股市业务)
    29.什么样是手机炒股?
    答:中国电信手机炒股业务属于中国电信自有品牌的全国级SP
业务,该工作通过中国电信C
网终端提供给客户移动炒股的功用,可以让用户能随时随地举行行情浏览和股票交易。
    30.手机炒股都有些什么内容?它能给自己带来怎样利益?
   
答:手机炒股业务可以提供三大证券类服务:证券交易、行情揭发、咨讯服务。手机炒股业务提供的意义利用更强有力:用户可透过BREW
客户端模式、WAP
形式等落实业务下载开通、定制使用、裁撤业务等;作为第二种非现场交易格局,提供实时行情、资讯查询以及安全的在线交易服务。手机炒股业务的劳务更规范:获上证、深证交易所行情服务使用授权;由专业财经资讯公司提供音信;全国20
家以上大中型券商帮忙手机炒股业务,实现券商自选完成在线交易服务。
    31.怎么着是证券交易效率?有些咋样新的情节?能给自家带来什么样便宜?
   
答:证券交易功用是指:移动用户通过动用协理交易功用的数据传输通道,把自己证券交易的乞请提交到券商端,由券商按照移动用户的命令展开证券交易的为主业务处理,实现与真正的营业厅类似的各种证券交易效能。
    考虑到证券交易安全保密特性的渴求,手机炒股业务的证券交易成效基于BREW
客户端的无线数据业务实现情势,证券交易的交互过程也仅在移动用户和券商端之间开展,不在其他网元中诞生,保证了用户的老本安全。
    32.什么样是行情揭露意义?有怎么着特点?能给自家带来怎么样好处?
   
答:行情揭发意义是指:手机炒股业务体系经过自然的法门引入证券交易所的行情新闻,并经过一定的适配工作,以BREW客户端/WAP
情势展开披露。中国电信手机炒股业务系统经过一定的艺术收取来自上交所、深交所的原有行情数据,并在用户终端对数码开展本地化处理后予以映现。
    33.怎么样是信息服务成效?有怎么着特点?能给自家带来怎样好处?
   
答:资讯服务效益是指:券商或音信提供商利用中国电信手机炒股业务所提供的报导通道,把证券资讯音信发送到电信手机炒股业务类别;用户通过行使有关的数额传输通道,把团结情报服务的哀告提交到手机炒股业务系统,获取相关的有价证券资讯信息。手机炒股业务的证券资讯信息来源券商或相关信息提供商。
    34.行使手机炒股软件拓展交易安全呢?
    答:安全。手机炒股业务的交易效用利用了CDMA 1X
技术中的军用安全加密技术,因而能确保交易过程的全程加密,安全性很高。同时,在客户交易的长河中不在第三方平台落地,整个经过只发生在用户和券商之间,排除了第三方平台盗取交易音讯的或是。
    35.应用手机炒股业务得到的信息和有价证券营业部的信息同步啊?
    答:同步。手机炒股业务建立在CDMA 1X
网络之上,其数量传输速率达到了153.6K,完全能确保客户一同得到股市行情和资讯。
    36.手机炒股业务的利用习惯和PC 版的炒股软件有哪些两样啊?
    答:没有两样。手机炒股业务的用户体验完全按照现有流行的PC
版炒股软件拓展规划,由此双方基本一致,用户无需举办超常规学习即可使用。
    37.手机炒股业务支撑多少家券商?
    答:100 家以上。手机炒股业务现已基本覆盖国内所有的主流券商。
    38.手机炒股业务的开支状况怎么着?
   
答:手机炒股业务使用“流量费+消息费”的花样展开收费,业务提供计次和包月二种费用连串。流量费建议采纳按流量收取,遵照用户所拔取的例外流量套餐而定,和手机炒股业务无直接关联;信息费取决于用户采用的套餐。不同应用办法的资费提出如下:
    收费项目 收费标准 是否与合作伙伴分成 表达
    信息费 WAP
    包月:不高于10 元/月;按次:不高于10 元/月
    是 信息费
    BREW
    ( 只有包
    月格局) 行情揭破/ 咨讯服
    务:15 元/月证券交易:
    30 元/月 是
    流量费 WAP:按流量费标准 否
    用户定制爆发的通
    信费
   
    39.如何办理手机炒股业务?
    答:过渡期间,如若你采取的是BREW
客户端模式的工作可以经过一贯下载、安装客户端软件开通相靥撞停绻≡竦氖荳AP
情势的作业可在中国电信WAP 门户办理。
    40.自我申请了是不是当下就能用那一个功用?
   
答:假设你的手机终端是电信定制终端,您申请后,一旦电信的资源配置工作形成,并安装完毕相关设施后即可使用。
    41.本人一度有BREW
客户端形式的物价指数揭穿/咨询服务效益,是否能选取证券交易效率?
    答:可以。然而你必须另行下载相应的客户端软件并安装。
    42.手机炒股的各类效率是不是都要下载相应的软件举行安装?如何设置?
    答:手机炒股业务分为BREW 客户端和WAP
二种艺术,其中客户端模式是必须下载相应软件拓展设置的,WAP
情势是无客户端格局的。客户端软件的安装在成功下载后能半自动执行,您只需要遵照相关提醒操作即可。
    43.在怎么地方能够收获手机炒股业务的连锁介绍?
   
答:您可以前往中国电信营业厅咨询、中国电信协作券商营业厅,或透过中国电信网上营业厅、中国电信WAP
门户网站、手机炒股产品表达获得有关介绍,同时中国电信也将会在营业厅专区等地方社团手机炒股业务的演示和表明。
    44.BREW 客户端软件怎么采用和设置?
    答:不同的BREW
客户端软件对应了不同产品效用和资费套餐,在装置前您应该密切翻看相关的软件表明,并采纳自己索要的客户端软件拓展设置。您能够透过相关应用验证、网上营业厅专区和10000
号自助安装。
    45.自我如何设置使用手机炒股业务的WAP 产品?
    答:您可以由此中国电信C 网终端自带的WAP 浏览器进入中国电信WAP
门户的手机炒股业务频道拔取有关制品套餐后一向开展浏览。中国电信的营业厅、网上营业厅都有《手机炒股业务使用指南》或《手机炒股业务产品使用手册》对此都有认证,很有利的索取或浏览。
    46.即便在自我在拔取手机炒股业务的经过中有题目该肿么办?
    答:中国电信网上营业厅提供有自助查询援救,您也可致电10000
号或亲临中国电信营业厅,大家的客户服务人口将为您提供救助。
    (三)号码百事通业务
    47.咋样是订餐服务?
    答:用户可通过拨打语音118114
格局搜索并获取餐饮公司的名称、区域、菜系、人均等详细音信。假设该餐饮集团为号百订餐的署名经纪人,那么用户可从来通过语音格局订餐,同时得到号百提供的积分或折扣。
    48.什么是订房服务?
    答:用户可透过拨打语音118114
模式在认可入住城市、入住日期、入住天数等主导尺度后,搜索并获得宾馆名称,以及价格限制等音信,并可透过语音形式订房,同时获取号百提供的积分或折扣。
    49.什么样是机票预订服务?
    答:用户可透过拨打语音118114
形式在认可出发、到达机场、出发日期等为主尺度后,搜索并取得航班时刻、班次、价格等实时新闻,并能通过语音形式成就预订,同时获取号百提供的积分或折扣。(近来只匡助电子客票,机场付款取票格局。)
    50.本人何以拔取预订服务?
   
答:号百目前提供膳食、酒馆、机票的预订服务(部分省市提供商品、鲜花、票务的订座服务),您可拨打118114预定。
    51.一旦本身在动用号百移动业务的历程中冒出问题,应该向哪儿投诉?
    答:您可以透过拨打中国电信客服电话10000
号或前往中国电信营业厅就有关题材进行投诉。
    52.自己投诉之后多久能博取回应?
    答:号百移动业务的投诉时间将严酷按照规定举办,紧急投诉2
钟头内回升,非紧急投诉1 个工作日内回复。
    53.怎么是竞价排行产品?
   
答:竞价排行是指在大众用户拔取首要词模糊搜索集团音信时,搜索结果遵照竞价排行高低以此体现购买该重大词的公司名称及有关音讯。
    54.一旦本身预订的号百移动产品出现问题,应该如果投诉或申告故障?
   
答:您可联络中国电信客户首席执行官或制品首席营业官,由其将你的题材影响到相关技术单位或号百业务部门。
    55.自我在投诉和故障申告之后多长时间后能收到回复?
   
答:政企用户受理客户投诉由客户高管或制品首席营业官协调在最长期内解决,最迟不可超过一个工作日。
    56.借使忘记WEB 自助服务密码咋办?
    答:您可互换中国电信客户首席执行官或制品主管,由其帮你向相关单位申请。
    (四)定位服务业务
    57.哪些是定点服务业务?
    答:LBS(Location-Based
Service)即一定服务,就是通过手机、PDA、特殊终端等运动终端与无线网络的配合,确定移动用户的实际地点新闻,包括经纬度坐标数据、三维数据等,并结合电子地图和数量音信内容,并通过SMS、WAP、MMS、语音、客户端等办法显示给用户,为用户提供各种相应增值服务。各样LBS
业务由中国电信联合SP 共同提供。
    58.稳定服务工作有怎样类型?
    答:LBS
业务依据不同的正儿八经,基于地方服务有多种分类方法,遵照使用特征,可分为日产采纳和行业应用。
   
马自达应用:针对群众用户的定点应用有诸多,就当下而言,在此临时能够分为:实时导航类、特殊群体跟踪爱护、新闻类、游戏社区类。:导航应用的目标就是对终极举行周期定位,随地方变动提供实时提醒,引导终端用户找到其目标地。实时导航类应用的定位精度一般应在10
米-50 米左右。
   
行业应用:这一类的运动定位应用就是天天得到员工和资本的职位音信和用户组详细业务的图景。应用的实例有不少,比如分派工作的老董需要精晓雇员的岗位和情景、物流管理、资产跟踪、动物跟踪等。相关行业紧要概括物流、运输、成立、医疗、保险、零售等行业。行业使用的精度要求取决于行业特性和现进行使项目。例如跨省的物流管理,精度达到500
米已经可以满意要求。
    59.原则性服务工作有什么样接入和运用方法:
    答:(1)SMS 接入:用户通过短信模式发生地方服务请求,
    地点服务业务系统从LBS
平台获取经纬度音信,结合地图等情节,并以短信情势向用户提供地方服务。
    (2)WAP 接入:用户访问WAP 网页,WAP 服务器从LBS
平台获取经纬度音讯或地点业务音信(如地图等),并向用户再次来到所请求的地点服务音信。
    (3)BREW/JAVA 及另外终端驻留应用接入:用户通过BREW/JAVA
下载服务器,下载地点服务应用,或通过其他模式获取极限驻留的地方服务应用。用户采纳下载到本地的地点服务应用,从地方服务系统获得经纬度信息或岗位业务音信。
    (4)其他连接格局:用户可以通过WEB
情势、语音模式查询其他用户终端的位置。地点服务业务序列接到到此呼吁后,向LBS
平台发起地方服务请求,并遵照重临的职务消息向用户提供地点服务。例如行业利用中,管理员对车辆展开稳定。
    60.原则性服务业务根本面对怎么样人群?这多少个用户在如何状况下需要利用LBS
业务?
    答:依照LBS 业务的体系不同,目的客户与行使情况也黯然失神:
    A.特斯拉应用类:
    a)目的客户:个人客户,首要不外乎社会人才有车一族,年轻风尚一族等。
   
b)使用情况1:用户前去陌生地点,使用导航工作在手机客户端规划最佳途径,查看交通路况,并在行路过程中听到行进方向、摄像头等音讯的实时语音播报,也可在手机屏幕看到道路状况和大面积音信。
   
c)使用场景2:老人在飞往时候,家人可眼看通过Web、Wap、短信等形式查询到其岗位,在长辈需要帮助时候,通过一定效率可即刻了然其地点,快捷抵达现场。
   
d)使用状况3:用户在陌生地寻找周边地图,获取餐馆、银行等信息;依照地方寻找路线、公互换乘新闻和畅行气象。
   
e)使用场景4:用户进入地方社区,可以展开地缘速配、聊天或其他娱乐娱乐。
    B.行业应用类:
   
a)目的客户:政企客户,首要不外乎物流、运输等外勤人员车辆相比较多的商家。
   
b)场景1:物流、快递、运输等公司对外勤人员、车辆地点举办监察,并结成地点向无绳电话机发送调度指令,获取调度结果,并对路途进行记录和总计,实现生产流程管理
   
c)场景2:保险公司调度大旨接收交通理赔请求,利用定位确定距离事故地方近期的理赔车辆,调度车辆去及时做到理赔任务。
    61.如何是导航工作?有些咋样遵守?
   
答:导航工作是遵照用户地点移动,以语音和地图等直观格局,为自驾车和行人提供实时路线、方向等导航提醒,指导终端用户找到其目标地。其工作效率包括:最佳路线规划、实时语音导航、周边消息查询、公交流乘查询、地方音信共享等。
    62.如何是非常群体跟踪业务?有些怎么着效益?
   
答:由于它首要为老人,小孩等新鲜群体提供位置服务,家人得以为老人、小孩配置中国电信的一定手机,及时通晓老人、小孩的此时此刻职务,在遭受危险时可采用极限向受害设定的人士发送求救音信,系统能及时收到求救音信并规定被检控人士脚下的职务音讯。
    63.原则性服务工作的开支情状如何?
   
答:定位服务的计费涉及到通信费、音讯服务费和一定服务费多少个方面:其中固定服务费由运营商向SP(业务提供商)和行业用户接受,通信费、信息费与使用服务费由活动运营商向用户收到,为SP、GIS
厂家代计费,并遵照LBS 业务的有关规定,在中国电信、SP、GIS
三者之间开展结算。定位服务费统一在中国电信的MPC(移动定位中央)发生,对SP(业务提供商)或行业用户实时计费,按离线格局计费(计费音信不影响工作提供的计费机制),按周期计费结算。定位服务工作的花费意况如下:
    A.前向用户(个人):
   
查询终端自身地方的,不独立接受一定服务费,只按WAP、BREW、JAVA、短信等相应工作现行资费标准收取信息服务费。
    B.前向用户(行业):
    定位服务费:
    定位服务费(元) 含免费定位次数 超出后费用(元/次)
    500 5000 0.1
    800 10000 0.08
    3000 50000 0.07
    10000 200000 0.06
    通信费:按WAP、BREW、JAVA、短信等遥相呼应工作现行资费标准收取通信费。
    C.后向用户:
    端口使用费:400 元/月
    定位服务费:0.06—0.1 元/次
    查询次数
    (万次/月) 单价
    (元/次) 总价( X 为月查询次数)
    0-1 0.1 X*0.1
    1-5 0.08 (X-10000)*0.08+10000*0.1
    5-20 0.07 (X - 50000 ) *0.07
    +40000*0.08+10000*0.1
    〉20 0.06 (X-200000)*0.06+150000*0.07
    +40000*0.08+10000*0.6
   
    64.自己索要一台什么样的顶峰才能应用中国电信一定服务工作?
   
答:需要采纳辅助定位效用的终点,并打开终端的永恒效能,才能订购和动用导航等LBS
业务。
    65.怎么着开展、更改或者撤回定位服务工作?
(依据地面营销策略不同,可举办改动、补充)
    答:依据工作系列不同,LBS 业务的开展、更改及吊销模式有所不同:
   
A.中国电信用户默认开通自定位服务(如导航、周边查询等),无需向中国电信报名开通定位能力,用户可透过手机安装关闭定位能力。用户拔取具有稳定能力的顶点,即可以从中国电信的WAP、Web、Brew
等门户中浏览、订购和管理定位服务产品,各种产品的受理、变更等工艺流程按照不同接入格局参考WAP、Brew、IVR
等制品的保管章程。
   
B.对于用户被一定,系统默认全体未开展,用户需要展开第三方定位业务的用户授权开通。在通达后,分为二种情状:(1)行业用户,全体权利开通;(2)普通用户,默认举行授权查询或被叫逐一确认。
    66.本人怎么样才能使用那么些永恒服务工作职能?
    答:用户可以在WAP
门户浏览,采用和预订具体的永恒类作业,到中国电信的下载门户中下载安装后才能运用该类事情,如实时导航类业务等。部分终端已经预安装导航等原则性业务。
    67.假设要安装客户端软件,是不是要求自己的无绳电话机终端必须是智能手机?
    答:客户端软件可分为BREW 版本和JAVA 版本,不要求终端是智能手机。
    对BREW 版本客户端,需要终端辅助BREW
程序运行环境,查看您的极端是否补助BREW
程序,请查看手机终端表明书或者提问终端生厂商。
    对JAVA 版本客户端,需要终端襄助JAVA
程序运行环境,查看您的顶点是否帮助JAVA
程序,请查看手机终端表明书或者提问终端生厂商。
    68.BREW 版本与JAVA 版本客户端如有什么两样?
    答:不同版本客户端只是本着不同款式终端开发,效能方面基本一致。
    70.在哪些地点可以博得一定服务工作的有关介绍?
   
答:您可以前往中国电信营业厅咨询、中国电信通力合作券商营业厅,或通过中国电信网上营业厅、中国电信WAP
门户网站、LBS 各类作业产品的出品表明拿到有关介绍。
    71.BREW 版本/JAVA 版本的固定服务工作产品客户端咋样设置?
    答:对提供了BREW/JAVA 版本客户端的LBS
业务产品,用户只需登陆中国电信统一WAP
移动门户,采用切合自己机型的客户端举办下载,同时举行工作的预订,客户端下载后,并打响开展订购了政工的用户,即可及时使用该事务。
    不同定位服务业务产品的BREW/JAVA
版本客户端软件对应了不同出品效率和资费套餐,在安装前您应该密切查占星关的软件表明,并选拔自己索要的客户端软件举办安装。您可以通过相关应用表达、网上营业厅专区和10000
号自助安装。
    72.对从未提供客户端的平昔服务业务产品客户端咋样利用?
    答:用户可以透过中国电信C 网终端自带的WAP 浏览器进入中国电信WAP
门户的LBS
业务频道,选拔有关产品及其套餐后平素开展浏览。中国电信的营业厅、网上营业厅均会提供《LBS业务产品使用指南》或《LBS
业务产品使用手册》给用户,很方便的索取或浏览。
    73.假使在自己在利用LBS 业务的长河中有题目该如何做?
    答:中国电信网上营业厅提供有自助查询帮衬,您也可致电10000
号或亲临中国电信营业厅,我们的客户服务人士将为你提供帮忙。
    (五)短信类业务
    74.哪些是短信工作?
   
答:短信业务是指通过存储转发、实时监测的体制,提供保险的,低开销的无线数据业务。人们常见所说的短信,一般都是指移出手机短信,而其实,短信业务远不止于此,大家周边的传统点对点短信及基于短音信技术平台上实现的各项增值内容服务以及其它依据互联网的即时通信类短信、固话短信等事务,也都属于短信的范畴。
    75.短信工作的分类有哪些?
   
答:按照中国电信近来提供的短信工作,大家将其分为点对点短信工作及按照短音讯技术平台上提供的信息订阅和点播业务两大类。
    76.点对点短信是何等?
   
答:短消息业务是依照移动网络的一项新工作,手机用户可以通过手机键盘输入中英文的简练音信,并将其神速无误地发往其他手机。无论对方已关机依旧不在服务区,在短信息发送有效期内假如其重新开机或再一次回来服务区内,即可及时收到到外人暴发的短信息。
    77. 点对点短信的效益有咋样?
   
答:用户编辑短信内容发送到想要发送的手机号码上,接受方收到短信到达的唤醒并可查阅相应的始末。
   
(1)短音讯的发送:手机用户可一向在手机短信息编辑菜单中,输入信息;在发送菜单中输入接收方手机号,即可发送信息。
   
(2)短信息的收受:接收到新的音信时,一般会有提醒音提醒,并且有连带标志突显,一贯到该音信被阅读。手机关机、或离开服务区时,暂时接过不到音讯,该音信会被储存起来。
   
当手机回到服务区内并处于待机状态时,仍可收取到该音信。这是短音讯服务相对于寻呼机的最大优势。
   
(3)短音信删除:当手机短音信存储满后,手机将展开指示,此时应答不根本的短信息举行删减,否则将不能够健康接收短信息。
   
(4)短音讯的有效期:有效期是指音讯发送不成事或音讯未接受在此之前,在确定的时辰内被保存起来,仍继续有效,等待重发或收取。借使领先规定时间,此音讯将永久删除。音信有效期最近为2
天。
    78. 点对点短信的特性有怎样?
    答:(1)保密:点对点的第一手互换,旁人无法知晓;
    (2)畅通:在信号弱乃至无法通话的地域仍能正常干活;
   
(3)可靠:在短音讯发送有效期内不会因关机、电力不足造成音信丢失,只要开机或退回服务区即可吸收短信息。
    79. 如何开展点对点短信?
    答:无需提请/开通,只要用户采用有短信效率的CDMA
手机(目前几乎拥有的手机都有短信功效)均可使用点对点短信工作。目前短信息服务缺省状态下是开展的。CDMA
手机的短音讯接收不需要其他设置即可使用。
    80. 点对点短信工作分类有怎么着?
   
答:点对点短信工作依照发送号码的着落区域分为国内短信及国际短信二种。国内短信遵照发送对象是否是本网用户分为网内点对点短信及网间点对点短信。
    81. 如何使用点对点短信?
   
答:点对点短信的出殡流程为:直接编辑短信内容发送至接收方手机或小灵通号码。(移动、联通与小灵通用户互发短信都已收回了“106”前缀。)
    82. 点对点短信的开支是什么样?
   
答:点对点短信工作的资费标准由发送方按条主叫计费,被叫免费;遵照发送号码的着落分为国内短信及国际短信二种。
    (1)国内点对点短信
    中国电信的手机用户发送至中国电信用户0.10
元/条,发送至中国移动用户和小灵通用户0.15
元/条,具体开支以当地电信分公司发表为准;
    (2)国际点对点短信:见移动电话基础业务部分。
    83. 点对点短信什么付费?
   
答:短信的收款与话音通信费一样,可透过到营业厅缴纳现金、充值卡充值、网上营业厅缴费、手机银行付费等多种方法付费。
    84. 什么是“短信”业务?
   
答:“短信”是中国电信遵照无线网络开展的无线数据业务,是为中国电信手机用户推出的新业务。
    中国电信经过 CDMA
网络提供手机点对点短信服务,并联名无线数据业务内容提供商(简称CP)/服务提供商(简称SP)向电信用户提供各项充足多彩的无线数据服务。SP
作为内容和应用服务的提供者,通过中国电信短音讯平台向中国电信移动用户提供各项音信及应用服务。“短信”是此业务的品牌,目的在于随时随地、得心应手地享用新闻,把握时机。最近重要提供按照短音讯平台的订阅和点播业务。
    85. “短信”的紧要内容是哪些?
   
答:“短信”的机要业务内容包括:生活类、娱乐类、金融类、商务类消息点播、音信定制伏务、交互式娱乐娱乐、交友聊天等。例如无线QQ
聊天、短信天气预报、航班音讯、证券交易、话费查询、音讯定制、电视机广播互动等事情。
    86. “短信”的要紧功用有什么样?
    答:每家SP
分配了固定的店铺代码和事情代码,各内容服务提供商通过一定的端口号码向用户提供音讯服务。
   
(1)信息订制:用户可因此上网、发送订制短信、手机点播等措施开展音讯点播。
   
(2)消息退订:用户可通过上网、发送订制短信、手机点播等措施对已订制的音讯举办消息退订。
   
(3)音讯查询:用户可因而上网、发送订制短信、手机点播等措施对已订制的信息举办消息查询。
    87. “短信”的如何分类?
    答:(1)依据业务属性分类
    ①信息类
    指基于短信平台的新闻、旅游、生活服务、财经音信等劳动。
    ②个人服务类
    指基于短信平台的电子邮件、日程安排、电话簿等个人服务。
    ③交易类
   
指基于短信平台的活动电子商务如股票交易、手机银行、彩票、交费、购票等事务。
    ④娱乐类
   
指基于短信平台的娱乐、铃声下载、图像下载、每一日星座、笑话、聊天等业务。
    ⑤基于地点的劳动
    指基于短信平台的酒楼、餐厅等环境音讯查询、紧急救助、区域广告等。
    ⑥公司及行业应用类
   
基于短信平台的小卖部办公室、交通管理、移动警务及公共机关和政坛部门公共设施管理及控制等应用服务。
    (2)业务使用限制分类
    ①全国性工作
    可对全国电信C网用户开放的短信工作。
    ②地点性工作
    只对本省电信C网用户开放的短信工作。
    88. 怎么着使用“短信”业务?
    答:使用“短信”业务无需提请/开通,只要采用有中文短信功用的CDMA
手机,就可使用“短信”业务。
    89. 如何订购、退订“短信”?
   
答:中国电信用户可用多种情势展开“短信”业务的订货和退订:包括殡葬短信、拨打“10000”热线电话、登录网站等措施。
    90. “短信”的费用是咋样?
   
答:用户使用中国电信的“短信”业务及其内容服务,将生出两笔开支,即通信费和新闻费。
   
通信费:是用户使用中国电信通信网络所发生的费用,由中国电信向用户收到。
   
音讯费:是用户采用内容/服务提供商(SP/CP)提供的服务所发生的资费,由SP/CP
向用户收到,中国电信代收,与手机话费同时接收。信息费由SP/CP
自主定价,报中国电信开展审批后执行。
    (1)通信费
   
对于用户通过手机发起的音信点播、查询等类业务,用户成功接到音信后,上行通信费(用户使用手机发出业务指令)按0.10
元/条收费,下行通信费(用户用手机收到信息)免费。
   
点对点办法(即手机对手机的短音讯工作),用户成功发送后,向主叫方收取0.10
元/条;对于用户在行使无线数据业务中发出的系统报告音讯,通信费免收。系统信息确认用户操作成功、系统故障或是因为用户误操作向用户反馈的操作不成功类音讯等,上、下行通信费均免收。
    (2)点播音讯费
    音讯费的计费原则是:
    信息费设定价格上限。SP 单项工作信息费按条收费的,价格上限为2
元/条;SP 单项业务信息费选择包月制收费的,价格上限为30 元/月。
    对于包月制的音讯服务,用户从开通业务之时起72
时辰之内可以收回订战胜务,无需交纳任何费用。对于每月20
日之后注册的包月业务,不向用户接受当月的包月费用。
    (六)互联星空(WAP)
    91. 互联星空是什么样?
    答:“互联星空”是为CDMA 1X 用户提供的一项手机无线上网服务。它使用CDMA
1X
网络有所高速数据传输优势,在二哥大上落实了信息浏览,图片、铃声、动画下载、互动信息等多种方便、实用的效用,为用户随时随地体验业务带来的高大乐趣与便宜。
    92. 互联星空的事体分类有哪些?
   
答:“互联星空”业务依据工作覆盖范围分为全国工作和地方工作,其中全国工作由总部负责作业接入、维护;地方工作由各省负责接入维护。
    问题:互联星空的互联星空的特征有什么?
   
答:“互联星空”手机上网服务具有高效、方便、随时、随地、安全等特性。用户倘使使用帮忙WAP
协议的手机终端,无需任何设置就足以轻松访问有线互联网音信,尽享内容繁多、图文并茂、个性显明的无绳电话机上网服务。
    93. 用户采纳互联星空的尺度是如何?
    答:只要用户使用扶助WAP 效用(即协理“互联星空”业务)的CDMA
手机,并将UIM 卡开通CDMA 1X 数据业务,便可一贯接纳“互联星空”业务。
    94. 咋样订购互联星空?
   
答:可采纳手机终端格局、网站模式和拨打中国电信客服热线“10000”等方法展开连锁作业的申请和退订。
    95. 互联星空的资费标准是怎样?
   
答:用户使用“互联星空”业务及其内容服务,将发出两笔费用,即通信费和信息费。通信费是用户接纳中国电信通信网络所暴发的支出,由中国电信向用户接受。CDMA
1X
用户按流量收取,具体开支标准以中国电信各支行具体开支政策为准。信息费是用户使用内容/服务提供商(SP/CP)提供的增值内容或服务所发出的费用,由华夏电信代SP/CP
向用户收取,信息费由SP/CP
自主定价,报中国电信展开审批后执行。计费形式分为按次计费、按天计费、包月计费两种。收费标准使用价格上限封顶:按次资费一般不超越2
元/次,按天资费一般不抢先2 元/天,包月资费一般不超越10元/月。
    96. 互联星空的什么样付费?
    答:用户使用“互联星空”发生的通信费和信息费都与手机话费同时吸收。
    97. 怎么互联星空上无法下载图片?
   
答:用户在“互联星空”上不能下载图片或另外内容可能存在如下原因:一、图片不存在;二、终端不辅助图片格式;三、无线信号糟糕。
    (七)彩e 业务
    98. 彩e 业务是如何?
    答:彩e
称为移动多媒体邮件业务,是中国电信公司会同内容和劳动提供商合作为CDMA 1X
用户提供的一项活动多媒体邮件业务。
    彩e 业务涵盖两部分:彩e 邮箱、彩e 信箱。彩e
邮箱业务经过手机客户端软件使用工作,彩e
信箱业务经过WAP(互联星空)使用工作。
    99. 彩e 业务的功效是如何?
   
答:手机接收来自互联网上的多媒体邮件:通过互联网上的其它邮箱(可以含文字、图片、音频、视频等情节)发送到“彩e”手机上,手机会自动保存邮件附件至文件夹。
   
“彩e”用户发送多媒体邮件到互联网:“彩e”用户可以将多媒体邮件(可以蕴涵文字、图片、音频、录像等内容)发送到互联网上的另外邮箱。
   
“彩e”手机里面交互发送多媒体邮件:“彩e”用户可以用手机互动发送多媒体邮件(可以蕴涵文字、图片、音频、视频等情节)。
    100. 怎么着运用彩e 业务?
   
答:通过按手机上的“e”键进入“彩e”菜单或透过按手机上的“互动视界”键进入彩e定制菜单。选取“邮件设置”选项;再接纳“注册/注销帐号”选项
;选用“注册帐号”实现“红草莓”效能的开明;用户登录互联网,进入自己的互联网邮箱,设置自动转化效率,将邮件自动转接到“手机号@cumail.com.cn”上。
    101. 彩e 的开销是怎么?
    答:“红草莓”业务费用包括邮箱费和发送费两部分,接收免费。
    102. “彩e”用户与“彩e”信箱用户的界别是哪些?
    答:“彩e”用户分为二类:
   
(1)“彩e”用户(“彩e”邮箱用户):使用帮助“彩e”的手机,在“彩e”中登记生成的用户;通过“彩e”注册的用户,能够运用“互联星空”中的“彩e”信箱。
   
(2)“彩e”信箱用户:使用“互联星空”注册的用户(适用于不襄助“彩e”成效的手机用户)。
    103. “彩e”的特色是何等?
    答:(1)襄助收发大容量多媒体邮件
    (2)传送文字邮件(最多5000 汉字的正文)
    (3)协理传送视频流、彩色图片、铃声等音频流的多媒体附件(最大
100KB)
    (4)帮助接收录像流、彩色图片、铃声等音频流的多媒体附件(最大500KB)
    (5)与电子邮件完全配合
    (6)可以接收来自另外邮箱的电子邮件
    (7)可以向任何邮箱发送电子邮件
    (8)扶助抄送、密送,帮助向多个人发送电子邮件
    (9)援助中转、回复、全部復苏邮件的效能
    (10)邮件不受手机机型限制,具备不错的互通性
    (11)统一的媒体格式,方便用户在互联网和手机里面传递媒体内容
    (12)图形格式:JPEG、PNG;铃声格式:MMF
    (13)动画格式标准:GIF;影象格式:AMC
    (14)简单、友好而精通的操作界面
    (15)用户不用设置任何利用参数
    (16)简单的编排邮件模式(与平常PC 电子邮件完全平等)
    (17)使用界面和章程与PC 上看似;一样援助剪切、复制和粘贴
    (18)“彩e”手机普遍协助有力的邮件和文件管理功用
    (19)提供类似PC 上OUTLOOK
的收发邮件、收件箱管理、发件箱管理等功用
    (20)实用的文件管理器,近似PC 上资源管理器的效率,实现对用户文件
的分类、重命名、排序等管理
    (21)强大的反垃圾邮件效用
    (22)可挑选自动/手动接受邮件
    104. “彩e”业务的使用规范是如何?
    答:只要接纳协理“彩e”功用的CDMA 1X 手机,并开展CDMA1X
数据业务,便可径直利用,近日怀有的CDMA 手机UIM卡已经先期开通了CDMA1X
数据业务,能够向来运用“彩e”业务。
    105. “彩e”信箱业务怎么开展?
   
答:用户可以通过“彩e”手机和“互联星空”举办工作申请,注册为“彩e”用户。
   
注:只要用户开通了“彩e”邮箱或“手机邮箱”业务,就可同时接纳两项工作(持“彩e”效能的手机用户),而不另行计费。
    (八)流媒体业务
    106. 手机电视机是哪些?
    答:“手机电视机”业务是按照中国电信CDMA 1X
精品网络,拔取先进的流媒体技术,为用户提供高质量的视、音频服务的手机增值业务。
   
所谓移动流媒体技术就是把连续的形象和声音信息通过压缩处理后放到网络服务器上,让活动终端用户可以一边下载一边观看,而不需要等到一切多媒体文件下载完成就足以看看的技巧。实际上流媒体技术是网络音视频技术和移动通信技术发展到早晚阶段的产物,涉及到数量的采集、压缩、存输以及网络通信等多项技艺。
    107. 手机电视机的事务内容有哪些?
   
答:用户使用“手机电视机”业务,可以在小弟大上寓目实时直播的电视节目,欣赏流行的M电视和经文的音乐,观察最新影片的片花预告和经典影视剧的剪辑,实时查看天气预报,下载精粹的体育赛事,查找自己喜爱的相声小品、明星访谈等综艺节目和幽默搞笑的短片,并有和生存不无关系的吃饭等各地点的出色内容。
    108. 无线电话电视机的利用标准是咋样?
    答:用户使用帮忙“手机电视”的CDMA 1X
手机,开通CDMA1X数据业务,便可径直行使。
    109. 无线电话电视采取形式分别是何等?
    答:依照业务内容分成点播格局、直播情势和下载情势。
   
(1)点播形式:用户可以透过访问手机门户,发现感兴趣的情节,有采取地举办播放。点播情势的最大特色就是灵活。
   
使用“手机电视机”业务可以使用户积极地挑选自己喜欢的情节,而并非被动接受,随时随地而从不范围。
   
(2)直播格局:直播形式的最大特征就是实时。依照实时内容信号源的不比,又足以分为电视直播、路况监控等。使用“手机电视机”业务在手机上就足以看到各套电视节目标直播、实时的路况监控。
   
(3)下载格局:用户将内容下载并蕴藏到手机中,然后能够选拔在随心所欲时间展开播报。下载形式的最大特色就是恒久保存。使用“手机电视机”业务,可以把自己喜爱的情节下载到手机上保存,能够极其次广播。下载后对情节版权的保安规定是:下载到手机的情节不得转发出来。
    110. 怎么着订购和退订手机电视机?
    答:用户可以在表哥大上实现“手机电视机”业务的预订和退订。
    111. 手机电视机的开支是怎么着?
    答:用户使用“手机电视机”业务,将生出两笔开支,即通信费和音信费。
    通信费,即流量费是用户使用中国电信移动通信网络所暴发的开支。
   
音讯费是用户使用内容/服务提供商(SP/CP)提供的始末或劳务所发出的花费,由SP/CP
向用户收取,中国电信代收,与手机话费同时收取。信息费由SP/CP
自主定价,报中国电信举行审批后实施。计费模式如下:
    (1)免费:向用户提供部分免费工作或免费内容,不接受消息费;
    (2)按次计费:点播或下载的内容可以按每条内容按次计费;
   
(3)包月计费:一个月内按一定使用费用不限定使用工作中的直播、点播和下载的内容。包月用户退订后,可以动用到月末;
    (4)按时长计费:仅限直播服务,以秒为单位计费。
    (九)彩信业务
    112. 什么是彩信?
    答:彩信的英文名是MMS,它是Multimedia Messaging Service的缩写,意为多媒体音信服务,平时又叫做彩信。它最大的风味就是支撑多媒体功效,可以传递功用完善的始末和音讯,这个消息包括文字、图像、声音、数据等各样多媒体格式的音讯。
彩信在技术上实际并不是一种短信,而是在GPRS 网络的协助下,以WAP
无线应用协议为载体传送图片、声音和文字等音讯。彩信业务可实现即时的手机端到端、手机终端到互联网或互联网到手机终端的多媒体消息传送。
    113. 手机关机或不在服务区影响彩信的收取呢?
    答:手机关机或不在服务区时是不可能接收彩信的,但彩信会在系统中保留48
刻钟,一旦开机或进入网络服务区,彩信手机依旧可以健康接收到彩信。如果手机在10
分钟以内没有开机或如故不在服务区,系统将会去除彩信内容。
    114. 部手机在拨打和接听电话时,仍能够收到彩信吗?
    答:不能够。因为彩信是透过CDMA 1X
为承接模式来传输的,在拨打和接听电话时不可以同时进行数据传输。但如若电话挂掉,仍可以够开展正常的彩信的接受和殡葬。
    115. 对方不是彩信手机仍能接到到用户发送的彩信吗?
    答:不可以。必须是彩信手机才能接受彩信。
    116. 彩信有高低限制吗?
   
答:严刻的说,彩信是尚未高低限制的。但鉴于当下的彩信手机对可以发送和吸收的彩信大小存在一定的范围,同时为了保证每条彩信在网络中传输的快慢,一般会在彩信网络设施MMSC
中设置一个限制的深浅。如今中国电信彩信业务每条彩信的轻重限制在100KByte
左右。这是一个可以设定的值,随着新的彩信终端的随地推出和彩信业务的愈发升华,彩信大小的限制值还足以天天再调动。
    117. 无线电话下载一些彩信动画,播放没有动静?一些则有声响?
   
答:因为大部分彩信动画搭配的背景音乐拔取的铃声格式不同,所以有部分手机不扶助搭配了MID
铃声的卡通在这多少个手机里是无能为力播放出音乐。
    118.
本人的彩信手机协助和弦铃声下载,为啥我下载一首和弦铃声后,收到的一堆乱码?
    答:(系统割接后的答复口径)因为MMS
彩信的机制与电子邮件机制一样,用户在暴发一个下载请求后,系统就会将一个文书发送到用户手机上。假使在传输过程中,手机网络或彩信网关出现不安静现象,就可能导致用户接收到不完整的文件,衍变成乱码。
这种场所较少出现,因为近年来中国电信的彩信网关仍在试运作中,所以有些地面可能出现部分小题目。用户只要发现这种意况,请告诉咱们,大家会延续革新。
    119. 为啥在此以前我能吸纳彩信,现在收不到了?
   
答:原因一:收到的彩信过多,导致手机内存满,所以不能再收取彩信,请留心及时去除彩信。喜欢的图样可以保存在手机中。原因二:用户手机安装被无意识中修改了,比如彩信接收提取方法成为“关”了,影响健康接收。原因三:倘使手机处于关机状态,将不能正常接收彩信。
    120. 境内旅游使用彩信,需要加收费用吗?
    答:国内旅游时不加收漫游资费。
    121. 怎样才能利用彩信业务?
    答:手机援助彩信功用,并已开展CDMA 1X 业务,即可使用彩信业务。
    122. 为啥自己打不开彩信?
   
答:原因一:手机参数设置错误;原因二:彩信数据过大,超过手机接到的最大值;原因三:彩信的格式手机不援助;原因四:文件破损,可能是网络原因促成。
    (十)手机报业务
    123. 怎样是手机报?
   
答:中国电信手机报是一项资讯类事情,通过手机为用户提供各项音信音讯的劳务。手机报提供的情报包括情报、体育、娱乐、文化、生活、财经等,并以具体“报刊”产品呈现相关内容。
   
中国电信手机报由一多元不同核心的手机报产品结合,用户定购了某份手机报产品后,将会定期/不定期收到相应的各期报刊,每期报刊具有三个版面,一个版面内由一条或多条内容资讯组成。
    124. 部手机报都有怎样内容?它能给自身带来什么样便宜?
   
答:手机报提供的消息包括音信、体育、娱乐、文化、生活、财经等,并以具体“报刊”产品展示相关内容。
   
您随时随地可以下载和查阅手机报内容,比如在户外地铁上、公交车上。手机报平时每日1
期或多期,您可以赢得最新的信息。彩信手机报可提供图片、铃声资讯,比单独的文字消息的表现情势更加助长。但彩信手机报过渡期提供与否与彩信平台是否开展业务有关(目前还不具有),过渡期间最重要提供彩e及短信二种艺术手机报。
    125. 咋样订购手机报产品?
    答:如今您可由此短信、10000 号、营业厅等渠道预订手机报产品。
    126. 本身预订了是不是霎时可以看来到手机报?
    答:在预订成功的第二天就足以吸纳到手机报。
    注:由于手机报工作基于彩信开展,其他题材请参考彩信部分。
    (十一)OTA 卡业务
    127. 什么是OTA?
    答:空中下载OTA(Over The Air)业务是基于UIM
卡UTK技术实现的增值业务之一,该事务为终极用户和运营商提供了经过无线网络传输情势对UIM
卡上的内容(包括菜单、文件等)举行保管的路径。终端用户可以经过OTA
应用举行卡片业务菜单的个性化定制。
    128. 咋样是OTA 卡,它和平凡的UIM 卡有哪些区别?
    答:OTA 卡是UIM
卡家族中的新产品,除了富有普通UIM卡打电话、发短信等基本效用之外,最大的效率是可以由此空中下载(Over
The
Air)的点子(通过短信发起呼吁和形成下载)实现卡上增值业务菜单的翻新。
    129. 用户可以由此什么样路线使用OTA 业务?
    答:用户使用OTA 业务的方法有三种:终端发起、WEB 方式(通过OTA
门户网站)发起或者结合运营商发送的PUSH 音讯发起。
    130. 使用OTA 有怎么着利益?
    答:传统的UTK UIM
卡由于指令菜单修改不便利,用户只要想更换菜单则必须换卡。而采取了OTA
技术的UIM
卡当用户要加进、修改、变更和删除应用时,无须做其余硬件更换,只要随时随地通过按键(空中下载效能应用从OTA
平台发来信息)就能轻轻松松取得所需的应用服务,同时运营商还可通过那种自发性快捷的问题诊断和解决改良客户服务。OTA
卡内新工作菜单任意下载删除,一张UIM
卡能够享用到最好的服务,为手机用户带来了劳务的省心;OTA
卡中的业务菜单通过空中下载形式进行动态更新,客户可依据喜好活动下载和删除菜单,知足了客户对业务应用的个性化和业务革新的实时性要求;OTA
卡用户可通过手机菜单操作或WEB 情势,灵活的运用OTA
功效;而且更大容量的OTA 卡也满足了用户存储需求。
    131. 什么样申请开通OTA 业务?
    答:用户第一次进入UIM OTA 卡菜单第一级目录时,UIM
卡会自动向服务器发送服务注册音讯。服务器收到卡端发来的注册音信后,向用户卡发送注册确认新闻成功业务开展。
    132. 当自己进去OTA
菜单后,系统就会自动开通用户,是否有额外的开销爆发了?
    答:没有,开通OTA
业务不接受任何费用,唯有利用其中的有的工作,才会接受工作使用费。
    133. OTA 应用服务怎样下载?
    答:用户可以透过极端发起应用下载,也得以因而运营商的OTA
门户网站下载使用。
    134. 假如本身不想开通OTA 业务,但现已不小心开通了,怎么样裁撤?
    答:OTA
业务的开明不收受其他费用,唯有应用其中的工作才会时有暴发资费,由此,您没有必要专门去注销。
    135. 选取OTA 业务的开销标准有什么?
   
答:通信费免除,业务使用费遵照不同工作有包月收费和按次收费二种,具体见事情介绍。
    136. 对此同一业务,通过OTA 菜单触发和透过另外途径触发有怎么样两样?
    答:没有什么样两样,OTA 只是福利用户拔取工作的一种途径。
    137. 怎么自己和本身爱人的OTA 业务菜单不雷同?
   
答:有两种原因:第一、是您和你朋友接纳的套餐有所不同,中国电信本着不同的套餐用户制定了不同的OTA
业务菜单;第二、可能是你要么您爱人对OTA
菜单举办了删减、扩展、定制等个性化操作导致的;第三、中国电信会依据不同的用户群推送一些利用,用户可以通过网站下载。
    138. OTA
菜单中有好多是自己不需要的,能否把那么些食谱删除掉?删除后,对另外OTA
业务有没有影响?
   
答:用户可以对这些允许删除的菜谱举办删减,对此外OTA业务不会促成影响。
    139. 自己在网站上添加新的OTA
菜单后,手机上从未有过立异,怎么做?我不时用的事务由于层级操作太多,每一遍使用都很勤奋,有什么样办法可以化解这些问题?
   
答:用户可以通过在顶峰或者登陆门户网站,利用音讯同步操作举办菜单更新
    140. OTA 卡丢失后,能补办吗?
    答:OTA
卡挂失后得以到营业厅办理补卡,费用按标准UIM卡补卡手续费收取,OTA
卡的工作菜单按最新专业推行。
    141. OTA 卡作业是不是只有起始的那几个使用?
    答:不是的,中国电信会日常更新OTA
应用,用户可以透过在顶峰或者门户网站上开展菜单搜索操作找到自己喜爱的OTA
业务举办下载。
    142. 怎么我的无绳电话机看不到OTA 业务菜单,而其外人可以OTA
上的政工能无法设置密码,避免外人利用?
    答:OTA 卡是基于UTK 技术来实现的,如今市面上绝大多数无线电话都是UTK
手机,都能支撑OTA 卡片。若是反映OTA 卡片放出手机后,看不到OTA
菜单,是由于手机的型号相比旧,不可能支撑UTK
技术所导致的,但仍旧有着普通UIM 卡的成效,如打电话、发短信等。备注:UTK
是UIM Tool 基特 的简称,意思是UIM 卡增值工具包,是GSM
规范定义的无绳电话机和卡期间通讯的一个标准规范,基于该标准,就可以在UIM
卡上贯彻广大的增值服务,从最后用户看来,就能看到卡上各样事务菜单。
    143. 当自家删除OTA
卡上的工作菜单后,卡片指示“删除成功”音讯,我按确认键后怎么手机会自动发送信息出去?
    答:因为OTA 卡片是和后台的OTA
服务器配合工作的,所以当用户删除卡片上的某个业务菜单后,卡片需要发送一条短音信告知服务器卡片上该事情菜单已经被删除了,这样OTA
卡片才能和服务器保持同步,当用户登录网站开展网上业务菜单的定制和删除时也恐怕看到和手机上一模一样的政工菜单了。
    (十二)BREW 业务
    144. 怎么退订BREW 业务?
   
答:唯有包月类资费的施用需要退定,下载类资费的运用无需退定。包月格局的退订可以由用户自己在手机上完成。
    145. 怎么利用手机退订BREW 业务?
   
答:在手机上退定的章程是:进入【软件超市】-【功效设置】-【软件安装】-选用某个应用,如【Happy
原唱魔铃】-采纳【撤消订购/删除】即可。退定成功后,不要顿时断开连接,稍等一会,以管教手机端发起的请求能打响到达服务器。
    146. 比方用户手机不见或换卡后,如何退订BREW 业务?
   
答:如若用户手机遗失或换卡,您可以携带有效证件到营业厅或拨打中国电信客户服务热线10000,由专业人士帮忙您退订。
    147. 若接纳多部手机下载同一个使用,怎么样收费?
   
答:若您使用多部手机下载同一个施用时,如若是包月类的费用,则同一个月内,只扣费四次。假使是下载类资费的作业,则下载五回收费三遍。
    扩展的分解口径:
    1、为啥要开展跨C网的用户账单拆分工作
   
遵照工业和音信化部、国家发展和改革委员会及财政部《关于深化电信体制立异的通报》,中国联通将向中国电信出售CDMA资产及作业。
   
鉴于CDMA业务交接后,由于技术和计费系统的范围,中国联通将无法继续向用户提供跨C网(即同时提到CDMA业务和中国联通其他工作,下同)的联合账单工作。
    2、跨C网统一的帐户是怎么拆分的?
    帐户的拆分原则是:
   
1)已享受CDMA手机补贴且未到期的用户,其账户内的预存款优先用于分享手机补贴账户的消费,总结协议金额与事实上消费额的差额,另外部分平均划转到其他G网号码。
   
2)未分享CDMA手机补贴或已协议到期的用户不再区分主账户,指出你按照默认拆分方案组成用户意愿进行拆分;默认拆分方案为:将同样合并账户下的预存款余额在各号码之间平均分配;如你不同意,可比照用户要求比例在账户间分配。
    以上拆分原则于2008 年八月27日在营业厅作出通告。
    系统推行账户拆分操作在十二月30日到位。
    3、跨C网联合的帐户拆分后我会受到如何影响?
    从帐户用户:
   
拆分后您就是独自计费独立出帐单的用户,需要您单独交费,而不可能依赖原来的主帐户交费了。
    主帐户用户:
   
拆分后对你没有什么样较大的震慑,就是拆分前依附您的从帐户已经独自出来了,不再从你的帐户上同步扣费了。您现在帐户上的资费就是你那些编号爆发的。
    4、我不容许这么的账户拆分原则,我要继续运用跨C网的账户合并效用。
   
遵照国家对电信行业构成的要求,中国联通向中国电信发售CDMA资产及作业,鉴于技术和计费系统的范围,中国联通将不可以持续向您提供跨C网的会面账单工作,付费帐户拆分是必须形成的。此次拆分仅影响您的付费格局和发票合打功效,您使用的资费套餐和优越将继承封存。因而给您带来的困难,敬请谅解。
    拆分方法见问题2
    5、账户拆分24时辰后因用户余额不足造成的停机解释口径。
    处理方案:
    处理方案1:如若用户是挟持拆分的。
   
告知用户:由于3月30日我们得不到与你得到联系,系统已于九月30日将您合并账户下的预存款余额按照拆分原则(见问题2答复)举行了分红。对于拆分后24钟头内,无论你各号码的账户余额多少,我们将确保你健康使用,为力保你将来连续可以正常使用,请你顿时查询各号码的余额,并为余额不足的数码缴费。
    处理方案2:要是用户是已赢得联络的且自己指定分配原则的。
   
告知用户,我们已与您取得联络,并按照你的希望将预存款余额划到另外帐户,对于拆分后24钟头内,无论你各号码的账户余额多少,大家将保险你的正常使用,为力保你将来连续可以正常使用,请你顿时查询各号码的余额,并为余额不足的数码缴费。
    处理方案3:假使用户是联系上的按默认拆分方案处理的。
   
告知用户,我们已与您拿到联络,并向你介绍了俺们的默认处理方案,您顿时已同意按此方案处理,对于拆分后24时辰内,无论你各号码的账户余额多少,咱们将保险你健康使用,为保证你将来连续可以健康使用,请你及时查询各号码的余额,并为余额不足的号码缴费。
   

前言:PetShop是一个范例,微软用它来显示.Net公司系统开发的能力。业界有许多.Net与J2EE之争,许多数目是从微软的PetShop和Sun的PetStore而来。这种争辩不可防止带有深远的买卖色彩,对于大家开发人士而言,没有必要过多关心。不过PetShop随着版本的不断更新,至后日基于.Net
2.0的PetShop4.0收场,整个计划渐渐变得干练而雅致,却又很多方可借鉴之处。PetShop是一个袖珍的项目,系统架构与代码都相比较简单,却也可见了广大颇有价值的计划与付出理念。本系列试图对PetShop作一个全副的解剖,按照的代码是PetShop4.0,可以从链接
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnbda/html/bdasamppet4.asp中获得。

一、PetShop的系列架构设计

在软件系列架构设计中,分层式结构是最常见,也是最着重的一种结构。微软引进的分层式结构相似分为三层,从下至上个别为:数据访问层、业务逻辑层(又或成为世界层)、表示层,如图所示:

图片 1
图一:三层的分层式结构

多少访问层:有时候也号称是持久层,其功效首假使承受数据库的走访。简单的传教就是实现对数据表的Select,Insert,Update,Delete的操作。倘诺要参预ORM的因素,那么就会包括对象和数据表之间的mapping,以及对象实体的持久化。在PetShop的多寡访问层中,并没有使用ORM,从而导致了代码量的扩充,可以当作是整套规划实现中的一大缺陷。

工作逻辑层:是全方位体系的中坚,它与这些系统的工作(领域)有关。以PetShop为例,业务逻辑层的连带计划,均和网上宠物店特有的逻辑相关,例如查询宠物,下订单,添加宠物到购物车等等。尽管涉及到数据库的拜访,则调用数据访问层。

表示层:是系统的UI部分,负责使用者与任何系统的互相。在这一层中,理想的气象是不应包括系统的事情逻辑。表示层中的逻辑代码,仅与界面元素有关。在PetShop中,是采纳ASP.Net来规划的,因而包含了成百上千Web控件和连锁逻辑。

分层式结构究竟其优势何在?马丁(Martin) 福勒(Fowler)在《Patterns of Enterprise
Application Architecture》一书中提交了答案:
1、开发人士可以只关心整整结构中的其中某一层;
2、能够很容易的用新的落实来替换原有层次的实现;
3、可以降低层与层之间的借助;
4、有利于规范;
5、利于各层逻辑的复用。

包括来说,分层式设计可以达至如下目标:分散关注、松散耦合、逻辑复用、标准定义。

一个好的分层式结构,可以使得开发人士的分工更加强烈。一旦定义好各层次之间的接口,负责不同逻辑设计的开发人士就可以分散关注,不相上下。例如UI人士只需考虑用户界面的心得与操作,领域的计划人士可以仅关注业务逻辑的筹划,而数据库设计人员也不必为繁琐的用户交互而发烧了。每个开发人士的任务得到了认同,开发进度就能够长足的增进。

麻痹大意耦合的裨益是醒目标。假若一个连串尚未分支,那么各自的逻辑都密不可分缠绕在联合,互相间相互依赖,谁都是不可替换的。一旦暴发改变,则牵一发而动全身,对项目的震慑颇为深重。降低层与层间的倚重性,既可以优秀地保管将来的可增添,在复用性上也是优势有目共睹。每个功效模块一旦定义好统一的接口,就可以被依次模块所调用,而不用为相同的功能举行重复地付出。

展开好的分层式结构设计,标准也是必不可少的。只有在一定水平的基准基础上,那么些系统才是可扩充的,可替换的。而层与层之间的通信也自然保证了接口的规则。

“金无足赤,人无完人”,分层式结构也不可制止具有局部欠缺:
1、降低了系统的性能。这是肯定的。假诺不应用分层式结构,很多业务可以直接访问数据库,以此博得相应的数码,近日却必须经过中间层来成功。
2、有时会导致级联的修改。这种修改尤其体现在自上而下的可行性。倘诺在表示层中需要充实一个效能,为力保其设计适合分层式结构,可能需要在相应的事情逻辑层和数量访问层中都追加对应的代码。

前边提到,PetShop的表示层是用ASP.Net设计的,也就是说,它应是一个BS系统。在.Net中,标准的BS分层式结构如下图所示:

图片 2
图二:.Net中标准的BS分层式结构

趁着PetShop版本的换代,其分层式结构也在相连的面面俱到,例如PetShop2.0,就没有运用正式的三层式结构,如图三:

图片 3
图三:PetShop 2.0的系列架构

从图中我们得以看来,并没有明确的多少访问层设计。这样的宏图尽管提升了多少访问的属性,但也还要招致了政工逻辑层与数量访问的职责混乱。一旦要求扶助的数据库暴发变化,或者需要修改数据访问的逻辑,由于没有清晰的支行,会导致项目作大的修改。而随着硬件系统性能的增长,以及充裕利用缓存、异步处理等体制,分层式结构所带来的习性影响几乎可以忽略不计。

PetShop3.0纠正了从前层次不明的题材,将数据访问逻辑作为单身的一层独立出来:

图片 4
图四:PetShop 3.0的系统架构

PetShop4.0差不多延续了3.0的结构,但在性质上作了必然的改革,引入了缓存和异步处理体制,同时又充足利用了ASP.Net
2.0的新效用MemberShip,因而PetShop4.0的连串架构图如下所示:

图片 5
图五:PetShop 4.0的序列架构

正如3.0和4.0的系统架构图,其基本的情节并不曾暴发变化。在数量访问层(DAL)中,依然采纳DAL
Interface抽象出多少访问逻辑,并以DAL
Factory作为数据访问层对象的工厂模块。对于DAL
Interface而言,分别有匡助MS-SQL的SQL Server DAL和支撑Oracle的Oracle
DAL具体落实。而Model模块则带有了数量实体对象。其详细的模块结构图如下所示:

图片 6
图六:数据访问层的模块结构图

可以看到,在数量访问层中,完全使用了“面向接口编程”思想。抽象出来的IDAL模块,脱离了与实际数据库的依赖,从而使得整个数据访问层利于数据库迁移。DALFactory模块专门管理DAL对象的创建,便于工作逻辑层访问。SQLServerDAL和OracleDAL模块均实现IDAL模块的接口,其中蕴含的逻辑就是对数据库的Select,Insert,Update和Delete操作。因为数据库类型的不等,对数据库的操作也截然不同,代码也会为此有所区别。

其它,抽象出来的IDAL模块,除了拔除了向下的借助之外,对于其上的事情逻辑层,同样仅设有弱倚重关系,如下图所示:

图片 7
图七:业务逻辑层的模块结构图

图七中BLL是业务逻辑层的着力模块,它涵盖了整整类此外为主业务。在工作逻辑层中,无法直接访问数据库,而必须经过数据访问层。注意图中对数码访问工作的调用,是透过接口模块IDAL来完成的。既然与具象的数据访问逻辑无关,则层与层之间的关联就是高枕无忧耦合的。假诺此时急需修改数据访问层的现实性贯彻,只要不关乎到IDAL的接口定义,那么业务逻辑层就不会碰着其他影响。毕竟,具体实现的SQLServerDAL和OracalDAL根本就与业务逻辑层没有点儿关系。

因为在PetShop
4.0中引入了异步处理体制。插入订单的国策可以分为同步和异步,两者的插入策略分明不同,但对于调用者而言,插入订单的接口是全然一致的,所以PetShop
4.0中规划了IBLLStrategy模块。尽管在IBLLStrategy模块中,仅仅是概括的IOrderStategy,但与此同时也提交了一个范例和信息,这就是在作业逻辑的处理中,即便存在工作操作的多样化,或者是然后也许的变通,均应选取抽象的法则。或者采纳接口,或者拔取抽象类,从而脱离对现实事情的依赖性。但是在PetShop中,由于工作逻辑相对简单,这种考虑体现得不够明确。也正因为此,PetShop将中央的事务逻辑都放到了一个模块BLL中,并不曾将切实的贯彻和虚幻严苛的遵照模块分开。所以表示层和工作逻辑层之间的调用关系,其耦合度相对较高:

图片 8
图八:表示层的模块结构图

在图五中,各样层次中还引入了帮衬的模块,如数据访问层的Messaging模块,是为异步插入订单的效用提供,采取了MSMQ(Microsoft
Messaging Queue)技术。而表示层的CacheDependency则提供缓存功效。

二、PetShop数据访问层之数据库访问计划
在多重一中,我从总体上分析了PetShop的架构设计,并提及了分支的定义。从本有的起始,我将依次对各层举行代码级的剖析,以求拿到进一步密切而深深的知道。在PetShop
4.0中,由于引入了ASP.Net
2.0的部分新特征,所以数据层的始末也愈来愈的普遍和复杂性,包括:数据库访问、Messaging、MemberShip、Profile四部分。在系列二中,我将介绍有关数据库访问的计划。

在PetShop中,系统需要处理的数据库对象分为两类:一是数据实体,对应数据库中相应的数据表。它们并未作为,仅用于表现对象的数量。这多少个实体类都被放置Model程序集中,例如数据表Order对应的实业类OrderInfo,其类图如下: 

图片 9

这一个目标并不享有持久化的功效,简单地说,它们是用作数据的载体,便于工作逻辑针对相应数据表进行读/写操作。尽管那些类的习性分别映射了数据表的列,而每一个对象实例也刚好对应于数据表的每一行,但这一个实体类却并不抱有相应的数据库访问能力。

是因为数量访问层和事务逻辑层都将对这个数据实体举办操作,由此先后集Model会被这两层的模块所引用。

第二类数据库对象则是数码的事情逻辑对象。这里所指的事体逻辑,并非业务逻辑层意义上的领域(domain)业务逻辑(从这一个意思上,我更倾向于将事情逻辑层称为“领域逻辑层”),一般意义上说,这多少个工作逻辑即为基本的数据库操作,包括Select,Insert,Update和Delete。由于这一个事情逻辑对象,仅具有行为而与数量无关,由此它们均被架空为一个独自的接口模块IDAL,例如数据表Order对应的接口IOrder: 

图片 10

将数据实体与连锁的数据库操作分离出来,符合面向对象的动感。首先,它映现了“职责分开”的规则。将数据实体与其行事分开,使得两者之间倚重收缩,当数码作为发出转移时,并不影响Model模块中的数据实体对象,防止了因一个类职责过多、过大,从而造成该类的引用者暴发“灾难性”的影响。其次,它展现了“抽象”的饱满,或者说是“面向接口编程”的特级展现。抽象的接口模块IDAL,与现实的数据库访问实现完全隔绝。这种与贯彻无关的计划性,保证了系统的可扩展性,同时也确保了数据库的可移植性。在PetShop中,可以帮忙SQL
Server和Oracle,那么它们具体的实现就各自放在五个不等的模块SQLServerDAL、OracleDAL中。

以Order为例,在SQLServerDAL、OracleDAL多少个模块中,有不同的贯彻,但它们同时又都落实了IOrder接口,如图: 

图片 11

从数据库的兑现来看,PetShop显示出了从未ORM框架的交汇与丑陋。由于要对数据表举办Insert和Select操作,以SQL
Server为例,就动用了SqlCommand,SqlParameter,SqlDataReader等对象,以成功这么些操作。尤其复杂的是Parameter的传递,在PetShop中,使用了大量的字符串常量来保存参数的名目。其它,PetShop还专门为SQL
Server和Oracle提供了纸上谈兵的Helper类,包装了一些常用的操作,如ExecuteNonQuery、Execute里德(Reade)r等方法。

在并未ORM的动静下,使用Helper类是一个相比较好的方针,利用它来形成数据库基本操作的卷入,可以减去过多和数据库操作有关的代码,这反映了对象复用的规格。PetShop将那么些Helper类统一置于DBUtility模块中,不同数据库的Helper类显露的艺术基本相同,只除了部分非常的要求,例如Oracle中处理bool类型的模式就和SQL
Server不同,从而专门提供了OraBit和OraBool方法。其余,Helper类中的方法均为static方法,以利于调用。OracleHelper的类图如下: 

图片 12

对于数据访问层来说,最头痛的是SQL语句的处理。在初期的CS结构中,由于未使用三层式架构设计,数据访问层和业务逻辑层是严密糅合在一块的,因而,SQL语句遍布与系统的每一个角落。这给程序的保安带来巨大的劳顿。其它,由于Oracle使用的是PL-SQL,而SQL
Server和Sybase等应用的是T-SQL,两者虽然都按照了业内SQL的语法,但在诸多细节上仍有分别,假如将SQL语句大量的施用到程序中,无疑为可能的数据库移植也牵动了费劲。

最好的法门是运用储存过程。这种模式使得程序更为清洁,此外,由于存储过程可以以数据库脚本的情势存在,也便宜移植和改动。但这种措施依旧有毛病。一是储存过程的测试相对困难。虽然有对应的调试工具,但比起对代码的调剂而言,依然比较复杂且不便利。二是对系统的翻新带来阻力。假使数据库访问是由程序完成,在.Net平台下,我们仅需要在改动程序后,将再也编译的顺序集xcopy到布置的服务器上即可。假如运用了仓储过程,出于安全的考虑,必须有专门的DBA重新运行存储过程的脚本,部署的艺术遭到了限定。

本身已经在一个类型中,利用一个特意的表来存放SQL语句。如要使用相关的SQL语句,就拔取重点字搜索拿到对应语句。这种做法近似于存储过程的调用,但却制止了安排上的题目。不过这种方式却在性质上无法取得保险。它仅符合于SQL语句较少的景观。不过,利用雅观的设计,我们可以为各种事务提供不同的表来存放SQL语句。同样的道理,这么些SQL语句也可以存放到XML文件中,更便宜系统的扩大或改动。不过前提是,我们需要为它提供特其余SQL语句管理工具。

SQL语句的采取无法避免,怎么样更好的施用SQL语句也无定论,但有一个标准化值得大家坚守,就是“应该尽可能让SQL语句尽存在于数量访问层的具体贯彻中”。

本来,如若拔取ORM,那么万事就变得不同了。因为ORM框架已经为多少访问提供了着力的Select,Insert,Update和Delete操作了。例如在NHibernate中,我们可以直接调用ISession对象的Save方法,来Insert(或者说是Create)一个数码实体对象:
public void Insert(OrderInfo order)
{
    ISession s = Sessions.GetSession();
    ITransaction trans = null;
    try
    {
    trans = s.BeginTransaction();
      s.Save( order);
      trans.Commit();
    }
    finally
    {
      s.Close();
    }
}

从未有过SQL语句,也尚未这个烦人的Parameters,甚至不需要专门去考虑工作。其它,那样的宏图,也是与数据库无关的,NHibernate可以通过Dialect(方言)的体制匡助不同的数据库。唯一要做的是,大家需要为OrderInfo定义hbm文件。

自然,ORM框架并非是文武双全的,面对纷繁复杂的事务逻辑,它并无法一心扑灭SQL语句,以及代表复杂的数据库访问逻辑,但它却很好的反映了“80/20(或90/10)法则”(也被叫做“帕累托法则”),也就是说:花相比少(10%-20%)的劲头就可以缓解大部分(80%-90%)的问题,而要解决剩余的少部分题材则需要多得多的着力。至少,这么些在数量访问层中据为己有了三头的CRUD操作,通过采取ORM框架,我们就仅需要提交极少数岁月和活力来化解它们了。这的确裁减了方方面面项目开发的周期。

仍然回到对PetShop的探究上来。现在大家已经有了数量实体,数据对象的空洞接口和兑现,可以说关于数据库访问的主导就曾经形成了。留待大家的还有四个问题亟待缓解:
1、数据对象创设的田间管理
2、利于数据库的移植

在PetShop中,要创制的多少对象包括Order,Product,Category,Inventory,Item。在眼前的宏图中,这多少个目标已经被架空为相应的接口,而其实现则基于数据库的不同而有所不同。也就是说,创造的对象有多种门类,而每种档次又有两样的兑现,这是突出的肤浅工厂情势的行使场景。而地点所述的六个问题,也都可以通过架空工厂格局来化解。标准的纸上谈兵工厂情势类图如下: 

图片 13

比如,创造SQL Server的Order对象如下:
PetShopFactory factory = new SQLServerFactory();
IOrder = factory.CreateOrder();

要考虑到数据库的可移植性,则factory必须作为一个全局变量,并在主程序运行时被实例化。但如此的筹划即便一度高达了“封装变化”的目的,但在创设PetShopFactory对象时,仍不可防止的产出了具体的类SQLServerFactory,也即是说,程序在这多少个局面上发生了与SQLServerFactory的强倚重。一旦整个系列要求帮忙Oracle,那么还索要修改这行代码为:
PetShopFactory factory = new OracleFactory();

修改代码的这种行为显明是不可接受的。解决的措施是“依赖注入”。“倚重注入”的效益通常是用特另外IoC容器提供的,在Java平台下,那样的容器包括Spring,PicoContainer等。而在.Net平台下,最普遍的则是Spring.Net。但是,在PetShop系统中,并不需要专门的容器来贯彻“依赖注入”,简单的做法仍旧利用配置文件和反光功用来落实。也就是说,我们可以在web.config文件中,配置好具体的Factory对象的共同体的类名。但是,当我们运用配置文件和反光功效时,具体工厂的创导就显示有些“画蛇添足”了,我们完全可以在部署文件中,直接指向具体的数据库对象实现类,例如PetShop.SQLServerDAL.IOrder。那么,抽象工厂形式中的相关工厂就足以简化为一个厂子类了,所以自己将这种情势称之为“具有简易工厂特质的纸上谈兵工厂模式”,其类图如下: 

图片 14

DataAccess类完全代表了面前创制的厂子类体系,它是一个sealed类,其中创立各样数码对象的不二法门,均为静态方法。之所以能用这么些类达到抽象工厂的目标,是因为安排文件和反光的运用,如下的代码片断所示:
public sealed class DataAccess
{
 // Look up the DAL implementation we should be using
    private static readonly string path =
ConfigurationManager.AppSettings[“WebDAL”];
    private static readonly string orderPath =
ConfigurationManager.AppSettings[“OrdersDAL”];

 public static PetShop.IDAL.IOrder CreateOrder()
 {
         string className = orderPath + “.Order”;
         return
(PetShop.IDAL.IOrder)Assembly.Load(orderPath).CreateInstance(className);
    }
}

在PetShop中,这种借助配置文件和反光创制对象的法门最好广泛,包括IBLLStategy、CacheDependencyFactory等等。这几个实现逻辑散布于一切PetShop系统中,在我看来,是可以在此基础上举行重构的。也就是说,我们得以为总体体系提供类似于“Service(Service)Locator”的贯彻:
public static class ServiceLocator
{
 private static readonly string dalPath =
ConfigurationManager.AppSettings[“WebDAL”];
    private static readonly string orderPath =
ConfigurationManager.AppSettings[“OrdersDAL”];
 //……
 private static readonly string orderStategyPath =
ConfigurationManager.AppSettings[“OrderStrategyAssembly”];

 public static object LocateDALObject(string className)
 {
  string fullPath = dalPath + “.” + className;
  return Assembly.Load(dalPath).CreateInstance(fullPath);
 }
public static object LocateDALOrderObject(string className)
 {
  string fullPath = orderPath + “.” + className;
  return Assembly.Load(orderPath).CreateInstance(fullPath);
 }
public static object LocateOrderStrategyObject(string className)
 {
  string fullPath = orderStategyPath + “.” + className;
  return Assembly.Load(orderStategyPath).CreateInstance(fullPath);
 }
 //……
}

这就是说和所谓“看重注入”相关的代码都得以利用ServiceLocator来成功。例如类DataAccess就足以简化为:
public sealed class DataAccess
{
 public static PetShop.IDAL.IOrder CreateOrder()
 {
     return (PetShop.IDAL.IOrder)ServiceLocator.
LocateDALOrderObject(“Order”);
  }
}

经过Service(Service)Locator,将具备与配置文件有关的namespace值统一保管起来,这有利于各种动态创造对象的军事管制和前途的保障。

 

三、PetShop数据访问层之消息处理

在展开系统规划时,除了对平安、事务等问题予以充分的推崇外,性能也是一个不可防止的问题所在,尤其是一个B/S结构的软件系统,必须充裕地考虑访问量、数据流量、服务器负荷的问题。解决性能的瓶颈,除了对硬件系统开展升级外,软件设计的客体尤为重大。
在头里我曾提到,分层式结构设计可能会在大势所趋程度上影响多少访问的特性,可是与它给规划职员拉动的益处相相比较,几乎可以忽略。要提供全套系统的性质,还足以从数据库的优化开首,例如连接池的使用、建立目录、优化查询策略等等,例如在PetShop中就采用了数据库的Cache,对于数据量较大的订单数量,则动用分库的法子为其单独创设了Order和Inventory数据库。而在软件设计上,相比实用的点子是使用多线程与异步处理格局。
在PetShop4.0中,使用了Microsoft Messaging
Queue(MSMQ)技术来形成异步处理,利用音讯队列临时存放要插入的数量,使得数据访问因为不需要拜访数据库从而提供了拜访性能,至于队列中的数据,则等待系统空闲的时候再展开拍卖,将其最后插入到数据库中。
PetShop4.0中的音讯处理,重要分为如下几片段:音信接口IMessaging、音讯工厂MessagingFactory、MSMQ实现MSMQMessaging以及数据后台处理利用程序OrderProcessor。
从模块化分上,PetShop自始自终地执行了“面向接口设计”的尺码,将信息处理的接口与贯彻分开,并经过工厂格局封装信息实现目标的创设,以达到松散耦合的目标。
鉴于在PetShop中仅对订单的处理利用了异步处理格局,由此在信息接口IMessaging中,仅定义了一个IOrder接口,其类图如下:
 图片 15
在对信息接口的贯彻中,考虑到以后的增添中会有任何的数额对象会利用MSMQ,因此定义了一个Queue的基类,实现消息Receive和Send的基本操作:
public virtual object Receive()
{
      try
{
          using (Message message = queue.Receive(timeout,
transactionType))
             return message;
      }
      catch (MessageQueueException mqex)
{
          if (mqex.MessageQueueErrorCode ==
MessageQueueErrorCode.IOTimeout)
             throw new TimeoutException();
                throw;
      }
}
public virtual void Send(object msg)
{
      queue.Send(msg, transactionType);
}
其中queue对象是System.Messaging.MessageQueue类型,作为存放数据的体系。MSMQ队列是一个可持久的行列,由此不用顾虑用户不间断地下订单会促成订单数量的不见。在PetShopQueue设置了timeout值,OrderProcessor会遵照timeout值定期扫描队列中的订单数量。
MSMQMessaging模块中,Order对象实现了IMessaging模块中定义的接口IOrder,同时它还持续了基类PetShopQueue,其定义如下:
public class Order:PetShopQueue, PetShop.IMessaging.IOrder
形式的贯彻代码如下:
    public new OrderInfo Receive()
    {
        // This method involves in distributed transaction and need
Automatic Transaction type
        base.transactionType = MessageQueueTransactionType.Automatic;
        return (OrderInfo)((Message)base.Receive()).Body;
    }

    public OrderInfo Receive(int timeout)
    {
        base.timeout =
TimeSpan.FromSeconds(Convert.ToDouble(timeout));
        return Receive();
    }

    public void Send(OrderInfo orderMessage)
    {
        // This method does not involve in distributed transaction and
optimizes performance using Single type
        base.transactionType = MessageQueueTransactionType.Single;
        base.Send(orderMessage);
    }
据此,最终的类图应该如下:
 图片 16
专注在Order类的Receive()方法中,是用new关键字而不是override关键字来重写其父类PetShopQueue的Receive()虚方法。因而,淌假如实例化如下的目的,将会调用PetShopQueue的Receive()方法,而不是子类Order的Receive()方法:
PetShopQueue queue = new Order();
queue.Receive();
从统筹上来看,由于PetShop采取“面向接口设计”的尺度,假使大家要创设Order对象,应该采用如下的措施:
IOrder order = new Order();
order.Receive();
设想到IOrder的贯彻有可能的变型,PetShop依然采纳了工厂格局,将IOrder对象的创造用特其它工厂模块举办了包装:
 图片 17
在类QueueAccess中,通过CreateOrder()方法运用反射技术创制正确的IOrder类型对象:
    public static PetShop.IMessaging.IOrder CreateOrder()
    {
        string className = path + “.Order”;
        return
PetShop.IMessaging.IOrder)Assembly.Load(path).CreateInstance(className);
    }
path的值通过安排文件获取:
private static readonly string path =
ConfigurationManager.AppSettings[“OrderMessaging”];
而部署文件中,OrderMessaging的值设置如下:
<add key=”OrderMessaging” value=”PetShop.MSMQMessaging”/>
就此采用工厂格局来顶住对象的开创,是便于在事情层中对其调用,例如在BLL模块中OrderAsynchronous类:
public class OrderAsynchronous : IOrderStrategy
{       
    private static readonly PetShop.IMessaging.IOrder asynchOrder =
PetShop.MessagingFactory.QueueAccess.CreateOrder();
    public void Insert(PetShop.Model.OrderInfo order)
{
        asynchOrder.Send(order);
    }
}
假设IOrder接口的实现发生变化,这种实现模式就足以使得客户仅需要修改配置文件,而不需要修改代码,如此就足以制止程序集的重复编译和布置,使得系统可以灵活应对需要的变更。例如定义一个兑现IOrder接口的SpecialOrder,则可以激增一个模块,如PetShop.SpecialMSMQMessaging,而类名则依旧为Order,那么此时我们仅需要修改配置文件中OrderMessaging的值即可:
<add key=”OrderMessaging” value=”PetShop.SpecialMSMQMessaging”/>
OrderProcessor是一个控制台应用程序,不过可以按照要求将其设计为Windows
Service(Service)。它的目标就是吸纳信息队列中的订单数量,然后将其插入到Order和Inventory数据库中。它应用了多线程技术,以高达提升系统特性的目的。
在OrderProcessor应用程序中,主函数Main用于控制线程,而基本的履行任务则由艺术ProcessOrders()实现:
    private static void ProcessOrders()
    {
        // the transaction timeout should be long enough to handle all
of orders in the batch
        TimeSpan tsTimeout =
TimeSpan.FromSeconds(Convert.ToDouble(transactionTimeout * batchSize));

        Order order = new Order();
        while (true)
        {
            // queue timeout variables
            TimeSpan datetimeStarting = new
TimeSpan(DateTime.Now.Ticks);
            double elapsedTime = 0;

            int processedItems = 0;

            ArrayList queueOrders = new ArrayList();

            using (TransactionScope ts = new
TransactionScope(TransactionScopeOption.Required, tsTimeout))
            {
                // Receive the orders from the queue
                for (int j = 0; j < batchSize; j++)
                {
                    try
                    {
                        //only receive more queued orders if there is
enough time
                        if ((elapsedTime + queueTimeout +
transactionTimeout) < tsTimeout.TotalSeconds)
                        {
                           
queueOrders.Add(order.ReceiveFromQueue(queueTimeout));
                        }
                        else
                        {
                            j = batchSize;   // exit loop
                        }

                        //update elapsed time
                        elapsedTime = new
TimeSpan(DateTime.Now.Ticks).TotalSeconds –
datetimeStarting.TotalSeconds;
                    }
                    catch (TimeoutException)
                    {
                        //exit loop because no more messages are
waiting
                        j = batchSize;
                    }
                }
                //process the queued orders
                for (int k = 0; k < queueOrders.Count; k++)
                {
                    order.Insert((OrderInfo)queueOrders[k]);
                    processedItems++;
                    totalOrdersProcessed++;
                }

                //batch complete or MSMQ receive timed out
                ts.Complete();
            }

            Console.WriteLine(“(Thread Id ” +
Thread.CurrentThread.ManagedThreadId + “) batch finished, ” +
processedItems + ” items, in ” + elapsedTime.ToString() + ”
seconds.”);
        }
    }
首先,它会通过PetShop.BLL.Order类的国有措施ReceiveFromQueue()来取得信息队列中的订单数量,并将其放入到一个ArrayList对象中,但是再调用PetShop.BLL.Order类的Insert方法将其插入到Order和Inventory数据库中。
在PetShop.BLL.Order类中,并不是直接执行插入订单的操作,而是调用了IOrderStrategy接口的Insert()方法:
public void Insert(OrderInfo order)
{
    // Call credit card procesor
    ProcessCreditCard(order);

    // Insert the order (a)synchrounously based on configuration
    orderInsertStrategy.Insert(order);
}
在此间,运用了一个策略情势,类图如下所示:
 图片 18
在PetShop.BLL.Order类中,依然接纳配置文件来动态创立IOrderStategy对象:
private static readonly PetShop.IBLLStrategy.IOrderStrategy
orderInsertStrategy = LoadInsertStrategy();
private static PetShop.IBLLStrategy.IOrderStrategy
LoadInsertStrategy()
{
    // Look up which strategy to use from config file
    string path =
ConfigurationManager.AppSettings[“OrderStrategyAssembly”];
    string className =
ConfigurationManager.AppSettings[“OrderStrategyClass”];

    // Using the evidence given in the config file load the appropriate
assembly and class
    return
(PetShop.IBLLStrategy.IOrderStrategy)Assembly.Load(path).CreateInstance(className);
}
是因为OrderProcessor是一个独门的应用程序,由此它使用的布置文件与PetShop不同,是存放在应用程序的App.config文件中,在该公文中,对IOrderStategy的配备为:
<add key=”OrderStrategyAssembly” value=”PetShop.BLL” />
<add key=”OrderStrategyClass” value=”PetShop.BLL.OrderSynchronous”
/>
从而,以异步格局插入订单的流水线如下图所示:
 图片 19
Microsoft Messaging
Queue(MSMQ)技术除用于异步处理以外,它根本依旧一种分布式处理技术。分布式处理中,一个重大的技艺因素就是有关信息的拍卖,而在System.Messaging命名空间中,已经提供了Message类,可以用来承载信息的传递,前提上音信的发送方与接收方在数据定义上应该统一的接口规范。
MSMQ在分布式处理的应用,在自己插手的品种中早已有了贯彻。在为一个汽车成立商开发一个大型系统时,分销商Dealer作为.Net客户端,需要将数据传递到管理主旨,并且该多大校被Oracle的EBS(E-Business
System)使用。由于分销商管理体系(DMS)接纳的是C/S结构,数据库为SQL
Server,而汽车创制商管理为主的EBS数据库为Oracle。这里就关系到六个系统里面数据的传递。
落实架构如下:
图片 20
     首先Dealer的数额经过MSMQ传递到MSMQ Server,此时可以将数据插入到SQL
Server数据库中,同时使用FTP将数据传送到专门的文本服务器上。然后接纳IBM的EAI技术(公司应用集成,Enterprise
Application
Itegration)定期将文件服务器中的文件,利用接口规范写入到EAI数据库服务器中,并最后写道EBS的Oracle数据库中。
上述架构是一个突出的分布式处理社团,而技术实现的中心就是MSMQ和EAI。由于我们曾经定义了统一的接口规范,在通过音讯队列形成文件后,此时的数量就已经与平台无关了,使得在.Net平台下的分销商管理类别可以与Oracle的EBS集成起来,完成数据的处理。

四、PetShop之ASP.NET缓存

假使对袖珍电脑硬件系统有充裕的问询,那么大家对于Cache这些名词一定是驾轻就熟的。在CPU以及主板的芯片中,都引入了那种名为高速缓冲存储器(Cache)的技巧。因为Cache的存取速度比内存快,因此引入Cache可以有效的化解CPU与内存之间的进度不般配问题。硬件系统可以行使Cache存储CPU访问概率高的这些数据,当CPU需要拜访那个多少时,可以平昔从Cache中读取,而毋庸访问存取速度相对较慢的内存,从而增强了CPU的工作功能。软件设计借鉴了硬件设计中引入缓存的建制以精益求精整个系统的属性,尤其是对此一个数据库驱动的Web应用程序而言,缓存的接纳是不可或缺的,毕竟,数据库查询可能是整整Web站点中调用最频繁但同时又是实践最缓慢的操作之一,咱们不可能被它老迈的双腿拖缓大家前行的征途。缓存机制正是解决这一缺点的加速器。

4.1  ASP.NET缓存概述

用作.Net框架下开发Web应用程序的主打产品,ASP.NET充裕考虑了缓存机制。通过某种情势,将系统需要的数额对象、Web页面存储在内存中,使得Web站点在需要取得那多少个数量时,不需要经过繁琐的数据库连接、查询和复杂性的逻辑运算,就可以“触手可及”,如“瓮中捉鳖”般容易而急忙,从而加强整个Web系统的属性。

ASP.NET提供了二种为主的缓存机制来提供缓存效率。一种是应用程序缓存,它同意开发者将顺序生成的数目或报表工作对象放入缓存中。其它一种缓存机制是页输出缓存,利用它,可以平昔拿走存放在缓存中的页面,而不需要通过繁杂的对该页面的重复拍卖。

应用程序缓存其实现原理说来平淡无奇,仅仅是经过ASP.NET管理内存中的缓存空间。放入缓存中的应用程序数据对象,以键/值对的措施存储,这有利于用户在拜访缓存中的数据项时,可以依照key值判断该项是否留存缓存中。

放入在缓存中的数据对象其生命周期是面临限制的,即便在方方面面应用程序的生命周期里,也不可能担保该数据对象向来有效。ASP.NET可以对应用程序缓存举办保管,例如当数码项无效、过期或内存不足时移除它们。另外,调用者还是可以够透过CacheItemRemovedCallback委托,定义回调方法使得数据项被移除时亦可通告用户。

在.Net
Framework中,应用程序缓存通过System.Web.Caching.Cache类实现。它是一个密封类,无法被延续。对于每一个应用程序域,都要创立一个Cache类的实例,其生命周期与使用程序域的生命周期保持一致。大家得以运用Add或Insert方法,将数据项添加到应用程序缓存中,如下所示:
Cache[“First”] = “First Item”;
Cache.Insert(“Second”, “Second Item”);

咱俩还足以为应用程序缓存添加依赖项,使得倚重项发生变更时,该数额项可以从缓存中移除:
string[] dependencies = {“Second”};
Cache.Insert(“Third”, “Third Item”,
new System.Web.Caching.CacheDependency(null, dependencies));

与之相应的是缓存中数据项的移除。后边提到ASP.NET可以自动管理缓存中项的移除,但大家也得以透过代码编写的章程显式的移除相关的数目项:
Cache.Remove(“First”);

相对于应用程序缓存而言,页输出缓存的拔取越来越宽广。它可以通过内存将处理后的ASP.NET页面存储起来,当客户端再五次访问该页面时,可以节省页面处理的历程,从而加强页面访问的性能,以及Web服务器的吞吐量。例如,在一个电子商务网站里,用户需要平日查询商品信息,这个进程会波及到数据库访问以及查找条件的万分,在数据量较大的处境下,如此的搜寻过程是较为耗时的。此时,利用页输出缓存就可以将率先次搜索拿到的询问结果页存储在缓存中。当用户第二次查询时,就可以节约数据查询的经过,缩短页面的响应时间。

页输出缓存分为整页缓存和一部分页缓存。我们得以经过@OutputCache指令完成对Web页面的输出缓存。它最紧要涵盖几个参数:Duration和VaryByParam。Duration参数用于安装页面或控件举办缓存的时日,其单位为秒。如下的设置表示缓存在60秒内立竿见影:
<%@ OutputCache Duration=“60“ VaryByParam=“none“ %>

尽管没有超过Duration设置的定期值,当用户访问同一的页面或控件时,就能够直接在缓存中得到。
行使VaryByParam参数可以按照设置的参数值建立不同的缓存。例如在一个出口天气预报结果的页面中,倘使需要为一个ID为txtCity的TextBox控件建立缓存,其值将映现某都会的气温,那么我们得以开展如下的安装:
<%@ OutputCache Duration=”60” VaryByParam=”txtCity” %>

如此一来,ASP.NET会对txtCity控件的值举行判断,只有输入的值与缓存值相同,才从缓存中取出相应的值。这就立竿见影地避免了因为值的两样而导致出口错误的数码。

采取缓存的体制对性能的升官很是显明。通过ACT(Application
Center
Test)的测试,可以窥见安装缓存后举办的性能比未安装缓存时的特性足足增强三倍多。

引入缓存看来是提升性能的“完美”解决方案,但是“金无足赤,人无完人”,缓存机制也有毛病,这就是数额过期的题目。一旦应用程序数据仍旧页面结果值发生的变更,那么在缓存有效期范围内,你所收获的结果将是逾期的、不可靠的数据。我们可以想一想股票系统利用缓存所带来的劫数,当您使用错误过期的数码去分析股市的弹指息万变时,你会意识赢得的结果真可以说是“失之毫厘,谬以千里”,看似大好的范围就会像漂亮的泡泡一样,用针一戳,转眼就没有得没有。

那么我们是不是应该为了追求高性能,而不顾所谓“数据过期”所带动的隐患呢?显明,在相近于股票系统这种数据更新往往的特定情景下,数据过期的不好表现如故比低效的属性更令人难以承受。故而,我们需要在性质与数据科学性间作出权衡。所幸的是,.Net
Framework
2.0引入了一种新的缓存机制,它为大家的“鱼与熊掌兼得”带来了技能上的倾向。

.Net
2.0引入的自定义缓存看重项,特别是基于MS-SQL
Server的SqlCacheDependency特性,使得我们得以防止“数据过期”的题材,它能够基于数据库中相应数据的变动,通知缓存,并移除那多少个过期的数码。事实上,在PetShop
4.0中,就充裕地采纳了SqlCacheDependency特性。

4.2 SqlCacheDependency特性

SqlCacheDependency特性实际上是通过System.Web.Caching.SqlCacheDependency类来反映的。通过此类,可以在享有补助的SQL
Server版本(7.0,2000,2005)上监视特定的SQL
Server数据库表,并创制看重于该表以及表中数据行的缓存项。当数据表或表中特定行的多寡暴发改变时,具有看重项的数据项就会失灵,并活动从Cache中除去该项,从而保证了缓存中不再保留过期的数目。
由于版本的原委,SQL Server 2005完全襄助SqlCacheDependency特性,但对于SQL
Server 7.0和SQL Server
2000而言,就从未有过这么幸运了。毕竟这个制品出现在.Net Framework
2.0事先,由此它并没有实现机关监视数据表数据变动,通知ASP.NET的效果。解决的艺术就是行使轮询机制,通过ASP.NET进程内的一个线程以指定的岁月距离轮询SQL
Server数据库,以跟踪数据的更动情状。

要使得7.0要么2000版本的SQL
Server协理SqlCacheDependency特性,需要对数据库服务器执行有关的配置步骤。有三种办法配置SQL
Server:使用aspnet_regsql命令行工具,或者使用SqlCacheDependencyAdmin类。

4.2.1  利用aspnet_regsql工具

aspnet_regsql工具位于Windows\Microsoft.NET\Framework\[版本]文本夹中。即使直接双击该工具的实施文书,会弹出一个带领对话框,提醒大家做到相应的操作:

图片 21
图4-1 aspnet_regsql工具

如图4-1所示中的指示音信,表明该引路重要用于配置SQL
Server数据库,如membership,profiles等音信,假诺要部署SqlCacheDependency,则需要以命令行的措施实施。以PetShop
4.0为例,数据库名为MSPetShop4,则下令为:
aspnet_regsql -S localhost -E -d MSPetShop4 -ed

以下是该工具的命令参数表达:
-?  彰显该工具的声援成效;
-S  后接的参数为数据库服务器的名称或者IP地址;
-U  后接的参数为数据库的登陆用户名;
-P  后接的参数为数据库的登陆密码;
-E  当使用windows集成验证时,使用该功效;
-d  后接参数为对哪一个数据库采纳SqlCacheDependency功用;
-t  后接参数为对哪一个表选拔SqlCacheDependency效率;
-ed  允许对数据库使用SqlCacheDependency效率;
-dd  禁止对数据库接纳SqlCacheDependency效能;
-et  允许对数据表选用SqlCacheDependency效能;
-dt  禁止对数据表采取SqlCacheDependency功用;
-lt  列出当下数据库中有什么表已经采纳sqlcachedependency成效。

以地点的一声令下为例,表达将对名为MSPetShop4的数据库接纳SqlCacheDependency效能,且SQL
Server采取了windows集成验证办法。我们仍可以够对相关的数据表执行aspnet_regsql命令,如:
aspnet_regsql -S localhost -E -d MSPetShop4 -t Item -et
aspnet_regsql -S localhost -E -d MSPetShop4 -t Product -et
aspnet_regsql -S localhost -E -d MSPetShop4 -t Category -et

当执行上述的四条命令后,aspnet_regsql工具会在MSPetShop4数据库中确立一个名为AspNet_SqlCacheTablesForChangeNotification的新数据库表。该数据表包含多少个字段。字段tableName记录要追踪的数据表的称呼,例如在PetShop
4.0中,要记录的数据表就概括Category、Item和Product。notificationCreated字段记录先导追踪的年华。changeId作为一个类型为int的字段,用于记录数据表数据暴发变化的次数。如图4-2所示:

图片 22
图4-2 AspNet_SqlCacheTablesForChangeNotification数据表

而外,执行该命令还会为MSPetShop4数据库添加一组存储过程,为ASP.NET提供查询追踪的数据表的情形,同时还将为使用了SqlCacheDependency的表添加触发器,分别对应Insert、Update、Delete等与数码变动相关的操作。例如Product数据表的触发器:
CREATE TRIGGER dbo.[Product_AspNet_SqlCacheNotification_Trigger] ON
[Product]
    FOR INSERT, UPDATE, DELETE AS BEGIN
    SET NOCOUNT ON
    EXEC dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure N’Product’
END

其中,AspNet_SqlCacheUpdateChangeIdStoredProcedure即是工具添加的一组存储过程中的一个。当对Product数据表执行Insert、Update或Delete等操作时,就会激活触发器,然后实施AspNet_SqlCacheUpdateChangeIdStoredProcedure存储过程。其举办的历程就是修改AspNet_SqlCacheTablesForChangeNotification数据表的changeId字段值:
CREATE PROCEDURE dbo.AspNet_SqlCacheUpdateChangeIdStoredProcedure
             @tableName NVARCHAR(450)
         AS
         BEGIN
             UPDATE dbo.AspNet_SqlCacheTablesForChangeNotification WITH
(ROWLOCK) SET changeId = changeId + 1
             WHERE tableName = @tableName
         END  
GO

4.2.2 
利用SqlCacheDependencyAdmin类

我们也得以应用编程的措施来来管理数据库对SqlCacheDependency特性的应用。该类包含了四个至关首要的艺术:

DisableNotifications 为特定数据库禁用 SqlCacheDependency对象更改通知
DisableTableForNotifications 为数据库中的特定表禁用SqlCacheDependency对象更改通知
EnableNotifications 为特定数据库启用SqlCacheDependency对象更改通知
EnableTableForNotifications 为数据库中的特定表启用SqlCacheDependency对象更改通知
GetTablesEnabledForNotifications 返回启用了SqlCacheDependency对象更改通知的所有表的列表

表4-1
SqlCacheDependencyAdmin类的根本情势

比方大家定义了如下的数据库连接字符串:
const string connectionStr =
“Server=localhost;Database=MSPetShop4”;

这就是说为数据库MSPetShop4启用SqlCacheDependency对象更改通告的实现为:
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)
   {
       SqlCacheDependencyAdmin.EnableNotifications(connectionStr);
   }
}

为数据表Product启用SqlCacheDependency对象更改通告的落实则为:
SqlCacheDependencyAdmin.EnableTableForNotifications(connectionStr,
“Product”);

如果要调用表4-1中所示的相关方法,需要小心的是造访SQL
Server数据库的帐户必须具有成立表和仓储过程的权能。假设要调用EnableTableForNotifications方法,还需要具备在该表上创建SQL
Server触发器的权位。

固然如此说编程形式予以了程序员更大的油滑,但aspnet_regsql工具却提供了更简短的措施实现对SqlCacheDependency的配置与治本。PetShop
4.0施用的难为aspnet_regsql工具的形式,它编写了一个文书名为InstallDatabases.cmd的批处理公事,其中蕴涵了对aspnet_regsql工具的推行,并透过安装程序去调用该文件,实现对SQL
Server的安排。

4.3 在PetShop
4.0中ASP.NET缓存的兑现

PetShop作为一个B2C的宠物网上商店,需要充裕考虑访客的用户体验,如果因为数据量大而招致Web服务器的响应不登时,页面和查询数据迟迟得不到结果,会由此而破坏客户走访网站的心怀,在耗尽耐心的等候后,可能会失掉这一有些客户。无疑,这是特别不好的结果。因此在对其展开系统架构设计时,整个系列的属性就显得殊为首要。不过,大家不可以因噎废食,因为在意于性能而忽略数据的正确。在PetShop
3.0版本以及从前的版本,因为ASP.NET缓存的局限性,这一题目并不曾获取很好的缓解。PetShop
4.0则引入了SqlCacheDependency特性,使得系统对缓存的处理相比从前大为改观。

4.3.1  CacheDependency接口

PetShop
4.0引入了SqlCacheDependency特性,对Category、Product和Item数据表对应的缓存进行了SQL
Cache
Invalidation技术。当对应的数据表数据暴发变更后,该技术可以将相关项从缓存中移除。实现这一技艺的着力是SqlCacheDependency类,它继续了CacheDependency类。但是为了确保所有架构的可扩张性,我们也同意设计者建立自定义的CacheDependency类,用以扩大缓存倚重。这就有必不可少为CacheDependency建立抽象接口,并在web.config文件中举办部署。

在PetShop
4.0的命名空间PetShop.ICacheDependency中,定义了名为IPetShopCacheDependency接口,它仅包含了一个接口方法:
public interface IPetShopCacheDependency
{      
    AggregateCacheDependency GetDependency();
}

AggregateCacheDependency是.Net Framework
2.0新增的一个类,它承受监视看重项对象的集结。当以此集合中的任意一个借助项对象暴发变动时,该依赖项对象对应的缓存对象都将被活动移除。
AggregateCacheDependency类起到了组合CacheDependency对象的职能,它可以将五个CacheDependency对象竟是不同类其它CacheDependency对象与缓存项建立关联。由于PetShop需要为Category、Product和Item数据表建立依赖项,由此IPetShopCacheDependency的接口方法GetDependency()其指标就是重临建立了这个倚重项的AggregateCacheDependency对象。

4.3.2  CacheDependency实现

CacheDependency的落实正是为Category、Product和Item数据表建立了相应的SqlCacheDependency类型的倚重性项,如代码所示:
public abstract class TableDependency : IPetShopCacheDependency
{
    // This is the separator that’s used in web.config
    protected char[] configurationSeparator = new char[] { ‘,’
};

    protected AggregateCacheDependency
dependency = new AggregateCacheDependency();
    protected TableDependency(string configKey)
    {
        string dbName =
ConfigurationManager.AppSettings[“CacheDatabaseName”];
        string tableConfig =
ConfigurationManager.AppSettings[configKey];
        string[] tables =
tableConfig.Split(configurationSeparator);

        foreach (string tableName in
tables)
            dependency.Add(new SqlCacheDependency(dbName, tableName));
    }
    public AggregateCacheDependency GetDependency()
   {
        return dependency;
    }
}

亟需树立依赖项的数据库与数量表都配置在web.config文件中,其安装如下:
<add key=”CacheDatabaseName” value=”MSPetShop4″/>
<add key=”CategoryTableDependency” value=”Category”/>
<add key=”ProductTableDependency” value=”Product,Category”/>
<add key=”ItemTableDependency”
value=”Product,Category,Item”/>

基于各类数据表间的倚重性关系,因此不同的数据表需要建立的依靠项也是不相同的,从布局文件中的value值可以观察。但是无论建立看重项的数目,其创建的表现逻辑都是相似的,因此在统筹时,抽象了一个一起的类TableDependency,并通过创建带参数的构造函数,完成对借助项的成立。由于接口方法GetDependency()的贯彻中,重回的目的dependency是在受保障的构造函数创造的,由此这里的实现模式也足以当做是Template
Method形式的灵活运用。例如TableDependency的子类Product,就是选择父类的构造函数建立了Product、Category数据表的SqlCacheDependency依赖:
public class Product : TableDependency
{
    public Product() : base(“ProductTableDependency”) { }
}

假设急需自定义CacheDependency,那么创制依赖项的法门又有两样。然则无论是开创SqlCacheDependency对象,仍旧自定义的CacheDependency对象,都是将这么些依赖项添加到AggregateCacheDependency类中,因此大家也得以为自定义CacheDependency建立专门的类,只要实现IPetShopCacheDependency接口即可。

4.3.3  CacheDependency工厂

接轨了纸上谈兵类TableDependency的Product、Category和Item类均需要在调用时成立各自的目的。由于它们的父类TableDependency实现了接口IPetShopCacheDependency,因此它们也直接实现了IPetShopCacheDependency接口,这为兑现工厂形式提供了前提。

在PetShop
4.0中,依然拔取了部署文件和反光技术来兑现工厂格局。命名空间PetShop.CacheDependencyFactory中,类DependencyAccess即为创制IPetShopCacheDependency对象的工厂类:
public static class DependencyAccess
{       
    public static IPetShopCacheDependency CreateCategoryDependency()
    {
        return LoadInstance(“Category”);
    }
    public static IPetShopCacheDependency CreateProductDependency()
    {
        return LoadInstance(“Product”);
    }
    public static IPetShopCacheDependency CreateItemDependency()
    {
        return LoadInstance(“Item”);
    }
    private static IPetShopCacheDependency LoadInstance(string
className)
    {
        string path =
ConfigurationManager.AppSettings[“CacheDependencyAssembly”];
        string fullyQualifiedClass = path + “.” + className;
        return
(IPetShopCacheDependency)Assembly.Load(path).CreateInstance(fullyQualifiedClass);
    }
}
漫天工厂情势的贯彻如图4-3所示:

图片 23
 图4-3 CacheDependency工厂

虽说DependencyAccess类创设了落实了IPetShopCacheDependency接口的类Category、Product、Item,然则大家之所以引入IPetShopCacheDependency接口,其目的就在于获取成立了看重项的AggregateCacheDependency类型的目的。我们得以调用对象的接口方法GetDependency(),如下所示:
AggregateCacheDependency dependency =
DependencyAccess.CreateCategoryDependency().GetDependency();

为了便利调用者,似乎我们得以对DependencyAccess类举行立异,将原来的CreateCategoryDependency()方法,修改为创立AggregateCacheDependency类型对象的点子。

而是如此的做法扰乱了作为工厂类的DependencyAccess的自家职责,且创设IPetShopCacheDependency接口对象的表现依旧有可能被调用者调用,所以保留原来的DependencyAccess类依然是有必不可少的。

在PetShop
4.0的宏图中,是由此引入Facade形式以有利于调用者更加简便易行地赢得AggregateCacheDependency类型对象。

4.3.4  引入Facade模式

运用Facade形式可以将部分繁杂的逻辑举行打包,以方便调用者对这个扑朔迷离逻辑的调用。就类似提供一个联合的假相一般,将内部的子系统封装起来,统一为一个高层次的接口。一个压倒一切的Facade模式示意图如下所示:

图片 24
图4-4 Facade模式

Facade情势的目标并非要引入一个新的法力,而是在现有效能的基础上提供一个更高层次的悬空,使得调用者可以直接调用,而不用关爱内部的兑现情势。以CacheDependency工厂为例,我们需要为调用者提供拿到AggregateCacheDependency对象的省事方法,由此创设了DependencyFacade类:
public static class DependencyFacade
{
    private static readonly string path =
ConfigurationManager.AppSettings[“CacheDependencyAssembly”];
    public static AggregateCacheDependency GetCategoryDependency()
    {
        if (!string.IsNullOrEmpty(path))
            return
DependencyAccess.CreateCategoryDependency().GetDependency();
        else
            return null;
    }
    public static AggregateCacheDependency GetProductDependency()
    {
        if (!string.IsNullOrEmpty(path))
            return
DependencyAccess.CreateProductDependency().GetDependency();
        else
            return null;
        }
    public static AggregateCacheDependency GetItemDependency()
    {
        if (!string.IsNullOrEmpty(path))
            return
DependencyAccess.CreateItemDependency().GetDependency();
        else
            return null;
    }
}

DependencyFacade类封装了获取AggregateCacheDependency类型对象的逻辑,如此一来,调用者可以调用相关办法取得成立连锁倚重项的AggregateCacheDependency类型对象:
AggregateCacheDependency dependency =
DependencyFacade.GetCategoryDependency();

比起一直调用DependencyAccess类的GetDependency()方法而言,除了艺术更简单之外,同时它还对CacheDependencyAssembly配置节举办了判断,假若其值为空,则赶回null对象。

在PetShop.Web的App_Code文件夹下,静态类WebUtility的GetCategoryName()和GetProductName()方法调用了DependencyFacade类。例如GetCategoryName()方法:
public static string GetCategoryName(string categoryId)
{
     Category category = new Category();
     if (!enableCaching)
            return category.GetCategory(categoryId).Name;

     string cacheKey =
string.Format(CATEGORY_NAME_KEY, categoryId);

     // 检查缓存中是不是存在该数量项;
     string data = (string)HttpRuntime.Cache[cacheKey];
     if (data == null)
     {
           // 通过web.config的配备获取duration值;
           int cacheDuration =
int.Parse(ConfigurationManager.AppSettings[“CategoryCacheDuration”]);
           //
倘诺缓存中不设有该数额项,则经过作业逻辑层访问数据库获取;
           data = category.GetCategory(categoryId).Name;
           // 通过Facade类创建AggregateCacheDependency对象;
           AggregateCacheDependency cd =
DependencyFacade.GetCategoryDependency();
           // 将数据项以及AggregateCacheDependency 对象存储到缓存中;
           HttpRuntime.Cache.Add(cacheKey, data, cd,
DateTime.Now.AddHours(cacheDuration), Cache.NoSlidingExpiration,
CacheItemPriority.High, null);
      }
      return data;
}

GetCategoryName()方法首先会检讨缓存中是不是已经存在CategoryName数据项,如果已经存在,就透过缓存直接获取数据;否则将透过作业逻辑层调用数据访问层访问数据库得到CategoryName,在收获了CategoryName后,会将新取得的数码及其DependencyFacade类创立的AggregateCacheDependency对象添加到缓存中。

WebUtility静态类被表示层的多多页面所调用,例如Product页面:
public partial class Products : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        Page.Title =
WebUtility.GetCategoryName(Request.QueryString[“categoryId”]);
    }
}

显示页面title的逻辑是身处Page_Load事件措施中,由此每一趟打开该页面都要执行获取CategoryName的措施。倘若没有动用缓存机制,当Category数据较多时,页面的呈现就会要命缓慢。

4.3.5  引入Proxy模式

政工逻辑层BLL中与Product、Category、Item有关的政工方法,其实现逻辑是调用数据访问层(DAL)对象访问数据库,以取得有关数据。为了改进系统特性,我们就需要为这么些实现形式增添缓存机制的逻辑。当大家操作扩展了缓存机制的事务对象时,对于调用者而言,应与BLL业务对象的调用保持一致。也即是说,我们需要引入一个新的目的去控制原来的BLL业务对象,这一个新的靶子就是Proxy情势中的代理对象。

以PetShop.BLL.Product业务对象为例,PetShop为其树立了代办对象ProductDataProxy,并在GetProductByCategory()等格局中,引入了缓存机制,例如:
public static class ProductDataProxy
{

    private static readonly int
productTimeout =
int.Parse(ConfigurationManager.AppSettings[“ProductCacheDuration”]);
    private static readonly bool enableCaching =
bool.Parse(ConfigurationManager.AppSettings[“EnableCaching”]);
       
    public static IList
GetProductsByCategory(string category)
    {
        Product product = new Product();

        if (!enableCaching)
            return product.GetProductsByCategory(category);

        string key =
“product_by_category_” + category;
        IList data = (IList )HttpRuntime.Cache[key];

        // Check if the data exists in
the data cache
        if (data == null)
        {
            data = product.GetProductsByCategory(category);

            // Create a
AggregateCacheDependency object from the factory
            AggregateCacheDependency cd =
DependencyFacade.GetProductDependency();

            // Store the output in the
data cache, and Add the necessary AggregateCacheDependency object
            HttpRuntime.Cache.Add(key, data, cd,
DateTime.Now.AddHours(productTimeout), Cache.NoSlidingExpiration,
CacheItemPriority.High, null);
        }
        return data;
    }
}

与事务逻辑层Product对象的GetProductsByCategory()方法相相比,增添了缓存机制。当缓存内不设有相关数据项时,则直接调用业务逻辑层Product的GetProductsByCategory()方法来获取数据,并将其与相应的AggregateCacheDependency对象一起存储在缓存中。

引入Proxy形式,实现了在缓存级别上对工作对象的卷入,增强了对作业对象的控制。由于透露在对象外的方法是如出一辙的,因此对于调用方而言,调用代理对象与真实对象并没有实质的区分。

从职责分开与分支设计的角度分析,我更愿意那多少个Proxy对象是被定义在工作逻辑层中,而不像在PetShop的规划这样,被分开到代表层UI中。此外,假使急需考虑程序的可扩大性与可替换性,我们还足以为真正对象与代理对象建立联合的接口或抽象类。可是,单以PetShop的表示层调用来看,拔取静态类与静态方法的主意,或许更为合理。我们需要谨记,“过度设计”是软件设计的警戒线。

万一需要对UI层选拔缓存机制,将应用程序数据存放到缓存中,就足以调用这一个代理对象。以ProductsControl用户控件为例,调用格局如下:
productsList.DataSource =
ProductDataProxy.GetProductsByCategory(categoryKey);

productsList对象属于自定义的CustomList类型,这是一个派生自System.Web.UI.WebControls.DataList控件的类,它的DataSource属性可以接受IList集合对象。
可是在PetShop
4.0的宏图中,对于类似于ProductsControl类型的控件而言,采取的缓存机制是页输出缓存。我们得以从ProductsControl.ascx页面的Source代码中发觉线索:
<%@ OutputCache Duration=”100000″ VaryByParam=”page;categoryId”
%>

与ASP.NET
1.x的页输出缓存不同的是,在ASP.NET
2.0中,为ASP.NET用户控件新引入了CachePolicy属性,该属性的连串为ControlCachePolicy类,它以编程模式实现了对ASP.NET用户控件的出口缓存设置。大家可以经过设置ControlCachePolicy类的Dependency属性,来安装与该用户控件相关的依赖项,例如在ProductsControl用户控件中,举行如下的安装:
protected void Page_Load(object sender, EventArgs e)
{
    this.CachePolicy.Dependency =
DependencyFacade.GetProductDependency();
}

拔取页输出缓存,并且选拔ControlCachePolicy设置输出缓存,可以将业务数据与任何页面放入到缓存中。这种艺术比起应用程序缓存而言,在性能上有很大的增长。同时,它又经过引入的SqlCacheDependency特性有效地制止了“数据过期”的弱点,因此在PetShop
4.0中被广泛使用。相反,在此以前为Product、Category、Item业务对象建立的代理对象则被“投闲散置”,仅仅作为一种设计格局的显示而“幸存”与所有类此外源代码中。

五 PetShop之业务逻辑层设计
政工逻辑层(Business Logic
Layer)无疑是系统架构中呈现核心价值的局部。它的关注点重要集中在作业规则的制订、业务流程的贯彻等与业务要求有关的连串规划,也即是说它是与系统所应对的天地(Domain)逻辑有关,很多时候,大家也将工作逻辑层称为世界层。例如Martin福勒(Fowler)在《Patterns of Enterprise Application
Architecture》一书中,将所有架构分为六个紧要的层:表示层、领域层和多少源层。作为世界驱动设计的先驱Eric埃文思(Evans)(Evans),对业务逻辑层作了更密切地分开,细分为应用层与世界层,通过分层进一步将世界逻辑与天地逻辑的解决方案分离。

事情逻辑层在系统架构中的地点很关键,它地处数据访问层与表示层中间,起到了数据交换中承上启下的功用。由于层是一种弱耦合结构,层与层之间的倚重性是向下的,底层对于上层而言是“无知”的,改变上层的宏图对于其调用的底部而言没有任何影响。虽然在分层设计时,遵守了面向接口设计的构思,那么这种向下的借助也相应是一种弱倚重关系。因此在不更改接口定义的前提下,理想的分层式架构,应该是一个支撑可抽取、可替换的“抽屉”式架构。正因为这么,业务逻辑层的设计对于一个支撑可扩展的架构尤为重大,因为它扮演了两个例外的角色。对于数据访问层而言,它是调用者;对于表示层而言,它却是被调用者。依赖与被倚重的涉嫌都纠结在工作逻辑层上,怎么样落实依靠关系的解耦,则是除了落实工作逻辑之外留给设计师的职责。

5.1  与领域专家合作
设计工作逻辑层最大的阻力不在于技术,而介于对世界工作的辨析与明白。很难想象一个不熟识该领域工作规则和流程的架构设计师可以统筹出符合客户要求的系统架构。几乎可以下定结论的是,业务逻辑层的筹划过程必须有领域专家的参预。在本人早已踏足开发的档次中,所波及的领域就隐含了电力、半导体、汽车等众多行当,如若紧缺这些世界的大方,软件架构的计划性更为是事情逻辑层的计划就无从谈起。这么些结论唯一的两样是,架构设计师同时又是该领域的专家。不过,正所谓“千军易得,一将难求”,大家很难寻觅到如此优异出众的美貌。

领域专家在集团中饰演的角色一般称为Business
Consultor(业务咨询师),负责提供与世界工作有关的提问,与架构师一起参加架构与数据库的设计,撰写需求文档和统筹用例(或者用户故事User
Story)。倘若在测试阶段,还应该包括撰写测试用例。理想的境况是,领域专家应该参预到方方面面项目标支付过程中,而不只是要求阶段。

领域专家能够是特地聘请的对该领域具有较深造诣的咨询师,也可以是当做需要提供方的客户。在顶峰编程(Extreme
Programming)中,就将客户作为领域专家引入到总体开发公司中。它强调了现场客户标准。现场客户需要加入到计划游戏、开发迭代、编码测试等品种开发的逐条阶段。由于领域专家与设计师以及开发人士组成了一个企业,贯穿开发过程的一贯,就足以制止需求了解错误的图景出现。尽管类型的付出与实际需要不符,也可以在档次先前时期及时更正,从而防止了花色不必要的推迟,加强了对品种经过和本钱的操纵。正如SteveMcConnell在构建移动的早期准备中提及的一个尺码:发现错误的年华要尽可能接近引入该错误的命宫。需求的败笔在系统中隐藏的年月越长,代价就越昂贵。假使在品种开发中可以与领域专家充足的通力合作,就足以最大职能地躲避这样一种恶性的链式反应。

历史观的软件开发模型同样强调与领域专家的通力合作,但这种合作紧要集中在需要分析阶段。例如瀑布模型,就可怜强调早期计划与要求调研。但是那种未雨绸缪的早期计划情势,对架构师与需要调研人口的技艺要求十分高,它强调需要文档的精确性,一旦分析出现错误,或者要求爆发变动,当项目开发进入设计阶段后,由于缺乏与领域专家沟通与协作的体制,开发人员算计不到那个错误与误差,由此难以登时作出修正。一旦这么些题材像毒瘤一般在系统中蔓延开来,渐渐显露在开发人员面前时,已经成了一座难以逾越的高山。大家需要耗费更多的人力物力,才可以修正这些不当,从而致使开发成本成多少级的加码,甚至于导致项目推迟。当然还有一个好的抉择,就是丢弃所有项目。这样的例子比比皆是,事实上,项目支出的“滑铁卢”,究其原因,大部分都是因为业务逻辑分析上出现了问题。

迭代式模型较之瀑布模型有很大地立异,因为它同意变更、优化系统要求,整个迭代过程实际上就是与领域专家的合作过程,通过向客户演示迭代所发出的体系机能,从而及时拿到反馈,并逐项解决迭代演示中冒出的题目,保证系统向着合乎客户需求的势头演化。因此,迭代式模型往往可以解决早期计划不足的题材,它同意在发现缺陷的时候,在要求变动的时候重新设计、重新编码不分轩轾复测试。

不管拔取何种开发模型,与领域专家的协作都将成为门类成败与否的基本点。那基于一个软件开发的普遍真理,那就是社会风气上从未有过不变的需要。一句经典名言是:“没有不变的需求,世上的软件都转移过3次以上,唯一一个只改变过两遍的软件的拥有者已经死了,死在去修改需要的中途。”一语道尽了软件开发的凶残与劳苦!

那么应该怎么样提升与领域专家的协作吗?詹姆斯(James) Carey和布伦特Carlson依据他们在出席的IBM SanFrancisco项目中赢得的经验,提议了Innocent
Questions形式,其含义即“立异领域专家和技术专家的交换质地”。在一个项目集体中,假设大家从没一位既能担任首席架构师,同时又是领域专家的人选,那么加强领域专家与技能专家的通力合作就显得更加重大了。毕竟,作为一个领域专家而言,可能并不熟识软件设计方经济学,也不具有面向对象开发和架构设计的能力,同样,大部分技巧专家很有可能对该项目所涉及的政工领域仅停留在一知半解的境地。尽管领域专家与技能专家不可以使得联系,则全体项目的前程就不定可危了。

Innocent Questions形式提出的缓解方案包括:
(1)拔取可以与人和谐相处的人士组建开发公司;
(2)清楚地定义角色和职权;
(3)明确定义需要的交互点;
(4)保持团队紧密;
(5)雇佣卓越的人。

事实上,这已经从技术的角度上升到对协会的治本层次了。就好比篮球运动一样,即使你的球队会面了五名世界上最一流最有自然的球员,假设各自为战,要想取得竞技的制胜依然是十分费劲的。团队精神与责任明确才是赢得胜利的维系,软件开发同样如此。

与领域专家合作的根基是承保支付社团中永远保存至少一名领域专家。他可以是系统的客户,第三方公司的咨询师,最美观是上下一心公司雇佣的大方。假设项目中不够这样的一个人,那么我的提议是去雇佣他,假若你不想见到项目受到“西伯澳门冷空气”的话。

规定领域专家的角色任务与任务。必须要让团队中的每一个人明明领域专家在总体集体中究竟扮演怎么着的角色,他的天职是何许。一个通关的领域专家必须对工作领域有丰盛深切的敞亮,他应有是一个可以俯瞰整个系统要求、总揽全局的人员。在档次开支进程中,将由他顶住作业规则和流程的制订,负责与客户的关系,需求的调研与商量,并于设计师一起参预系统架构的宏图。编档是领域专家必须出席的办事,无论是需求文档依旧设计文档,以及用例的编制,领域专家或者提出意见,或者作为创作的作者,至少她也应有是评审委员会的重中之重成员。

专业工作领域的术语和技能术语。领域专家和技能专家必须在保管不爆发二义性的语义环境下展开联络与互换。假使出现了然上的冲突,我们必须立刻缓解,通过座谈创设术语标准。很难想象五个语言不通的人可以相互合作愉快,解决的方法是参与一位翻译人士。在领域专家与技能专家之间搭建一座语义上的桥梁,使其可以相互通晓、互相认同。还有一个办法是在集体内部举行作育活动。尤其对于开发人员而言,或多或少地了然一些事务领域知识,对于项目标开支有很大的佑助。在我参加过的半导体领域的类型开发,团队就特意邀请了半导体行业的大家就生产过程的事体逻辑举行了整整的介绍与培育。正所谓“磨刀不误砍柴工”,即便大家花费了培训的时刻,但对于通晓了业务规则与流程的开发人员,却可以晋级项目开发进度,总体上节约了开发成本。

增强与客户的关系。客户同时也得以看作团队的领域专家,极限编程的实地客户标准是最好的以身作则。但实际并不都这么的两全,在不可以要求客户变为开销公司中的固定一员时,聘请或者配置一个特地的领域专家,加强与客户的关联,就显得越发重大。项目得以透过领域专家拿到客户的即时申报。而透过领域专家去精通变更了的急需,会在最大程度上压缩需求误差的恐怕。

5.2  业务逻辑层的格局采取
马丁Fowler在《集团应用架构情势》一书中对天地层(即工作逻辑层)的架构形式作了一体化概括,他将工作逻辑设计分为两种重点的情势:Transaction
Script、Domain Model和Table Module。

Transaction
Script情势将业务逻辑看作是一个个历程,是相比典型的面向过程开发格局。应用Transaction
Script形式可以不需要多少访问层,而是采纳SQL语句直接访问数据库。为了实用地管理SQL语句,可以将与数据库访问有关的行为放到一个特意的Gateway类中。应用Transaction
Script形式不需要太多面向对象知识,简单直接的性状是该形式全体价值之四海。因此,在众多事务逻辑绝对简单的门类中,应用Transaction
Script格局较多。

Domain
Model形式是压倒元白的面向对象设计思想的反映。它丰裕考虑了作业逻辑的复杂多变,引入了Strategy模式等设计格局思想,并通过创立世界对象以及抽象接口,实现格局的可增加性,并动用面向对象思想与身俱来的风味,如连续、封装与多态,用于拍卖复杂多变的政工逻辑。唯一制约该形式应用的是目的与关系数据库的炫耀。我们得以引入ORM工具,或者采纳Data
Mapper格局来完成关系向目标的投射。

与Domain Model情势相似的是Table
Module形式,它同样持有面向对象设计的思辨,唯一不同的是它赢得的目的无须是只是的小圈子对象,而是DataSet对象。假诺为涉及数据表与对象建立一个简单的照射关系,那么Domain
Model情势就是为多少表中的每一条记下建立一个世界对象,而Table
Module形式则是将一切数据表看作是一个全体的目标。尽管拔取DataSet对象会丢掉面向对象的着力特色,但它在为表示层提供数据源扶助地点却具有优秀的优势。尤其是在.Net平台下,ADO.NET与Web控件都为Table
Module格局提供了发育的肥沃土壤。

5.3  PetShop的业务逻辑层设计
PetShop在作业逻辑层设计中引入了Domain
Model情势,这与数码访问层对于数据对象的支撑是分不开的。由于PetShop并没有对宠物网上商店的事务逻辑举行深入,也简要了很多扑朔迷离细节的商务逻辑,由此在Domain
Model情势的利用上并不明确。最出色地应当是对Order领域对象的处理情势,通过引入Strategy形式完成对插入订单行为的包装。关于这或多或少,我已在第27章有了详实的讲述,这里就不再赘言。

本应是系统架构设计中最大旨的业务逻辑层,由于简化了业务流程的缘故,使得PetShop在这一层的统筹有些乏善可陈。尽管在事情逻辑层中,针对B2C业务定义了有关的世界对象,但这多少个领域对象只是是成功了对数据访问层中数量对象的简要封装而已,其目标仅在于分离层次,以支撑对各个数据库的壮大,同时将SQL语句排除在工作逻辑层外,防止了SQL语句的街头巷尾蔓延。

最能体现PetShop业务逻辑的除外对订单的保管之外,还包括购物车(Shopping
Cart)与Wish
List的管理。在PetShop的BLL模块中,定义了Cart类来担负有关的业务逻辑,定义如下:
[Serializable]
public class Cart
{
    private Dictionary cartItems = new Dictionary();
    public decimal Total
    {
        get
        {
            decimal total = 0;
            foreach (CartItemInfo item in cartItems.Values)
                total += item.Price * item.Quantity;
            return total;
        }
    }
    public void SetQuantity(string itemId, int qty)
    {
        cartItems[itemId].Quantity = qty;
    }
    public int Count
    {
        get { return cartItems.Count; }
    }
    public void Add(string itemId)
    {
        CartItemInfo cartItem;
        if (!cartItems.TryGetValue(itemId, out cartItem))
        {
            Item item = new Item();
            ItemInfo data = item.GetItem(itemId);
            if (data != null)
            {
                CartItemInfo newItem = new CartItemInfo(itemId,
data.ProductName, 1, (decimal)data.Price, data.Name, data.CategoryId,
data.ProductId);
                cartItems.Add(itemId, newItem);
            }
        }
        else
            cartItem.Quantity++;
    }
    //其他方法略;
}

Cart类通过一个Dictionary对象来担负对购物车内容的储存,同时定义了Add、Remove、Clear等办法,来兑现对购物车内容的管制。

在前边我提到PetShop业务逻辑层中的领域对象只是是完成对数码对象的简单包装,但那种分离层次的不二法门在架构设计中依然扮演了至关首要的效益。以Cart类的Add()方法为例,在艺术内部引入了PetShop.BLL.Item领域对象,并调用了Item对象的GetItem()方法。假使没有在事情逻辑层封装Item对象,而是直接调用数据访问层的Item数据对象,为保险层次间的弱依赖关系,就需要调用工厂对象的工厂方法来创制PetShop.IDAL.IItem接口类型对象。一旦数据访问层的Item对象被一再调用,就会造成重复代码,既不离于程序的修改与壮大,也招致程序结构生长为臃肿的态势。

另外,领域对象对数码访问层数据对象的卷入,也便于表示层对工作逻辑层的调用。在三层式架构中,表示层应该是对此数据访问层是“无知”的,这样既减弱了层与层间的依靠关系,也能立竿见影防止“循环依赖”的结果。

值得商榷的是Cart类的Total属性。其值的收获是因而遍历购物车聚集,然后加上价格与货物数量的乘积。这里肯定简化了作业逻辑,而从不充分考虑需求的恢宏。事实上,这种获取购物车总价格的算法,在大多数动静下只有是内部的一种政策而已,大家还应该考虑折扣的情况。例如,当总价格抢先100元时,可以赋予顾客肯定的折扣,这是与网站的减价计划有关的。除了给予折扣的打折计划外,网站也足以设想赠送礼品的优惠政策,因而我们有必不可少引入Strategy格局,定义接口IOnSaleStrategy:
public interface IOnSaleStrategy
{
     decimal CalculateTotalPrice(Dictionary cartItems);
}

如此一来,我们可以为Cart类定义一个有参数的构造函数:
private IOnSaleStrategy m_onSale;
public Cart(IOnSaleStrategy onSale)
{
     m_onSale = onSale;
}

那么Total属性就可以修改为:
public decimal Total
{
     get {return m_onSale.CalculateTotalPrice(cartItems);}
}

如此一来,就足以使得Cart类可以使得地协理网站推出的优惠计划,也适合开-闭原则。同样的,这种设计模式也是Domain
Model模式的体现。修改后的宏图如图5-1所示: 

图片 25

图5-1 引入Strategy模式

作为一个B2C的电子商务架构,它所提到的政工领域已为大部分设计师与开发人士所熟练,由此在本例中,与领域专家的通力合作显得并不那么重要。可是,如若我们要开支一个打响的电子商务网站,与领域专家的搭档仍旧是不可或缺的。以订单的田间管理而言,倘若考虑复杂的小买卖利用,就需要管理订单的跟踪(Tracking),与网上银行的协作,账户安全性,库存管理,物流管理,以及客户关系管理(CRM)。整个事情经过却涵盖了诸如电子商务、银行、物流、客户关系学等居多天地,虽然没有领域专家的加入,业务逻辑层的设计也许会“败走麦城”。

5.4  与数据访问层的通信
业务逻辑层需要与数据访问层通信,利用数据访问层访问数据库,因而业务逻辑层与数码访问层之间就存在依靠关系。在多少访问层引入接口程序集以及数据工厂的统筹前提下,可以完成两者间关系为弱看重。我们从事情逻辑层的引用程序集中可以看看,BLL模块并从未引用SQLServerDAL和OracleDAL程序集。在作业逻辑层中,有关数据访问层中多少对象的调用,均采纳多态原理定义了纸上谈兵的接口类型对象,然后使用工厂对象的工厂方法创立具体的数额对象。如PetShop.BLL.PetShop领域对象所示:
namespace PetShop.BLL
{
    public class Product
    {
    //按照工厂对象创造IProduct接口类型实例;
        private static readonly IProduct dal = 
PetShop.DALFactory.DataAccess.CreateProduct();       
        //调用IProduct对象的接口方法GetProductByCategory();
  public IList
GetProductsByCategory(string category)
  {
   // 假若为空则新建List对象;
   if(string.IsNullOrEmpty(category))
    return new List ();

   // 通过数量访问层的多寡对象访问数据库;
   return dal.GetProductsByCategory(category);
  }
        //其他方法略;
    }
}

在世界对象Product类中,利用多少访问层的工厂类DALFactory.DataAccess创造PetShop.IDAL.IProduct类型的实例,如此就足以免去对切实程序集SQLServerDAL或OracleDAL的借助。只要PetShop.IDAL的接口方法不变,虽然修改了IDAL接口模块的切实落实,都不会影响工作逻辑层的兑现。这种松散的弱耦合关系,才可以最大程度地匡助架构的可增添。

天地对象Product实际上还完成了对数据对象Product的卷入,它们透露在外的接口方法是同等地,正是通过包装,使得表示层可以完全退出数据库以及数据访问层,表示层的调用者仅需要关爱工作逻辑层的兑现逻辑,以及世界对象暴露的接口和调用情势。事实上,只要规划合理,规范了逐条层次的接口方法,三层式架构的统筹完全可以分别开由不同的开发人士同时开发,这就足以有效地应用开发资源,裁减项目开发周期。

5.5  面向接口设计
兴许是业务逻辑相比简单地缘故,在事情逻辑层的计划中,并没有秉承在多少访问层中面向接口设计的盘算。除了成功对插入订单策略的肤浅外,整个事情逻辑层仅以BLL模块实现,没有为世界对象定义抽象的接口。由此PetShop的表示层与工作逻辑层就存在强看重关系,假如事情逻辑层中的需求发生变更,就决然会影响表示层的贯彻。唯一可堪欣慰的是,由于我们应用分层式架构将用户界面与工作领域逻辑完全分离,一旦用户界面暴发变更,例如将B/S架构修改为C/S架构,那么业务逻辑层的贯彻模块是可以完全重用的。

只是,最特出的章程还是是面向接口设计。依照第28章对ASP.NET缓存的解析,我们可以将意味层App_Code下的Proxy类与Utility类划分到事情逻辑层中,并修改这多少个静态类为实例类,并将这一个类中与业务领域有关的点子抽象为接口,然后建立如数据访问层一样的虚幻工厂。通过“依赖注入”模式,解除与现实领域对象类的借助,使得表示层仅依靠于事情逻辑层的接口程序集以及工厂模块。

这就是说,这样的宏图是否有“过度设计”的疑虑呢?大家需要按照工作逻辑的需求情形而定。另外,要是我们需要引入缓存机制,为世界对象创设代理类,那么为世界对象建立接口,就展现更加必要。我们得以创设一个特意的接口模块IBLL,用以定义领域对象的接口。以Product领域对象为例,我们得以创设IProduct接口:
public interface IProduct
{
   IList GetProductByCategory(string category);
   IList GetProductByCategory(string[] keywords);
   ProductInfo GetProduct(string productId);
}

在BLL模块中可以引入对IBLL程序集的依赖,则领域对象Product的概念如下:
public class Product:IProduct
{
  public IList GetProductByCategory(string category) { //实现略; }
  public IList GetProductByCategory(string[] keywords) { //实现略; }
  public ProductInfo GetProduct(string productId) { //实现略; }
}

接下来咱们可以为代理对象建立专门的主次集BLLProxy,它不仅引入对IBLL程序集的看重,同时还将借助于BLL程序集。此时代理对象ProductDataProxy的定义如下:
using PetShop.IBLL;
using PetShop.BLL;
namespace PetShop.BLLProxy
{
  public class ProductDataProxy:IProduct
  {
     public IList GetProductByCategory(string category)
     {
        Product product = new Product();
        //其他实现略;
     }
     public IList GetProductByCategory(string[] keywords) { //实现略;
}
     public ProductInfo GetProduct(string productId) { //实现略; }
  }
}

这般的宏图正是突出的Proxy形式,其类社团如图5-2所示: 

图片 26

图5-2 Proxy模式

参考数据访问层的设计方法,我们可以为世界对象及代理对象建立抽象工厂,并在web.config中安排相关的配置节,然后采用反射技术创制具体的对象实例。如此一来,表示层就足以只是依靠PetShop.IBLL程序集以及工厂模块,如此就可以祛除表示层与现实领域对象之间的借助关系。表示层与修改后的事情逻辑层的涉嫌如图5-3所示:

图片 27

图5-3 修改后的作业逻辑层与表示层的关系

图5-4则是PetShop 4.0本来规划的层次关系图:
 

图片 28

图5-4 PetShop 4.0中表示层与业务逻辑层的关系

因此相比图5-3与图5-4,虽然后者不管是模块的个数,仍旧模块之间的关联,都相对更为简约,但是Web
Component组件与业务逻辑层之间却是强耦合的,这样的计划不便于应对事情扩展与要求变动。通过引入接口模块IBLL与工厂模块BLLFactory,解除了与现实模块BLL的借助关系。那种设计对于工作逻辑绝对相比复杂的系统而言,更符合面向对象的设计思想,有利于我们创建可抽取、可替换的“抽屉”式三层架构。

六 PetShop之表示层设计

表示层(Presentation
Layer)的筹划可以给系统客户最直接的体会和最十足的信心。正如人与人的交接相识一样,初次会合的痛感总是永难忘怀的。一件交付给客户采纳的出品,倘使在用户界面(User
Interface,UI)上缺乏吸引人的性状,界面不自己,操作不够珍爱,固然这件产品性能卓殊理想,架构设计合理,业务逻辑都满意了客户的需求,却照样难以讨得客户的欢心。俗语云:“佛要金装,人要衣装”,特别是对此Web应用程序而言,Web网页就好比人的时装,代表着漫天系统的地点与脸面,是揽客“顾客”的最大卖点。

“献丑不如藏拙”,作为艺术细胞缺乏的自我,并不打算在用户界面的美术设计上大做随笔,是以本书略过不提。本章所关心的表示层设计,依然以架构设计的角度,演讲在表示层设计中对格局的选择,ASP.NET控件的筹划与利用,同时还包括了对ASP.NET
2.0新特征的介绍。

6.1  MVC模式

表示层设计中最要害的形式是MVC(Model-View-Controller,即模型-视图-控制器)形式。MVC形式最早是由SmallTalk语言研究团提议的,被广泛应用在用户交互应用程序中。Controller依据用户请求(Response)修改Model的属性,此时伊夫(Eve)nt(事件)被触发,所有依赖于Model的View对象会自动更新,并按照Model对象暴发一个响应(Response)信息,再次回到给Controller。马丁福勒在《公司应用架构情势》一书中,显示了MVC格局应用的全经过,如图6-1所示: 

图片 29

图6-1 典型的MVC模式

比方将MVC格局拆解为几个独立的一部分:Model、View、Controller,大家得以经过GOF设计情势来促成和管制它们中间的关系。在系统架构设计中,业务逻辑层的圈子对象以及数据访问层的数据值对象都属于MVC形式的Model对象。假如要管制Model与View之间的关联,可以应用Observer形式,View作为观看者,一旦Model的属性值爆发变化,就会通报View基于Model的值举办翻新。而Controller作为控制用户请求/响应的靶子,则足以行使Mediator形式,专门负责请求/响应任务之间的调节。而对于View本身,在面向组件设计思想的根底上,我们经常将它计划为组件或者控件,那多少个零件或者控件依据自己特色的不同,共同整合一序列似于递归组合的靶子协会,因此大家得以采取Composite模式来计划View对象。

只是在.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控件的数据源绑定。

6.2  Page Controller情势的行使

综观PetShop的表示层设计,充足利用了ASP.NET的技能特色,通过Web页面与用户控件控制和表现视图,并利用codebehind技术将事情逻辑层的小圈子对象参预到表示层实现逻辑中,一个优异的Page
Controller情势呼之欲出。

Page Controller格局是MartinFowler在《集团应用架构模式》中最首要的表示层格局之一。在.NET平台下,Page
Controller情势的兑现万分简单,以Products.aspx页面为例。首先在aspx页面中,举行如下的装置:

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

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

图片 31[AspNetHostingPermission(SecurityAction.InheritanceDemand, 
图片 32Level=AspNetHostingPermissionLevel.Minimal), 
图片 33AspNetHostingPermission(SecurityAction.LinkDemand, 
图片 34Level=AspNetHostingPermissionLevel.Minimal)]
图片 35public interface IHttpHandler
图片 36图片 37图片 38{
图片 39      void ProcessRequest(HttpContext context);
图片 40图片 41      bool IsReusable 图片 42{ get; }
图片 43}
图片 44

Page类实现了ProcessRequest()方法,通过它可以设置Page对象的Request和Response属性,从而形成对用户请求/相应的操纵。然后Page类通过从Control类继承来的Load事件,将View与Model建立关联,如Products.aspx.cs所示:

图片 45public partial class Products : System.Web.UI.Page 
图片 46图片 47图片 48{
图片 49    protected void Page_Load(object sender, EventArgs e) 
图片 50图片 51    图片 52{
图片 53        //get page header and title
图片 54        Page.Title = WebUtility.GetCategoryName(Request.QueryString[“categoryId”]);
图片 55    }
图片 56}
图片 57

事件机制恰好是observer格局的兑现,当ASPX页面的Load事件被点燃后,系统通过WebUtility类(在第28章中有对WebUtility类的事无巨细介绍)的GetCategoryName()方法,得到Category值,并将其出示在页面的Title上。Page对象作为Controller,就好似一个调停者,用于协调View与Model之间的关系。

出于ASPX页面中还足以涵盖Web控件,这多少个控件对象同样是当做View对象,通过Page类型对象完成对它们的主宰。例如在CheckOut.aspx页面中,当用户发生CheckOut的呼吁后,作为System.Web.UI.WebControls.Winzard控件类型的wzdCheckOut,会在所有向导过程截止时,触发FinishButtonClick事件,并在该事件中调用领域对象Order的Insert()方法,如下所示:

图片 58public partial class CheckOut : System.Web.UI.Page图片 59
图片 60
图片 61图片 62    protected void wzdCheckOut_FinishButtonClick(object sender, WizardNavigationEventArgs e) 图片 63{
图片 64图片 65        if (Profile.ShoppingCart.CartItems.Count > 0) 图片 66{
图片 67图片 68            if (Profile.ShoppingCart.Count > 0) 图片 69{
图片 70
图片 71                // display ordered items
图片 72                CartListOrdered.Bind(Profile.ShoppingCart.CartItems);
图片 73
图片 74                // display total and credit card information
图片 75                ltlTotalComplete.Text = ltlTotal.Text;
图片 76                ltlCreditCardComplete.Text = ltlCreditCard.Text;
图片 77
图片 78                // create order
图片 79                OrderInfo order = new OrderInfo(int.MinValue, DateTime.Now, User.Identity.Name, GetCreditCardInfo(), billingForm.Address, shippingForm.Address, Profile.ShoppingCart.Total, Profile.ShoppingCart.GetOrderLineItems(), null);
图片 80
图片 81                // insert
图片 82                Order newOrder = new Order();
图片 83                newOrder.Insert(order);
图片 84
图片 85                // destroy cart
图片 86                Profile.ShoppingCart.Clear();
图片 87                Profile.Save();
图片 88            }
图片 89        }
图片 90图片 91        else 图片 92{
图片 93            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>”;
图片 94            wzdCheckOut.Visible = false;
图片 95        }
图片 96    }
图片 97
图片 98

在地点的一段代码中,卓殊优异地表明了Model与View之间的关联。它经过得到控件的属性值,作为参数值传递给数据值对象OrderInfo,从而采用页面上发生的订单信息创制订单对象,然后再调用领域对象Order的Inser()方法将OrderInfo对象插入到多少表中。其它,它还对天地对象ShoppingCart的数码项作出判断,假若其值等于0,就在页面中呈现UI提醒信息。此时,View的始末决定了Model的值,而Model值反过来又控制了View的显得内容。

6.3  ASP.NET控件

ASP.NET控件是View对象最重点的组成部分,它充足利用了面向对象的计划性思想,通过包装与继承构建一个个控件对象,使得用户在支付Web页面时,可以重用那么些控件,甚至自定义自己的控件。在第8章中,我早就介绍了.NET
Framework中控件的统筹思想,通过引入一种“复合形式”的Composite模式实现了控件树。在ASP.NET控件中,System.Web.UI.Control就是这棵控件树的根,它定义了有着ASP.NET控件共有的特性、方法和事件,并负责管理和控制控件的万事实施生命周期。

Control基类并没有包含UI的特定效率,尽管急需提供与UI相关的模式属性,就需要从System.Web.UI.WebControls.WebControl类派生。该类实际上也是Control类的子类,但它附加了诸如ForeColor、BackColor、Font等特性。

除却,还有一个重点的类是System.Web.UI.UserControl,即用户控件类,它同样是Control类的子类。我们可以自定义一些用户控件派生自UserControl,在Visual
Studio的Design环境下,大家得以经过拖动控件的不二法门将多系列型的控件组合成一个自定义用户控件,也能够在codebehind格局下,为自定义用户控件类添加新的习性和章程。

任何ASP.NET控件类的层次结构如图6-2所示: 

图片 99

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

ASP.NET控件的执行生命周期如表6-1所示:

阶段

控件需要执行的操作
要重写的方法或事件
初始化 初始化在传入 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 方法)

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

在此地,控件设计使用了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。

出于这五个控件都改成了其父类控件的显现模式,故而,我们得以通过重写父类的Render虚方法,完成控件的自定义。例如CustomGrid控件:

图片 100public class CustomGrid : Repeater…
图片 101//Static constants
图片 102    protected const string HTML1 = “<table cellpadding=0 
图片 103cellspacing=0><tr><td colspan=2>”;
图片 104    protected const string HTML2 = “</td></tr><tr><td class=paging align=left>”;
图片 105    protected const string HTML3 = “</td><td align=right class=paging>”;
图片 106    protected const string HTML4 = “</td></tr></table>”;
图片 107    private static readonly Regex RX = new Regex(@”^&page=\d+”, 
图片 108RegexOptions.Compiled);
图片 109    private const string LINK_PREV = “<a href=?page={0}>< Previous</a>”;
图片 110    private const string LINK_MORE = “<a href=?page={0}>More ></a>”;
图片 111private const string KEY_PAGE = “page”;
图片 112    private const string COMMA = “?”;
图片 113    private const string AMP = “&”;
图片 114
图片 115图片 116override protected void Render(HtmlTextWriter writer) 图片 117{
图片 118
图片 119        //Check there is some data attached
图片 120图片 121        if (ItemCount == 0) 图片 122{
图片 123            writer.Write(emptyText);
图片 124            return;
图片 125        }
图片 126        //Mask the query
图片 127        string query = Context.Request.Url.Query.Replace(COMMA, AMP);
图片 128        query = RX.Replace(query, string.Empty);
图片 129        // Write out the first part of the control, the table header
图片 130        writer.Write(HTML1);
图片 131        // Call the inherited method
图片 132        base.Render(writer);
图片 133        // Write out a table row closure
图片 134        writer.Write(HTML2);
图片 135        //Determin whether next and previous buttons are required
图片 136        //Previous button?
图片 137        if (currentPageIndex > 0)
图片 138            writer.Write(string.Format(LINK_PREV, (currentPageIndex – 1) + query));
图片 139        //Close the table data tag
图片 140        writer.Write(HTML3);
图片 141
图片 142        //Next button?
图片 143        if (currentPageIndex < PageCount)
图片 144            writer.Write(string.Format(LINK_MORE, (currentPageIndex + 1) + query));
图片 145
图片 146        //Close the table
图片 147        writer.Write(HTML4);
图片 148    }

是因为CustomGrid继承自Repeater控件,因而它同时还连续了Repeater的DataSource属性,这是一个虚属性,它默认的set访问器属性如下:

图片 149public virtual object DataSource
图片 150图片 151图片 152{
图片 153图片 154      get  图片 155{… }
图片 156      set
图片 157图片 158      图片 159{
图片 160            if (((value != null) && !(value is IListSource)) && !(value is IEnumerable))
图片 161图片 162            图片 163{
图片 164图片 165                  throw new ArgumentException(SR.GetString(“Invalid_DataSource_Type”, new object[] 图片 166{ this.ID }));
图片 167            }
图片 168            this.dataSource = value;
图片 169            this.OnDataPropertyChanged();
图片 170      }
图片 171}

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

图片 172private IList dataSource;
图片 173private int itemCount;
图片 174
图片 175图片 176override public object DataSource 图片 177{
图片 178图片 179    set 图片 180{
图片 181    //This try catch block is to avoid issues with the VS.NET designer
图片 182        //The designer will try and bind a datasource which does not derive from ILIST
图片 183图片 184        try 图片 185{
图片 186            dataSource = (IList)value;
图片 187            ItemCount = dataSource.Count;
图片 188        }
图片 189图片 190        catch 图片 191{
图片 192            dataSource = null;
图片 193            ItemCount = 0;
图片 194        }
图片 195    }
图片 196}

当设置的value对象值不为IList类型时,set访问器就将捕获万分,然后将dataSource字段设置为null。

由于我们改写了DataSource属性,因此改写Repeater类的OnDataBinding()方法也就势在必行。其它,CustomGrid还提供了分页的功力,我们也急需贯彻分页的相干操作。与DataSource属性不同,Repeater类的OnDataBinding()方法其实是连续和改写了Control基类的OnDataBinding()虚方法,而我辈又在此基础上改写了Repeater类的OnDataBinding()方法:

图片 197图片 198override protected void OnDataBinding(EventArgs e) 图片 199{
图片 200
图片 201    //Work out which items we want to render to the page
图片 202    int start = CurrentPageIndex * pageSize;
图片 203    int size = Math.Min(pageSize, ItemCount – start);
图片 204
图片 205    IList page = new ArrayList();
图片 206    //Add the relevant items from the datasource
图片 207    for (int i = 0; i < size; i++)
图片 208        page.Add(dataSource[start + i]);
图片 209
图片 210    //set the base objects datasource
图片 211    base.DataSource = page;
图片 212    base.OnDataBinding(e);
图片 213}

此外,CustomGrid控件类还增添了广大属于自己的属性和方法,例如PageSize、PageCount属性以及SetPage()方法等。正是因为ASP.NET控件引入了Composite形式与Template
Method格局,当我们在自定义控件时,就足以经过连续与改写的主意来成功控件的筹划。自定义ASP.NET控件一方面可以依据系统的需求实现特定的法力,也可以最大限度地促成目的的任用,既可以削减编码量,同时也有利于未来对程序的扩展与修改。
在PetShop
4.0中,除了自定义了上述WebControl控件的子控件外,最要害的依然拔取了用户控件。在Controls文件夹下,一共定义了11个用户控件,内容包含客户地址音信、信用卡音信、购物车信息、期望列表(Wish
List)音信以及导航信息、搜索结果音讯等。它们相当于是局部整合控件,除了含有了子控件的章程和性质外,也定义了有些必要的UI实现逻辑。以ShoppingCartControl用户控件为例,它会在该控件被展现(Render)在此之前,做一些多少准备干活,获取购物车多少,并作为数据源绑定到其下的Repeater控件:

图片 214public partial class ShoppingCartControl : System.Web.UI.UserControl图片 215
图片 216       
图片 217图片 218    protected void Page_PreRender(object sender, EventArgs e) 图片 219{
图片 220图片 221        if (!IsPostBack) 图片 222{
图片 223            BindCart();                
图片 224        }
图片 225    }
图片 226图片 227    private void BindCart() 图片 228{
图片 229
图片 230        ICollection<CartItemInfo> cart = Profile.ShoppingCart.CartItems;
图片 231图片 232        if (cart.Count > 0) 图片 233{
图片 234            repShoppingCart.DataSource = cart;
图片 235            repShoppingCart.DataBind();
图片 236            PrintTotal();
图片 237            plhTotal.Visible = true;
图片 238        }
图片 239图片 240        else 图片 241{
图片 242            repShoppingCart.Visible = false;
图片 243            plhTotal.Visible = false;
图片 244            lblMsg.Text = “Your cart is empty.”;
图片 245        }
图片 246    }

在ShoppingCart页面下,我们可以进入该用户控件,如下所示:

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

出于ShoppingCartControl用户控件已经落实了用来展现购物车数量的逻辑,那么在ShoppingCart.aspx.cs中,就足以不要承担这么些逻辑,在丰硕完成目的重用的进程中,同时又达到了任务分开的目标。用户控件的设计者与页面设计者可以互不烦扰,分头完成自己的计划。特别是对此页面设计者而言,他可以是纯净的UI设计人员角色,仅需要关爱用户界面是否雅观与自己,对于表示层中对天地对象的调用与操作就可以不必理会,整个页面的代码也显得结构清晰、逻辑清楚,无疑也“干净”了许多。

6.4  ASP.NET 2.0新特性

是因为PetShop 4.0是基于.NET Framework
2.0阳台支付的电子商务系统,因此它在表示层也引入了过多ASP.NET
2.0的新特色,例如MemberShip、Profile、Master
Page、登录控件等风味。接下来,我将构成PetShop
4.0的宏图分别介绍它们的落实。

6.4.1  Profile特性

Profile提供的效率是本着用户的个性化服务。在ASP.NET
1.x本蛇时,大家得以使用Session、库克(Cook)ie等方法来存储用户的图景消息。可是Session对象是兼备生存期的,一旦生存期停止,该对象保留的值就会失灵。Cookie将用户新闻保存在客户端,它抱有一定的安全隐患,一些重点的音信不可以储存在库克(Cook)ie中。一旦客户端禁止行使Cookie,则该意义就将错过利用的职能。

Profile的面世缓解了上述的沉郁,它可以将用户的个人化消息保存在指定的数据库中。ASP.NET
2.0的Profile效率默认帮助Access数据库和SQL
Server数据库,假诺急需扶助任何数据库,可以编写相关的ProfileProvider类。Profile对象是强类型的,我们可以为用户音讯建立属性,以PetShop
4.0为例,它确立了ShoppingCart、WishList和AccountInfo属性。

出于Profile效能需要拜访数据库,由此在数据访问层(DAL)定义了和Product等数据表相似的模块结构。首先定义了一个IProfileDAL接口模块,包含了接口IPetShopProfileProvider:

图片 248public interface IPetShopProfileProvider 
图片 249图片 250图片 251
图片 252 AddressInfo GetAccountInfo(string userName, string appName);   
图片 253 void SetAccountInfo(int uniqueID, AddressInfo addressInfo);
图片 254 IList<CartItemInfo> GetCartItems(string userName, string appName, 
图片 255bool isShoppingCart);
图片 256 void SetCartItems(int uniqueID, ICollection<CartItemInfo> cartItems, 
图片 257bool isShoppingCart);
图片 258 void UpdateActivityDates(string userName, bool activityOnly, string appName);
图片 259 int GetUniqueID(string userName, bool isAuthenticated, bool ignoreAuthenticationType,
图片 260 string appName);
图片 261 int CreateProfileForUser(string userName, bool isAuthenticated, string appName);
图片 262 IList<string> GetInactiveProfiles(int authenticationOption, 
图片 263DateTime userInactiveSinceDate, string appName);
图片 264 bool DeleteProfile(string userName, string appName);   
图片 265 IList<CustomProfileInfo> GetProfileInfo(int authenticationOption, 
图片 266string usernameToMatch, DateTime userInactiveSinceDate, string appName, 
图片 267out int totalRecords);
图片 268}

因为PetShop 4.0本子分别援助SQL
Server和Oracle数据库,因此它分别定义了六个不同的PetShopProfileProvider类,实现IPetShopProfileProvider接口,并放在两个不等的模块SQLProfileDAL和OracleProfileDAL中。具体的实现请参见PetShop
4.0的源代码。
相同的,PetShop
4.0为Profile引入了工厂情势,定义了模块ProfileDALFActory,工厂类DataAccess的概念如下:

图片 269图片 270public sealed class DataAccess 图片 271{
图片 272
图片 273    private static readonly string profilePath = ConfigurationManager.AppSettings[“ProfileDAL”];
图片 274图片 275    public static PetShop.IProfileDAL.IPetShopProfileProvider CreatePetShopProfileProvider() 图片 276{
图片 277 string className = profilePath + “.PetShopProfileProvider”;
图片 278 return (PetShop.IProfileDAL.IPetShopProfileProvider)Assembly.Load(profilePath).CreateInstance(className);
图片 279    }
图片 280}

在事情逻辑层(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.Profile.PetShopProfileProvider类后,才可以在web.config配置文件中配备如下的配置节:

图片 281<profile automaticSaveEnabled=”false” defaultProvider=”ShoppingCartProvider”>
图片 282 <providers>
图片 283  <add name=”ShoppingCartProvider” connectionStringName=”SQLProfileConnString” type=”PetShop.Profile.PetShopProfileProvider” applicationName=”.NET Pet Shop 4.0″/>
图片 284  <add name=”WishListProvider” connectionStringName=”SQLProfileConnString” type=”PetShop.Profile.PetShopProfileProvider” applicationName=”.NET Pet Shop 4.0″/>
图片 285  <add name=”AccountInfoProvider” connectionStringName=”SQLProfileConnString” type=”PetShop.Profile.PetShopProfileProvider” applicationName=”.NET Pet Shop 4.0″/>
图片 286 </providers>
图片 287 <properties>
图片 288  <add name=”ShoppingCart” type=”PetShop.BLL.Cart” allowAnonymous=”true” provider=”ShoppingCartProvider”/>
图片 289  <add name=”WishList” type=”PetShop.BLL.Cart” allowAnonymous=”true” provider=”WishListProvider”/>
图片 290  <add name=”AccountInfo” type=”PetShop.Model.AddressInfo” allowAnonymous=”false” provider=”AccountInfoProvider”/>
图片 291 </properties>
图片 292</profile>

在部署文件中,针对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”/>

而键值为ProfileDAL的值,正是Profile的工厂类PetShop.ProfileDALFactory.DataAccess在运用反射技术创立IPetShopProfileProvider类型对象时得到的。

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

图片 293图片 294public partial class ShoppingCart : System.Web.UI.Page 图片 295{
图片 296
图片 297图片 298    protected void Page_PreInit(object sender, EventArgs e) 图片 299{
图片 300图片 301        if (!IsPostBack) 图片 302{
图片 303            string itemId = Request.QueryString[“addItem”];
图片 304图片 305            if (!string.IsNullOrEmpty(itemId)) 图片 306{
图片 307                Profile.ShoppingCart.Add(itemId);
图片 308                Profile.Save();
图片 309                // Redirect to prevent duplictations in the cart if user hits “Refresh”
图片 310                Response.Redirect(“~/ShoppingCart.aspx”, true);
图片 311            }
图片 312        }
图片 313    }
图片 314}

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

6.4.2  Membership特性

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抽象类。

OracleMembershipProvider类的实现所有极高的参考价值,如果我们需要定义自己的MembershipProvider类,可以参见该类的贯彻。
骨子里OracleMemberShip类的贯彻并不复杂,在此类中,重假使本着用户及用户安全而实现相关的所作所为。由于在父类MembershipProvider中,已经定义了连带操作的虚方法,由此大家需要作的是重写这一个虚方法。由于与Membership有关的音信都是储存在数据库中,由此OracleMembershipProvider与SqlMembershipProvider类的重点区别如故在于对数据库的造访。对于SQL
Server而言,大家运用aspnet_regsql工具为Membership建立了相关的数据表以及存储过程。也许是因为文化产权的缘故,Microsoft并从未为Oracle数据库提供类似的工具,因此需要我们协调去创立membership的数据表。其余,由于尚未创立Oracle数据库的贮存过程,由此OracleMembershipProvider类中的实现是直接调用SQL语句。以CreateUser()方法为例,剔除那多少个乱七八糟的参数判断与安全性判断,SqlMembershipProvider类的贯彻如下:

图片 315public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
图片 316图片 317图片 318{
图片 319      MembershipUser user1;
图片 320      //前面的代码略;
图片 321      try
图片 322图片 323      图片 324{
图片 325            SqlConnectionHolder holder1 = null;
图片 326            try
图片 327图片 328            图片 329{
图片 330                  holder1 = SqlConnectionHelper.GetConnection(this._sqlConnectionString, true);
图片 331                  this.CheckSchemaVersion(holder1.Connection);
图片 332                  DateTime time1 = this.RoundToSeconds(DateTime.UtcNow);
图片 333                  SqlCommand command1 = new SqlCommand(“dbo.aspnet_Membership_CreateUser”, holder1.Connection);
图片 334                  command1.CommandTimeout = this.CommandTimeout;
图片 335                  command1.CommandType = CommandType.StoredProcedure;
图片 336                  command1.Parameters.Add(this.CreateInputParam(“@ApplicationName”, SqlDbType.NVarChar, this.ApplicationName));
图片 337                  command1.Parameters.Add(this.CreateInputParam(“@UserName”, SqlDbType.NVarChar, username));
图片 338                  command1.Parameters.Add(this.CreateInputParam(“@Password”, SqlDbType.NVarChar, text2));
图片 339                  command1.Parameters.Add(this.CreateInputParam(“@PasswordSalt”, SqlDbType.NVarChar, text1));
图片 340                  command1.Parameters.Add(this.CreateInputParam(“@Email”, SqlDbType.NVarChar, email));
图片 341                  command1.Parameters.Add(this.CreateInputParam(“@PasswordQuestion”, SqlDbType.NVarChar, passwordQuestion));
图片 342                  command1.Parameters.Add(this.CreateInputParam(“@PasswordAnswer”, SqlDbType.NVarChar, text3));
图片 343                  command1.Parameters.Add(this.CreateInputParam(“@IsApproved”, SqlDbType.Bit, isApproved));
图片 344                  command1.Parameters.Add(this.CreateInputParam(“@UniqueEmail”, SqlDbType.Int, this.RequiresUniqueEmail ? 1 : 0));
图片 345                  command1.Parameters.Add(this.CreateInputParam(“@PasswordFormat”, SqlDbType.Int, (int) this.PasswordFormat));
图片 346                  command1.Parameters.Add(this.CreateInputParam(“@CurrentTimeUtc”, SqlDbType.DateTime, time1));
图片 347                  SqlParameter parameter1 = this.CreateInputParam(“@UserId”, SqlDbType.UniqueIdentifier, providerUserKey);
图片 348                  parameter1.Direction = ParameterDirection.InputOutput;
图片 349                  command1.Parameters.Add(parameter1);
图片 350                  parameter1 = new SqlParameter(“@ReturnValue”, SqlDbType.Int);
图片 351                  parameter1.Direction = ParameterDirection.ReturnValue;
图片 352                  command1.Parameters.Add(parameter1);
图片 353                  command1.ExecuteNonQuery();
图片 354                  int num3 = (parameter1.Value != null) ? ((int) parameter1.Value) : -1;
图片 355                  if ((num3 < 0) || (num3 > 11))
图片 356图片 357                  图片 358{
图片 359                        num3 = 11;
图片 360                  }
图片 361                  status = (MembershipCreateStatus) num3;
图片 362                  if (num3 != 0)
图片 363图片 364                  图片 365{
图片 366                        return null;
图片 367                  }
图片 368                  providerUserKey = new Guid(command1.Parameters[“@UserId”].Value.ToString());
图片 369                  time1 = time1.ToLocalTime();
图片 370                  user1 = new MembershipUser(this.Name, username, providerUserKey, email, passwordQuestion, null, isApproved, false, time1, time1, time1, time1, new DateTime(0x6da, 1, 1));
图片 371            }
图片 372            finally
图片 373图片 374            图片 375{
图片 376                  if (holder1 != null)
图片 377图片 378                  图片 379{
图片 380                        holder1.Close();
图片 381                        holder1 = null;
图片 382                  }
图片 383            }
图片 384      }
图片 385      catch
图片 386图片 387      图片 388{
图片 389            throw;
图片 390      }
图片 391      return user1;
图片 392}

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

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

图片 393图片 394public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object userId, out MembershipCreateStatus status) 图片 395{
图片 396    //后边的代码略;
图片 397 //Create connection
图片 398 OracleConnection connection = new OracleConnection(OracleHelper.ConnectionStringMembership);
图片 399 connection.Open();
图片 400 OracleTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);
图片 401图片 402 try 图片 403{
图片 404  DateTime dt = DateTime.Now;
图片 405  bool isUserNew = true;
图片 406
图片 407  // Step 1: Check if the user exists in the Users table: create if not    
图片 408  int uid = GetUserID(transaction, applicationId, username, true, false, dt, out isUserNew);
图片 409图片 410  if(uid == 0) 图片 411{ // User not created successfully!
图片 412   status = MembershipCreateStatus.ProviderError;
图片 413   return null;
图片 414  }
图片 415  // Step 2: Check if the user exists in the Membership table: Error if yes.
图片 416图片 417  if(IsUserInMembership(transaction, uid)) 图片 418{
图片 419   status = MembershipCreateStatus.DuplicateUserName;
图片 420   return null;
图片 421  }
图片 422  // Step 3: Check if Email is duplicate
图片 423图片 424  if(IsEmailInMembership(transaction, email, applicationId)) 图片 425{
图片 426   status = MembershipCreateStatus.DuplicateEmail;
图片 427   return null;
图片 428  }
图片 429  // Step 4: Create user in Membership table     
图片 430  int pFormat = (int)passwordFormat;
图片 431图片 432  if(!InsertUser(transaction, uid, email, pass, pFormat, salt, “”, “”, isApproved, dt)) 图片 433{
图片 434   status = MembershipCreateStatus.ProviderError;
图片 435   return null;
图片 436  }
图片 437  // Step 5: Update activity date if user is not new
图片 438图片 439  if(!isUserNew) 图片 440{
图片 441图片 442   if(!UpdateLastActivityDate(transaction, uid, dt)) 图片 443{
图片 444    status = MembershipCreateStatus.ProviderError;
图片 445    return null;
图片 446   }
图片 447  }
图片 448  status = MembershipCreateStatus.Success;
图片 449  return new MembershipUser(this.Name, username, uid, email, passwordQuestion, null, isApproved, false, dt, dt, dt, dt, DateTime.MinValue);
图片 450 }
图片 451图片 452 catch(Exception) 图片 453{
图片 454  if(status == MembershipCreateStatus.Success)
图片 455   status = MembershipCreateStatus.ProviderError;
图片 456  throw;
图片 457 }
图片 458图片 459 finally 图片 460{
图片 461  if(status == MembershipCreateStatus.Success)
图片 462   transaction.Commit();
图片 463  else
图片 464   transaction.Rollback();
图片 465  connection.Close();
图片 466  connection.Dispose();
图片 467 }
图片 468}

代码中,InsertUser()方法就是肩负用户的创始,而在头里则需要判定成立的用户是否已经存在。InsertUser()方法的概念如下:

图片 469图片 470private static bool InsertUser(OracleTransaction transaction, int userId, string email, string password, int passFormat, string passSalt, string passQuestion, string passAnswer, bool isApproved, DateTime dt) 图片 471{
图片 472
图片 473 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)”;
图片 474图片 475 OracleParameter[] insertParms = 图片 476{ 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) };
图片 477 insertParms[0].Value = userId;
图片 478 insertParms[1].Value = email;
图片 479 insertParms[2].Value = password;
图片 480 insertParms[3].Value = passFormat;
图片 481 insertParms[4].Value = passSalt;
图片 482 insertParms[5].Value = passQuestion;
图片 483 insertParms[6].Value = passAnswer;
图片 484 insertParms[7].Value = OracleHelper.OraBit(isApproved);
图片 485 insertParms[8].Value = dt;
图片 486 insertParms[9].Value = dt;
图片 487 insertParms[10].Value = dt;
图片 488
图片 489 if(OracleHelper.ExecuteNonQuery(transaction, CommandType.Text, insert, insertParms) != 1)
图片 490  return false;
图片 491 else
图片 492  return true;
图片 493}

在为Membership建立了Provider类后,还索要在配备文件中安排相关的配置节,例如SqlMembershipProvider的安排:

图片 494<membership defaultProvider=”SQLMembershipProvider”>
图片 495 <providers>
图片 496  <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”/>
图片 497 </providers>
图片 498</membership>

对于OracleMembershipProvider而言,配置大致相像:

图片 499<membership defaultProvider=”OracleMembershipProvider”>
图片 500 <providers>
图片 501  <clear/>
图片 502  <add name=”OracleMembershipProvider” 
图片 503   type=”PetShop.Membership.OracleMembershipProvider” 
图片 504   connectionStringName=”OraMembershipConnString” 
图片 505   enablePasswordRetrieval=”false” 
图片 506   enablePasswordReset=”false” 
图片 507   requiresUniqueEmail=”false” 
图片 508   requiresQuestionAndAnswer=”false” 
图片 509   minRequiredPasswordLength=”7″ 
图片 510   minRequiredNonalphanumericCharacters=”1″ 
图片 511   applicationName=”.NET Pet Shop 4.0″ 
图片 512   hashAlgorithmType=”SHA1″ 
图片 513   passwordFormat=”Hashed”/>
图片 514 </providers>
图片 515</membership>

至于部署节属性的含义,可以参见MSDN等有关文档。

6.4.3  ASP.NET登录控件

此间所谓的登录控件并不是指一个控件,而是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等类型的控件,用法如下所示:

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

又比如说NewUser.aspx中对CreateUserWizard控件的行使:

图片 518<asp:CreateUserWizard ID=”CreateUserWizard” runat=”server” CreateUserButtonText=”Sign Up” InvalidPasswordErrorMessage=”Please enter a more secure password.” PasswordRegularExpressionErrorMessage=”Please enter a more secure password.” 
图片 519RequireEmail=”False” SkinID=”NewUser”>
图片 520<WizardSteps>
图片 521            <asp:CreateUserWizardStep ID=”CreateUserWizardStep1″ runat=”server”>
图片 522   </asp:CreateUserWizardStp>
图片 523 </WizardSteps>
图片 524</asp:CreateUserWizard>

使用了登录控件后,大家毋需编写与用户登录相关的代码,登录控件已经为我们做到了连带的效应,这就大大地简化了这些系统的宏图与实现。

6.4.4  Master Page特性

Master Page相当于是一切Web站点的会见模板,建立的Master
Page文件扩充名为.master。它可以分包静态文本、html元素和服务器控件。Master
Page由新鲜的@Master指令识别,如:

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

动用Master
Page可以为网站建立一个统一的体制,且可以采纳它有利于地开创一组控件和代码,然后将其使用于一组页。对于那一个体制与效用相似的页而言,利用Master
Page就可以集中处理为Master
Page,一旦举行改动,就足以在一个职务上进展翻新。

在PetShop 4.0中,建立了名为MasterPage.master的Master
Page,它含有了header、LoginView控件、导航菜单以及用于展现内容的html元素,如图6-3所示: 

图片 526

图6-3 PetShop 4.0的Master Page

@Master指令的概念如下:

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

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

图片 528public partial class MasterPage : System.Web.UI.MasterPage {
图片 529
图片 530    private const string HEADER_PREFIX = “.NET Pet Shop :: {0}”;
图片 531
图片 532    protected void Page_PreRender(object sender, EventArgs e) { 
图片 533        ltlHeader.Text = Page.Header.Title;
图片 534        Page.Header.Title = string.Format(HEADER_PREFIX, Page.Header.Title);          
图片 535    }
图片 536    protected void btnSearch_Click(object sender, EventArgs e) {
图片 537        WebUtility.SearchRedirect(txtSearch.Text);    
图片 538    }
图片 539}

留意Master
Page页面不再继续自System.Web.UI.Page,而是继续System.Web.UI.MasterPage类。与Page类继承TemplateControl类不同,它是UserControl类的子类。由此,可以采用在Master
Page上的行之有效指令与UserControl的可用指令相同,例如Auto伊芙(Eve)ntWireup、ClassName、CodeFile、EnableViewState、WarningLevel等。

每一个与Master
Page相关的内容页必须在@Page指令的MasterPageFile属性中援引相关的Master
Page。例如PetShop 4.0中的CheckOut内容页,其@Page指令的定义如下:

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

Master Page能够开展嵌套,例如我们树立了父Master
Page页面Parent.master,那么在子Master
Page中,可以动用master属性指定其父MasterPage:
<%@ Master Language=”C#” master=”Parent.master”%>

而内容页则可以依照意况指向Parent.master或者Child.master页面。

尽管说Master
Page大部分气象下是以宣称格局成立,但我们也足以建立一个类继承System.Web.UI.MasterPage,从而做到对Master
Page的编程式创设。但在采纳这种艺术的同时,应该而且创制.master文件。另外对Master
Page的调用也足以应用编程的方法成功,例如动态地添加Master
Page,我们重写内容页的Page_PreInit()方法,如下所示:

图片 541void Page_PreInit(Object sender, EventArgs e)
图片 542图片 543图片 544{
图片 545    this.MasterPageFile = “~/NewMaster.master”;
图片 546}

从而重写Page_PreInit()方法,是因为Master
Page会在情节页开头化阶段展开统一,也即是说是在PreInit阶段完成Master
Page的分红。
ASP.NET
2.0引入的新特色,并不仅仅限于上述介绍的始末。例如Theme、Wizard控件等新特点在PetShop
4.0中也赢得了大气的利用。即使ASP.NET
2.0应声地吐故纳新,对表示层的计划性有所改革,但是作为ASP.NET
2.0的其中一部分,它们仅仅是对现有框架缺失的弥补与改进,属于“锦上添花”的规模,对于整个表示层设计技术而言,起到的有助于效用却非凡有限。

以至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应用环境。

本身明天还不能预知AJAX技术在未来的走向,然则单单从表示层设计的角度而言,AJAX技术一样带了一场全新的革命。我们还可以够期待将来的PetShop
5.0,可以在表示层设计上带来更多的惊喜。

Leave a Comment.