Windows Azure Platform (二十六) 动态指定WCF的发布地址
2012-03-22 11:58:35 来源:WEB开发网在刚才的例子中,服务端和客户端都是通过配置文件明确指定了WCF的地址,而如果现在需要将此服务发布到别的Hosted Service,那么还需要响应地修改配置文件。并且,如果WCF使用的端口号发生变化,在修改了Windows Azure开放的Endpoint信息同时,开发人员还需要修改配置文件中的WCF部分。
Windows Azure SDK附带的类库允许用户通过编程的方式获得当前Role Instance的IP地址以及所有Endpoint的信息,因此对于上述的问题可以通过代码的形式配置WCF服务,动态指定地址和端口号。
首先打开服务端的配置文件,将system.serviceModel节点删除,以代码的方式来配置WCF服务。在WorkerRole的OnStart()方法里面创建ServiceHost,通过编程指定其地址、绑定和契约。
//host the wcf service _host=new ServiceHost(typeof(EchoService)); //retrieve the endpoint address var endpoint=RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["EchoService"]; var address=new Uri(string.Format("net.tcp://{0}/EchoService")); //add the endpoint into the wcf host _host.AddServiceEndpoint(typeof(IEchoService),new NetTcpBinding(SecurityMode.None),address); //open the host _host.Opened += (sender,e) => { Trace.TraceInformation("Listening at {0}",_host.Description.Endpoint[0].ListenUri); }; _host.open();
在上面的代码中,RoleEnvironment类的CurrentRoleInstance属性返回当前Role Instance的状态和配置信息,包括ID、故障域(Fault Domin) ID、升级域(Upgrade Domain) ID以及Endpoint信息。通过Endpoint名字,开发人员便可以获得当前Instance下某个Endpoint的完整地址。在上面的代码中,我们通过EchoService这个名称获得了Input Endpoint的地址,然后将其格式化为合法的NET.TCP地址并配置到ServiceHost中。在这个例子中,由于事先为这个Role配置了两个 Instance,所以这段代码会分别在两个Windows Azure虚拟机中执行,也就是说相同的WCF服务会被部署在两台机器上,通过代码获取到的Endpoint信息是不一样的。而客户端的请求都会通过 Hosted Service URL进入Windows Azure负载均衡服务器,然后路由到这两个虚拟机中。
除此之外还需要一些额外的修改工作。打开EchoService类,在类定义部分需要加入一个Service Behavior标签。为了测试在服务器端返回结果的时候加入一些额外的信息来显示当前的消息是由哪个Role Instance通过哪个Endpoint访问的。
[ServiceBahavior(AddressFilterMode = AddressFilterMode.Any)] public class EchoService : IEchoService { public string Echo(string content) { var date = DateTime.Now; var instance = RoleEnvironmentCurrentRoleInstance.Id; var endpoint = RoleEnvironmentCurrentRoleInstance.InstanceEndpoints["EchoService"]; return string.Format("[SERVER] {0} - {1}. (by {2} at {3})", content. date.ToString(), instance, endpoint.IPEndpoint); } }
现在讲修改后的服务发布到了Windows Azure平台,然后通过客户端程序测试。可以看到,客户端连接到Windows Azure上的Hosted Service URL,但是实际执行请求的是其中一个Instance。
通过这种方式寄宿WCF服务,为什么要在代码中加入一个Service Behavior标签并且将AddressFilterMode设定为Any呢?我们知道在默认配置下,WCF会验证接收客户端请求的服务器地址和这个服务所发布的地址是否一致。如果一致,那么WCF将会处理这个请求,否则就不予处理。而此前通过配置文件寄宿的时候,由于WCF服务器发布的地址已经确定就是Hosted Servuce URL,即接收客户端请求的地址,因此不会出现什么问题。而在修改后的代码中,我们是动态获取当前Role Instance的地址配置ServiceHost。
如上图所示,两个Role Instance都会获得一个在数据中心的内部IP地址,而WCF会被发布在各自虚拟机的这个外部地址上。客户端请求首先到达Windows Azure负载均衡服务器,也就是Hosted Service对外开放的VIP地址。然后负载均衡将会给予Service Model的配置将请求路由到某个Role Instance上面。所以可以看到,在这种情况下客户端的请求消息是在Load Balancer上,而最终执行这个请求缺是某个Role Instance上面的WCF服务,即获取客户端请求的地址和WCF的发布地址并不一致,因此默认情况下WCF将不会处理这个请求。加入 AddressFilterMode.Any标签则要求WCF框架无需验证消息地址的一致性,直接处理请求。
更多精彩
赞助商链接