在Windows Azure上使用WAS和IIS托管服务
Adoption Program Insights 系列描述了微软服务咨询的经验 ( 包含在Windows Azure Technology Adoption Program内,该项目旨在帮助客户开发Windows Azure平台上的解决方案 ) 。这篇文章由Tom Hollander发表。
许多开发人员选择使用面向服务的技术来将大型系统分成更小的、松散耦合的服务。通常,每个服务将托管在不同的计算机上并使用WS-*的基于标准的通信协议。但是有时不同的托管和通信方法使其更有意义。例如,如果你控制服务和所有的客户端,使用二进制消息通过TCP发送可能使你获得更好的性能。在某些情况下,你可以选择将多台服务器托管在同一机器上并使用优化本地通信机制如命名管道,同时保持你的服务器之间的逻辑分离。
微软的应用程序平台一直使其易于支持所有的这些方案,应用程序代码很少或没有更改。Windows通信基础(WCF)通过多个消息传递协议提供了一个统一的编程模型,而Windows进程激活服务(WAS)允许你将服务托管在IIS中并通过由非HTTP发送输入报文包括TCP和命名管道来 “唤醒” 他们。
但是如果你已经决定利用Windows Azure部署你的应用程序,如何利用WAS就不明显了。但是好消息是,由于PowerShell的一点帮助,这个起作用是完全可行的。你需要写的脚本关键步骤是:
- 为你选择的协议启用并启动WAS激活服务
为你选择的协议添加绑定到IIS web站点
- 在你的web站点或应用程序上允许选择的协议
这篇博客描述了一个简单的应用程序,它由包含web站点(客户端)的一个单点web角色和托管WCF服务的一个虚拟应用程序组成。因为在客户端和服务器托管在同一机器上,我们将使用WCF的用来优化通信的NetNamedPipeBinding,虽然相同的基本方法也适用于NetTcpBinding。(注意Windows Azure上不支持MSMQ,因此你不能使用那些绑定)。我在帖子里列出了该解决方案的最主要的代码,你可以通过点击帖子底部的WasInAzure.zip文件来下载整个例子。
WCF 配置
对Azure来说关于WCF配置方面没有特殊的地方,但是为了更加完整我将展示其中一部分。我已经建立了一个简单的服务并用NetNamedPipeBinding
和net.pipe:// URL配置了一个终结点。
web.config (Service):
<system.serviceModel>
<services>
<service name="WcfService1.Service1">
<endpoint binding="netNamedPipeBinding" address="net.pipe://localhost/WcfService1/service1.svc"
contract="WcfService1.IService1"/>
</service>
</services>
</system.serviceModel>
客户端的WCF配置看起来大致相同,使用匹配的ABC(地址、绑定和合同。)
Windows Azure 启动任务
当你想要在Windows Azure实例启动时执行一些脚本,通常你将在服务定义文件的 <Startup> 元素中定义的脚本中做所有的工作。不过这里定义的任务在组织配置IIS之前执行,结果是这根本不是做出WAS大部分所需修改的合适地方。所以我们在启动任务中需要做的是配置PowerShell,从而我们可以稍后再启动序列中运行我们的脚本:
ServiceDefinition.csdef:
<ServiceDefinition name="WasInAzure"
xmlns="https://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="WebRole1">
...
<Startup>
<Task commandLine="setup\startup.cmd"
executionContext="elevated" />
</Startup>
</WebRole>
</ServiceDefinition>
Startup.cmd:
powershell -command "set-executionpolicy Unrestricted" >>
out.txt
Windows Azure角色OnStart
WebRole 类OnStart方法的在IIS被组织装配之后执行,因此在这个时候我们自由运行所需更改配置的脚本。首先要注意的是通常OnStart方法不在管理员权限下运行——我们需要为使得我们的脚本起作用更改这个。
ServiceDefinition.csdef:
<ServiceDefinition name="WasInAzure"
xmlns="https://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
<WebRole name="WebRole1">
...
<Runtime executionContext="elevated" />
</WebRole>
</ServiceDefinition>
现在,当角色启动时我们可以添加开始PowerShell脚本的代码:
WebRole.cs:
public class WebRole : RoleEntryPoint
{
public override bool OnStart()
{
var startInfo = new ProcessStartInfo()
{
FileName = "powershell.exe",
Arguments = @".\setup\rolestart.ps1",
RedirectStandardOutput = true,
UseShellExecute=false,
};
var writer = new StreamWriter("out.txt");
var process = Process.Start(startInfo);
process.WaitForExit();
writer.Write(process.StandardOutput.ReadToEnd());
writer.Close();
return base.OnStart();
}
}
最后,我们来看启动侦听服务和配置绑定的PowerShell脚本。关于此脚本有几点需要注意:
- 如果你正在使用TCP而不是命名管道,更改所有引用到net.pipe到net.tcp,更改绑定到包含你所选的端口(如“808:*”)。你还需要启用NetTcpPortSharing 和 NetTcpActivator 服务。
该脚本对角色名称做了一些假设并更改在所有IIS虚拟应用程序的协议。取决于你怎样设置你的角色和可能需要更改此设置的站点。
- 在怎样访问IIS 7.0和IIS 7.5的IIS PowerShell
cmdlets有一些不同。我的脚本适用于IIS 7.5,其中包括在Windows Server
2008 R2 和Windows Azure 操作系统“2.x”族。若要获取此版本,请确保你在ServiceConfiguration.cscfg文件根节点下设置 osFamily="2" 。或者如果你想要使用IIS 7.0 (Azure OS “1.x”) ,可以修改你的powerShell脚本来让这个起作用。
RoleStart.ps1:
write-host "Begin RoleStart.ps1"
import-module WebAdministration
# 启动net.pipe服务
$listenerService = Get-WmiObject win32_service -filter
"name='NetPipeActivator'"
$listenerService.ChangeStartMode("Manual")
$listenerService.StartService()
# 绑定net.pipe
$WebRoleSite = (Get-WebSite "*webrole*").Name
Get-WebApplication -Site $WebRoleSite | Foreach-Object { $site =
"IIS:/Sites/$WebRoleSite" + $_.path; Set-ItemProperty $site -Name
EnabledProtocols 'http,net.pipe'}
New-ItemProperty "IIS:/Sites/$WebRoleSite" -name bindings -value
@{protocol="net.pipe";bindingInformation="*"}
write-host "End RoleStart.ps1"
总结
正确配置Windows Azure服务定义和服务配置文件,最常见的配置任务无需任何编码或脚本即可获得。但是有一些有用的功能可以用来从非云端Windows安装使用,目前一般不这么做。幸运的是,如果你熟悉脚本技术和Windows Azure 启动序列,你可以通常的代码解决这些问题。有很多有用的特性,Windows Azure本身并未启用,Windows Process Activation Services就是一个很好的例子。我们可以通过一些努力来启用它。