- 环境条件:
- WinXP SP2.Cn
- Visual Studio Team System 2008 Beta2.En
- VPC 2007.En
- Win2K3 Server SP2
- 准备工作:
- 在WinXP SP2的机器上安装VS2008;
- 在WinXP SP2的机器上安装VPC 2007;
- 在VPC 2007中准备两个Win2K3 Server的虚拟环境,并为其安装.NET 3.5 Framework Beta2 RunTime:
虚拟机环境A
虚拟机环境B
设备名
Win2K3-I
Win2K3-II
机器名
Server-01
Server-02
内存分配
256M
256M
IP分配
192.168.4.10
192.168.4.11
- 基于WCF的面向服务结构Demo概述:
VS2008已经提供了两类关于WCF的项目模板:Web分类下的WCF Service Application、WCF分类下的WCF Service Library及其工作流相关的WCF Service模板。WCF Service Appliaction项目模板:该模板将IIS作为WCF Service的宿主,对外提供服务,默认情况下将使用HTTP协议的wsHttpBinding,即WebServices。但在这个项目模板中,不光包含了*.svc类型的服务声明,
WCF Service Library项目模板:该模板将会默认建立Contract的接口以及Service的实现类。在该类型项目中添加一个WCF Service类型项,会同时添加IService接口和Service的实现类。在IService这个接口文件中会包含两个类:ServiceContract契约接口和DataContract数据契约类;而Service这个类是对IService接口文件中的ServiceContract接口的实现。按照WCF设计的思路可以理解为,在IService这个接口文件中定义的都是服务契约Contract,是需要提供给Service调用者的依据,即服务接口和数据实体,统称契约Contract。
按照WCF Service Libray模板设计,把服务接口和数据实体都定义在一起,并且在把服务接口的具体实现也包含在了一个程序集中。明显,这不是一种满足低耦合的设计,因此,在这个例子中会把这几部分单独分开建立项目。在这个WCF例子中,会把整个架构划分为6个项目,没有明确说明的都是基于.NET 3.5的类库Class Librayr型项目。
-
- Fetion.Web.Framework.DataContract
简要说明:数据契约DataContract,它的定义有些类似于传统项目中的业务实体对象BusinessEntity。
项目引用:System.Runtime.Serialization - Fetion.Web.Framework.ServiceContract
简要说明:服务契约ServiceContract,服务契约都是接口Interface,用于定义服务的操作接口。
项目引用:System.ServiceModel
Fetion.Web.Framework.DataContract - Fetion.Web.Framework.BusinessService
简要说明:服务实现Service,对服务契约ServiceContract接口的具体实现,包含了Service的实际业务操作。
项目引用:Fetion.Web.Framework.DataContract
Fetion.Web.Framework.ServiceContract - Fetion.Web.Framework.ServiceContainer
简要说明:服务容器,即WCF的宿主。以WCF Service Appliaction项目模板建立项目,在这基础上做修改使成为满足需要的项目。
项目类型:Web分类下的WCF Service Appliaction
项目引用:Fetion.Web.Framework.BusinessService - Fetion.Web.Framework.ServiceWrapper
简要说明:客户端服务代理,该层完成对服务器端Service的封装,包含权限安全性、数据加密压缩、缓存等方面的内容。
项目引用:System.ServiceModel
Fetion.Web.Framework.DataContract
Fetion.Web.Framework.ServiceContract - Fetion.Web.Framework.UIConsole
简要说明:UI控制台程序,用来代替最终的UI层对WCF Service进行测试.
项目类型:Windows分类下的Console Appliaction
项目引用:System.ServiceModel
Fetion.Web.Framework.DataContract
Fetion.Web.Framework.ServiceContract
Fetion.Web.Framework.ServiceWrapper整个项目结构如下图所示:
- Fetion.Web.Framework.DataContract
-
- Fetion.Web.Framework.DataContract
Fetion.Web.Framework.DataContract中包含了需要和前台传递的数据实体对象,在这个例子中做了一个叫做HostInfo的类作为数据载体,HostInfo只有两个属性,用于记录主机名和主机IP,便于在后面做负载均衡试验时确定是从哪台服务器上执行的。其中,[DataContract]标记HostInfo类为WCF的数据契约类,这个标记非常类似以前常用的Serializable属性,可以实现对类标记为可序列化;[DataMember]标记需要被暴露为数据契约的数据字段属性。 - Fetion.Web.Framework.ServiceContract
Fetion.Web.Framework.ServiceContract中包含的都是接口Interface,并将接口用[ServiceContract]标记为WCF的服务契约,用[OperationContract]标记里面的方法为具体的操作契约。在ServiceContract中定义了服务的结构框架,一方面制约服务的具体实现,另一方面可以作为调用Service方的调用凭据。(在MSDN以及多数WCF的资料中会推荐用svcutil.exe来生成服务调用凭据,个人对此并不认同,后面到客户端调用时再详细阐述) - Fetion.Web.Framework.BusinessService
Fetion.Web.Framework.BusinessService中是对Fetion.Web.Framework.ServiceContract的具体实现。在这个例子中,实现了一个简单的业务逻辑:获取当前服务器的机器名以及IP地址,并填充到DataContract中定义的数据实体中,提供给服务调用方。
注意:在这个例子屏蔽掉了一个系统应该有的业务领域以及数据访问等,应该由此层完成对业务的最终封装,并发布给调用方使用。 - Fetion.Web.Framework.ServiceContainer
Fetion.Web.Framework.ServiceContainer是WCF的宿主容器,将WCF依托在IIS上。WCF和.NET Remoting相同,可以以任何Application做为宿主:Console Appliaction、Windows Service、WinForm、Web Service Applicaton,但为了能够使用IIS提供的安全性和负载均衡特性,这个例子里面选择IIS作为WCF Service的宿主。
首先,添加一个WCF Service Appliaction类型项目,添加项目引用后,删除默认添加的IService1.cs和Service1.svc.cs文件,然后修改Service1.svc文件名为ServerEnvironmentService.svc,并打开该文件(如果还没有删除Service1.svc.cs,则不能打开该svc文件),修改里面的<%@ ServiceHost%>的Service属性为引用的Service实现类Fetion.Web.Framework.BusinessService.ServerEnvironment,并删除CodeBehind属性。
因为默认的模板采用的是wsHttpBinding,而wsHttpBinding缺省使用的Security Mode是Message,而在Message模式下Windows集成验证是缺省的Credentials,所以就不再修改Web.Config,使用缺省的安全验证模式。(参见后附的)
设置该项目为启动项目,在IE中输入http://localhost:3060/ServerEnvironmentService.svc验证服务正常提供。 - Fetion.Web.Framework.ServiceWrapper
Fetion.Web.Framework.ServiceWrapper是作为WCF Service的调用端。VS2008对于WCF的调用提供了很多种快捷的方式:1、直接在项目上反选Add Service Reference,会以类似于Add Web Reference的方式自动生成对Service的引用代理生成,然后在程序中可以直接调用生成的代理类;2、使用svcutil.exe来生成用于调用服务的代理类和app.config,将文件添加到项目中,就可以通过生成的代理类调用WCF Services。
无论以上提供的哪一种方法,都会在WCF Services调用端重新生成一个代理类,包含服务接口和数据实体对象类,虽然使用方便,但改变了整个框架的完整性和一致性。事实上重新生成的代理类和实体类都是对Fetion.Web.Framework.ServiceContract和Fetion.Web.Framework.DataContract的重复实现。如果前后台的实体对象不是同一个对象,可能会在开发中产生一些麻烦,导致两个本来一致的实体对象之间需要互相赋值。
并且,自动生成的代理类完成了对调用的完全封装,如果想再添加关于数据压缩,缓存,加密,权限方面的操作将无法进行。因此,推荐在ServiceWrapper层独立封装操作调用类。
在Demo中采用扩展方法对所有System.ServiceModel.ClientBase的子类添加了一个方法:Credential(),在这个方法中封装了对WCF Service权限校验认证的代码。并让对应服务的Wrapper类继承和实现了System.ServiceModel.ClientBase 和ServiceContract的IServerEnvironment接口。 WrapperRightExtension.cs
ServerEnvironmentServiceWrapper.cs
- Fetion.Web.Framework.UIConsole
Fetion.Web.Framework.UIConsole,作为最终的UI展示,调用ServiceWrapper封装后的方法,实现对WCF Service的远程调用。在它的app.config中写入对WCF Service调用的相关配置信息,如Binding,Service的URI,服务接口类等。
以上,完成了WCF Service项目的Demo,接下来需要把项目部署到Win2K3环境中,并为两台虚拟机环境建立起负载均衡群集,实现WCF Service部署在NLB环境中。 - 发布WCF Service到Win2K3 Server
为了方便,决定采用VS2008提供的Publish功能,要使用这个功能需要Win2K3 Server的IIS上安装了FrontPage扩展。
在Fetion.Web.Framework.ServiceContainer项目上反选Publish,在Target location项的详细中选择Remote Site,输入:http://192.168.4.10/FetionFramework,如果是第一次发布,还需要点击New Web Site后确定。在点击publish按钮后,如果正常应该已经在Server-01完成了WCF Service的部署。通过在IE中输入http://192.168.4.10/FetionFramework/ServerEnvironmentService.svc验证是否正确部署。(注意,需要检查默认站点上使用的.NET Framework版本,需要设置为.NET Framework 2.0)。
重复上述过程,完成对Server-02的部署。 - 使用控制台对访问验证部署
使用Fetion.Web.Framework.UIConsole控制台对Server-01和Server-02访问验证,需要分别在Server-01和Server-02上建立两个Windows帐号:IISAdmin,密码:8848,默认的Users组即可。修改UIConsole的app.config中的address属性为http://192.168.4.10/FetionFramework/ServerEnvironmentService.svc,以验证Server-01的访问正常
重复以上过程,完成对Server-02的验证。 - Server-01和Server-02的负载均衡NLB环境搭建
查看Server-01的网卡属性,选中:网络负载均衡后,点击属性进行配置。首先在群集IP设置中填写IP地址为192.168.4.100,子网掩码为255.255.255.0,群集操作模式选择多播;然后在主机参数中的专用IP配置设置为192.168.4.10(即本机IP);最后在端口规则中将端口范围改为80~8080。完成对网络负载均衡的属性设置后,点击Internet协议(TCP/IP)的属性进行设置:在高级中添加IP地址192.168.4.100,掩码255.255.255.0。完成后确定,等待系统进行配置。
完成对Server-01的配置之后,再对Server-02进行同样的配置,只是在设置主机参数中的专用IP配置时,需要设置为Server-02自己的IP地址,即192.168.4.11。这样就完成了对NLB负载均衡环境的最简化搭建。
- 使用UIConsole控制台验证NLB环境搭建成功
修改UIConsole程序的app.config中的address属性为http://192.168.4.100/FetionFramework/ServerEnvironmentService.svc,运行该控制台程序,应该可以得到其中一台Win2K3 Server的机器名和IP地址,此时,关闭该Server后,再次执行该控制台程序,如果依然能正常访问,并且得到另一台服务器的机器名和IP地址,则验证整个试验成功。
1. 安装完 VS Extension 后,我们可以创建一个 WCF service 的网站项目。
2. 添加一个 WCF service 新项,系统自动会创建 Service.svc、App_Code\Service.cs 等必要文件。
3. 在 Service.cs 文件中完成服务编码。
4. 添加 web.config 文件,并在其位置单击鼠标右键,打开 "Microsoft Service Configuration Editor" 工具完成服务配置。
5. 注意添加 serviceMetadata,否则我们使用浏览器无法查看,也无法创建客户端代理。
web.config 演示 (注意配置文件中并没有提供服务地址)
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<services>
<service behaviorConfiguration="MyServiceTypeBehaviors" name="MyService">
<endpoint binding="wsHttpBinding" contract="IMyService"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true">
</system.web>
</configuration>
service.svc
建议将服务放到一个单独的 Library 中,这样更改宿主环境会更方便一点,不过上述步骤要做些修改。
1. 安装完 VS Extension 后,我们可以创建一个 WCF service 的网站项目。
2. 添加服务所在类库的引用。
3. 创建 svc 文件,内容也所不同。如 <%@ ServiceHost Debug="true" Service="Learn.Library.WCF.CalculateService" %>,注意使用包含名字空间的全名。
4. 添加 web.config 文件,打开 "Microsoft Service Configuration Editor" 工具完成服务配置。
5. 注意添加 serviceMetadata,否则我们使用浏览器无法查看,也无法创建客户端代理。
web.config
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.serviceModel>
<services>
<service behaviorConfiguration="MyServiceTypeBehaviors" name="Learn.Library.WCF.CalculateService">
<endpoint binding="wsHttpBinding" contract="Learn.Library.WCF.ICalculate"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MyServiceTypeBehaviors">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true">
</system.web>
</configuration>