实现分布式的Membership和上下文传递通过上一篇了解了模块内基本的层次划分之后,接下来我们来聊聊PetShop中一些基本基础功能的实现,以及一些设计、架构上的应用如何同WCF进行集成。本篇讨论两个问题:实现分布式的Membership和客户端到服务端上下文(Context)的传递。一、如何实现用户验证对登录用户的验证是大部分应用所必需的,对于ASP.NET来说,用户验证及帐号管理实现在成员资格(Membership)模块中。同ASP.NET的其他模块一样,微软在设计Membership的时候,为了实现更好地可扩展性,采用了策略(Strategy)设计模式:将模块相关的功能定义在被称为Provider的抽象类型中,并通过继承它提供具体的Provider。如果这些原生的Provider不能满足你的需求,你也可以通过继承该抽象的Provider,创建自定义的Provider。通过ASP.NET提供的配置,你可以很轻易地把自定义的Provider应用到你的应用之中。在一般情况下,最终的编程人员并不通过Provider调用相关的功能,而是通过一个外观(Facade)类实现对相关功能的调用。ASP.NET成员资格模块的设计基本上可以通过下面的类图1反映出来:最终的编程人员通过外观类型(FaçadeClass)Membership调用成员资格相关的功能,比如用户认证、用户注册、修改密码等;Membership通过抽象类MembershipProvider提供所有的功能,至于最终的实现,则定义在一个个具体的MembershipProvider中。基于成员资格信息不同的存储方式,ASP.NET提供了两个原生的MembershipProvider:SqlMembershipProvider和ActiveDirectoryMembershipProvider,前者基于SQLServer数据库,后者基于AD。如果这两个MembershipProvider均不能满足需求,我们还可以自定义MembershipProvider。clip_image002图1ASP.NETMembership设计原理我们的案例并不会部署于AD之中,所以不能使用ActiveDirectoryMembershipProvider;直接通过Web服务器进行数据库的存取又不符合上述物理部署的要求(通过应用服务器进行数据库访问),所以SqlMembershipProvider也不能为我们所用。为此需要自定义MembershipProvider,通过WCF服务调用的形式提供成员资格所有功能的实现。我们将该自定义MembershipProvider称为RemoteMembershipProvider。图2揭示了RemoteMembershipProvider实现的原理:RemoteMembershipProvider通过调用WCF服务MembershipService提供对成员资格所有功能的实现;MembershipService则通过调用Membership实现服务;最终的实现还是落在了SqlMembershipProvider这个原生的MembershipProvider上。clip_image004图2RemoteMembershipProvider实现原理1、服务契约和服务实现首先来看看MembershipService实现的服务契约的定义。由于MembershipService最终是为RemoteMembershipProvider这个自定义MembershipProvider服务的,所以服务操作的定义是基于MembershipProvider的API定义。MembershipProvider包含两种类型的成员:属性和方法,简单起见,我们可以为MembershipProvider每一个抽象方法定义一个匹配的服务操作;而对于所有属性,完全采用服务端(应用服务器)的MembershipProvider相关属性。在RemoteMembershipProvider初始化的时候通过调用MembershipService获取所有服务端MembershipProvider的配置信息。为此,我们为MembershipProvider的所有属性定义了一个数据契约:MembershipConfigData。在PetShop中,MembershipConfigData和服务契约一起定义在Infrastructures.Service.Interface项目中。1:usingSystem.Runtime.Serialization;2:usingSystem.Web.Security;3:namespaceArtech.PetShop.Infrastructures.Service.Interface4:{5:[DataContract(Namespace=)]6:publicclassMembershipConfigData7:{8:[DataMember]9:publicstringApplicationName10:{get;set;}11:12:[DataMember]13:publicboolEnablePasswordReset14:{get;set;}15:16:[DataMember]17:publicboolEnablePasswordRetrieval18:{get;set;}19:20:[DataMember]21:publicintMaxInvalidPasswordAttempts22:{get;set;}23:24:[DataMember]25:publicintMinRequiredNonAlphanumericCharacters26:{get;set;}27:28:[DataMember]29:publicintMinRequiredPasswordLength30:{get;set;}31:32:[DataMember]33:publicintPasswordAttemptWindow34:{get;set;}35:36:[DataMember]37:publicMembershipPasswordFormatPasswordFormat38:{get;set;}39:40:[DataMember]41:publicstringPasswordStrengthRegularExpression42:{get;set;}43:44:[DataMember]45:publicboolRequiresQuestionAndAnswer46:{get;set;}47:48:[DataMember]49:publicboolRequiresUniqueEmail50:{get;set;}51:}52:}在服务契约中,定义了一个额外的方法GetMembershipConfigData获取服务端MembershipProvider的所有配置信息,而对于服务操作的定义,则与MembershipProvider同名抽象方法相对应。1:usingSystem.ServiceModel;2:usingSystem.Web.Security;3:namespaceArtech.PetShop.Infrastructures.Service.Interface4:{5:[ServiceContract(Namespace=)]6:publicinterfaceIMembershipService7:{8:[OperationContract]9:boolChangePassword(stringusername,stringoldPassword,stringnewPassword);10:[OperationContract]11:boolChangePasswordQuestionAndAnswer(stringusername,stringpassword,stringnewPasswordQuestion,stringnewPasswordAnswer);12:[OperationContract]13:MembershipUserCreateUser(stringusername,stringpassword,stringemail,stringpasswordQuestion,stringpasswordAnswer,boolisApproved,objectproviderUserKey,outMembershipCreateStatusstatus);14:[OperationContract]15:boolDeleteUser(stringusername,booldeleteAllRelatedData);16:[OperationContract]17:MembershipUserCollectionFindUsersByEmail(stringemailToMatch,intpageIndex,intpageSize,outinttotalRecords);18:[OperationContract]19:MembershipUserCollectionFindUsersByName(stringusernameToMatch,intpageIndex,intpageSize,outinttotalRecords);20:[OperationContract]21:MembershipUserCollectionGetAllUsers(intpageIndex,intpageSize,outinttotalRecords);22:[OperationContract]23:intGetNumberOfUsersOnline();24:[OperationContract]25:stringGetPassword(stringusername,stringanswer);26:[OperationContract(Name=GetUserByName)]27:MembershipUserGetUser(stringusername,booluserIsOnline);28:[OperationContract(Name=GetUserByID)]29:MembershipUserGetUser(objectproviderUserKey,booluserIsOnline);30:[OperationContract]31:stringGetUserNameByEmail(stringemail);32:[OperationContract]33:stringResetPassword(stringusername,stringanswer);34:[OperationContract]35:boolUnlockUser(stringuserName);36:[OperationContract]37:voidUpdateUser(MembershipUseruser);38:[OperationContract]39:boolValidateUser(stringusername,stringpassword);40:[OperationContract]41:MembershipConfigDataGetMembershipConfigData();42:}43:}服务的实现,则异常简单,我们须要做的仅仅是通过Membership.Provider获得当前的MembershipProvider,调用同名的属性或方法即可。MembershipService定义在Infrastructures.Service中,定义如下:1:usingSystem.Web.Security;2:usingArtech.PetShop.Infrastructures.Servic