本主题概述了托管 Windows Communication Foundation (WCF) 服务的一些最佳做法。
将 WCF 服务实现为 DLL
将 WCF 服务实现为部署到 Web 应用程序的 \bin 目录的 DLL 允许在 Web 应用程序模型之外重复使用该服务,例如,在可能未部署 Internet Information Services(IIS)的测试环境中。
IIS-Hosted 应用程序中的服务主机
不要使用强制性自承载 API 创建用于侦听 IIS 承载环境原生不支持的网络传输的新服务主机(例如,承载 TCP 服务的 IIS 6.0,因为 IIS 6.0 原生并不支持 TCP 通信)。 不建议使用此方法。 在 IIS 托管环境中,强制创建的服务主机未知。 关键点是,当 IIS 确定托管应用程序池是否空闲时,命令性创建服务完成的处理不会由 IIS 负责。 结果是,这些通过命令式创建服务主机的应用程序,采用了能够主动终止 IIS 主机进程的 IIS 托管环境。
URI 和承载于 IIS 中的终结点
应使用相对统一资源标识符(URI),而不是绝对地址配置 IIS 托管服务的终结点。 这可以保证终结点地址位于属于宿主应用程序的 URI 地址集中,并确保基于消息的激活按预期进行。
状态管理和进程回收
IIS 托管环境针对未在内存中维护本地状态的服务进行优化。 IIS 回收主机进程以响应各种外部和内部事件,导致内存中以独占方式存储的任何易失状态丢失。 IIS 中托管的服务应将其状态存储在进程外部(例如,在数据库中)或内存中缓存中,如果发生应用程序回收事件,则可以轻松重新创建。
注释
WCF 用于消息层可靠性和安全性的协议利用易失的内存中状态。 由于应用程序重启,WCF可靠会话和安全会话可能会意外终止。 使用这些协议的 IIS 托管应用程序应依赖于 WCF 提供的会话密钥以外的内容来关联应用程序层状态(例如应用程序层构造或自定义关联标头),或者禁用托管应用程序的 IIS 进程回收。
在中间层方案中优化性能
为了获得 中间层方案中的最佳性能(一种服务,用于调用其他服务以响应传入消息)将 WCF 服务客户端实例化到远程服务一次,并在多个传入请求中重复使用它。 实例化 WCF 服务客户端是一项昂贵的作,与对预先存在的客户端实例进行服务调用相比,中间层方案通过跨请求缓存远程客户端产生不同的性能提升。 WCF 服务客户端是线程安全的,因此不必跨多个线程同步对客户端的访问。
中间层场景通过使用svcutil /a选项生成的异步API来提升性能。
/a 选项会导致 ServiceModel 元数据实用工具(Svcutil.exe) 为每个服务操作生成 BeginXXX/EndXXX 方法,从而使对远程服务进行的运行较长时间的调用可以在后台线程上进行。
多宿主或多名称方案中的 WCF
可以在 IIS Web 场内部署 WCF 服务,其中一组计算机共享公用外部名称(例如 http://www.contoso.com),但由不同的主机名单独寻址(例如, http://www.contoso.com 可能会将流量定向到两个命名 http://machine1.internal.contoso.com 的计算机和 http://machine2.internal.contoso.com)。 WCF 完全支持此部署方案,但需要对承载 WCF 服务的 IIS 网站进行特殊配置,以便在服务的元数据(Web 服务说明语言)中显示正确的(外部)主机名。
若要确保正确的主机名出现在服务元数据 WCF 中,请为承载 WCF 服务的 IIS 网站配置默认标识以使用显式主机名。 例如,驻留在 www.contoso.com 服务器群内的计算机应使用 IIS 站点绑定 *:80:www.contoso.com for HTTP and *:443:www.contoso.com for HTTPS。
可以使用 IIS Microsoft 管理控制台 (MMC) 管理单元配置 IIS 网站绑定。
在不同用户上下文中运行的应用程序池覆盖来自临时文件夹中其他帐户的程序集
若要确保在不同用户上下文中运行的应用程序池无法覆盖临时 ASP.NET 文件夹中其他帐户的程序集,请对不同的应用程序使用不同的标识和临时文件夹。 例如,如果有两个虚拟应用程序 /Application1 和 /Application2,则可以创建两个应用程序池 A 和 B,其中包含两个不同的标识。 应用程序池 A 可以在一个用户标识(user1)下运行,而应用程序池 B 可以在另一个用户标识(user2)下运行,并将 /Application1 配置为使用 A 和 /Application2 以使用 B。
在 Web.config中,可以使用 system.web/compilation/@tempFolder< 配置临时文件夹>。 对于 /Application1,它可以是“c:\tempForUser1”,对于 application2,它可以是“c:\tempForUser2”。 将相应的写入权限授予两个标识的这些文件夹。
然后,user2 无法更改 /application2 的代码生成文件夹(在 c:\tempForUser1 下)。
启用异步处理
默认情况下,以同步方式处理发送到 IIS 6.0 及更早版本下托管的 WCF 服务的消息。 ASP.NET 在其自己的线程(ASP.NET 工作线程)上调用 WCF,WCF 使用另一个线程来处理请求。 WCF 会保持对 ASP.NET 工作线程的控制,直到完成其处理。 这会导致对请求进行同步处理。 以异步方式处理请求可实现更大的可伸缩性,因为它减少了处理请求所需的线程数 –WCF 在处理请求时不会保留 ASP.NET 线程。 对于运行 IIS 6.0 的计算机,不建议使用异步行为,因为无法控制传入请求,这会使服务器容易受到拒绝服务(DoS)攻击。 从 IIS 7.0 开始,引入了并发请求限制: [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ASP.NET\2.0.50727.0]"MaxConcurrentRequestsPerCpu 借助这一新的限制,可安全地使用异步处理。 默认情况下,在 IIS 7.0 中,将注册异步处理程序和模块。 如果已关闭此功能,则可以在应用程序的 Web.config 文件中手动启用请求的异步处理。 所使用的设置取决于你的 aspNetCompatibilityEnabled 设置。 如果将 aspNetCompatibilityEnabled 设置为 false,请按照以下配置片段对 System.ServiceModel.Activation.ServiceHttpModule 进行配置。
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="false" />
</system.serviceModel>
<system.webServer>
<modules>
<remove name="ServiceModel"/>
<add name="ServiceModel"
preCondition="integratedMode,runtimeVersionv2.0"
type="System.ServiceModel.Activation.ServiceHttpModule, System.ServiceModel,Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
</modules>
</system.webServer>
如果将aspNetCompatibilityEnabled设置为true,请按照以下配置片段所示来配置System.ServiceModel.Activation.ServiceHttpHandlerFactory。
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
</system.serviceModel>
<system.webServer>
<handlers>
<clear/>
<add name="TestAsyncHttpHandler"
path="*.svc"
verb="*"
type="System.ServiceModel.Activation.ServiceHttpHandlerFactory, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
/>
</handlers>
</system.webServer>