之前,我们在Windows Azure平台简介中介绍过Windows Azure的三大主要功能。那就是计算,存储,以及管理。至今为止,通过之前的教学文章,大家已经熟知了Windows Azure的存储功能。当然,存储只是最基本的一个功能。要充分发挥云计算的威力,我们不得不学习如何“计算”。
同样在Windows Azure平台简介中,我们也介绍了Windows Azure的三种主要计算功能:
作为一个部署服务平台
作为一个软件分发平台
作为一个一般的分布式计算平台
本文将引导大家达成第一种功能:在Windows Azure上部署服务。后续文章将会介绍另两种功能。事实上,在Windows Azure入门教学系列 (一): 创建第一个WebRole程序里,大家已经尝试过部署一个最简单的服务:一个ASP.NET网站。是的,ASP.NET网站也可以称作一种服务。现在,你的ASP.NET程序不再是运行在你自己的服务器上,而是运行在云端了。但是,Windows Azure不仅仅支持常规网站,我们也完全可以把那些和用户界面无关的服务(headless services)部署至云端。例如,WCF服务,WF工作流,等等。而也正是这些headless services,使我们的web site摇身一变成为了Web API,让用户可以使用任意大小的屏幕,在任意场合,使用他们喜欢的客户端,访问我们的服务。本文将会教导大家如何在Windows Azure上部署一个WCF服务,作为入门教学,我们将使用最简单的SOAP Service。
如果你并不了解WCF,请自http://msdn.microsoft.com/en-us/netframework/aa663324.aspx开始学习。本文假设你已经了解了WCF的基础知识。
前期准备
想要在Windows Azure这样的负载平衡环境中使用WCF,首先必须下载一个hotfix。这个hotfix已经预装在云端的服务器上,但是如果你要在本地测试,还需要手工装到本机。这个hotfix解决了WCF的一些在负载平衡场合下可能出现的bug。
创建并观察项目
创建一个新的Cloud Service项目。选择添加一个WCF Service Web Role。
在这个入门教学中,我们将使用最基本的,默认生成的代码。以下是默认生成的OperationContracts:
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
打开web.config,请注意默认生成的配置使用的便是basicHttpBinding。可是如果使用普通的WCF Service项目模板,你将会得到wsHttpBinding。注意wsHttpBinding默认使用Windows Authentication,在Windows Azure中Windows Authentication是不支持的,所以如果你使用普通的WCF Service项目模板,请记得修改wsHttpBinding的安全配置,或者改成使用basicHttpBinding。
负载平衡带来的问题
现在,运行项目,你会看到标准的WCF信息页面
请注意WSDL文件的地址并不正确,我们的服务应该是运行在81端口上,但是该页面确报告WSDL文件位于端口5100。假设你点击上述链接,将会得到一个400 Bad Request错误。即使你强制在浏览器中输入http://127.0.0.1:81/Service1.svc?wsdl,你会发现虽然的确可以看到WSDL文件,但是生成的WSDL文件并不正确,包含一系列诸如 这样的链接。如果你尝试在一个客户端程序中add service reference,就会遇上错误了。
以上,正是WCF默认的行为在负载平衡场合下会引发的问题。事实上,我们的服务的第一个实例(至少在本地模拟环境中)确实运行在端口5100上,如果你的Web Role有多个实例,第二个实例很可能会运行在端口5101上。但是负载平衡器对外暴露的端口永远是你在csdef文件中指定的端口(当然在本地因为80端口已经被IIS占用,不得不使用81端口)。WCF默认并不知道负载平衡器,所以它还是认为客户端必须访问端口5100。
解决负载平衡带来的问题
之前我们提到过WCF团队已经研发了一个hotfix,用于解决负载平衡带来的问题。但是为了发挥该hotfix的功效,必须做一点配置。
首先,在web.config中找到服务的service behavior,并且添加一个名为useRequestHeadersForMetadataAddress的behavior。这个行为是通过hotfix安装的。
<behavior name="WCFServiceWebRole1.Service1Behavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
<!-- 启用hotfix解决负载平衡造成的端口不正确问题。 -->
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="http" port="80" />
<add scheme="https" port="443" />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
</behavior>
再有,在负载平衡场合,客户端所请求的地址往往和服务所部署的真正地址是不同的。因此我们推荐大家将AddressFilterMode设置成Any,从而不再检查地址匹配性。
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]
public class Service1 : IService1
现在,再次运行程序,你会看到端口81已经被成功识别出来。
将Web Role部署至云端
请参考http://blogs.msdn.com/azchina/archive/2010/02/18/webrole.aspx将Web Role部署至云端,这个过程是完全一致的,不管你使用ASP.NET,使用WCF,或者使用其它技术。本文不再重复。
现在,你可以尝试在本地构建一个客户端程序访问刚发布的服务,不过本文就不再详细介绍如何访问服务了。再下一篇文章中,我们将会从云端分发一个软件,并且让那个软件和我们的服务交互,协同工作。
总结
你可以在Windows Azure上部署任意服务,而为了充分发挥云计算的威力,我们往往不仅仅需要使用诸如ASP.NET之类的技术制作的web site,更需要使用诸如WCF之类的技术制作的Web API,从而真正地通过云,将所有种类的客户端连接起来。
在Windows Azure中使用WCF和在一般场合下使用WCF非常类似,但是我们必须注意负载平衡可能带来的问题,并做好应对方案。