转自:http://www.microsoft.com/china/MSDN/library/Windev/WindowsVista/bb332338.mspx?mfr=true
Chris Peiris(澳大利亚 Avanade 公司,http://www.chrispeiris.com/)
Dennis Mulder(荷兰 Avanade 公司,http://www.dennismulder.net/)
适用于:
• | Microsoft .NET Framework 3.0 |
• | Windows Vista |
• | Microsoft Internet 信息服务 |
• | Microsoft Visual Studio 2005 |
摘要:本文讨论 Windows Communication Foundation (WCF) 承载方案和 WCF 服务的使用。传统的 ASMX Web 服务通常仅由 Microsoft Internet 信息服务 (IIS) 承载。在 Microsoft .NET Framework 3.0 中,WCF 服务的承载方案得到了极大的增强。我们将讨论如何将承载模型扩展为包括 Windows 服务和自承载方案。此外,我们还将详细探讨可用于 WCF 服务的 IIS 承载(版本 5.1、6.0 和 7.0)和 Windows 激活服务 (WAS) 承载方案。本文内容是根据 Apress 出版的《Pro WCF: Practical Microsoft SOA Implementation》一书第 5 章内容编撰的。这本书是由 Avanade 公司的全球顾问团队编写的。其主要针对入门级到中级读者。包括这本书在内,Apress 已出版了一系列有关 Windows Presentation Foundation (WPF)、Windows Communication Foundation (WCF) 和 Windows Workflow Foundation (WF) 的丛书。
简介 | |
研究承载方案 | |
自承载您的服务 | |
在 Windows 服务中进行承载 | |
使用 Internet 信息服务进行承载 | |
使用 WCF 服务 | |
结论 |
如果企业依赖于面向服务的体系结构,就必须确保服务能够正常可靠的运行。应用程序可靠性背后最重要的动因是在哪里托管服务以及如何托管服务。在考虑托管服务时,您必须事先考虑几个问题:服务有哪些可用性方面的要求?如何管理和部署服务?是否需要提供对旧版本服务的支持?
了解如何满足这些业务要求对于开发成功的服务是至关重要的。在第 3 章中您将了解到,必须自己提供宿主来承载服务。Windows Communication Foundation (WCF) 本身没有附带宿主,而是提供了一个被称为 ServiceHost 的类,该类允许您在自己的应用程序中承载 WCF 服务。您不必考虑任何网络传输方面的细节,即可确保服务能够被访问。只需以编程方式或声明方式对服务的端点进行配置,然后调用 ServiceHost 的 Open 方法即可。ServiceHostBase 和 ServiceHost 中集成了第 3 章要介绍的有关绑定、通道、调度程序和侦听器的所有一般功能。这意味着用于承载服务的应用程序(运行 ServiceHost 的应用程序)的负载将远远低于您之前预期的水平。
本章讨论何种类型的应用程序可以为 ServiceHost 提供宿主环境。此外,您还会对使用不同应用程序内承载的服务时存在的差异有所了解。
读完本章后,您将学到以下知识:
• | 适用于您的各种不同的承载方案 |
• | 每种承载方案有哪些优点和缺点 |
• | 根据具体情况选择承载方案的指导 |
• | 有关 Microsoft 如何实现不同承载方案以及每种方案在哪些方面具有可扩展性的体系结构方面的指导 |
在 Microsoft .NET 平台上,使用 Microsoft Visual Studio.NET 可以创建几种不同类型的托管 Windows 应用程序:
• | WinForms 应用程序 |
• | 控制台应用程序 |
• | Windows 服务 |
• | 承载于 Internet 信息服务 (IIS) 中的 Web 应用程序 (ASP.NET) |
• | IIS 7.0 内提供的 WCF 服务以及 Windows Vista 或 Windows Server 2007 中的 WAS |
如果您仔细研究 Microsoft Visual Studio 2005 附带的项目模板,就会发现还有其他可选方案供您使用。很显然,我们认为没有其他模板可以在服务世界中用作可行的方案。但值得注意的是,只要 WCF 能够提供 .NET 应用程序域,您就可以在其他任何类型的应用程序中运行服务。(如果您不了解 .NET 应用程序域的原理,请参考下面“了解 .NET 应用程序域”一节的有关内容。)实际上这完全取决于您对宿主的要求。总结这些可选方案,我们主要考虑以下三类常见的 WCF 服务宿主:
• | 在托管的 .NET 应用程序中进行自承载 |
• | 在 Windows 服务中进行承载 |
• | 在不同版本的 IIS 中进行承载 |
可想而知,如本节之前提到的,所有这些宿主在 Visual Studio 中都有相关联的项目模板,并且都有自己的特征。要想更好地了解在每种情况下哪种宿主是最佳选择,必须了解宿主通常的要求和功能。理解这一点后,我们将分别详细介绍每种承载方案。
如果您了解 Windows 进程的角色以及如何通过托管代码与它们交互,那么您肯定会对 .NET 应用程序域的概念有所了解。要在进程中运行托管 .NET 代码,就需要创建程序集。这些程序集并不直接承载于 Windows 进程中。而是由公共语言运行库 (CLR) 在进程中创建称为“应用程序域”的单独逻辑分区来对托管代码进行隔离。单个进程可能会包含多个应用程序域,每个域都会承载封装于程序集内的不同代码片断。这种对传统 Windows 进程的划分方式可以通过 .NET Framework 提供几个好处。
主要好处如下所示:
• | 由于不涉及可执行文件或库的概念,应用程序域决定了 .NET 平台的与操作系统无关的特性。 |
• | 您可以根据自身需要控制、卸载和加载应用程序域。 |
• | 应用程序域在应用程序或多个应用程序域共生的进程中起到隔离的作用。进程中的应用程序域彼此相互独立,虽然一个域出现故障,但其他域仍可正常工作。 |
.NET 应用程序需要一个作为宿主的 Windows 进程。该 Windows 进程内部可以承载多个 .NET 应用程序域。应用程序域是 .NET CLR 将托管代码与 Windows 进行隔离所采用的一种手段。CLR 会在每个工作进程中进行初始化,并自动创建一个默认的应用程序域。该默认应用程序域运行于某个进程,并直到该进程结束时才会卸载。默认应用程序域的关闭是由 CLR 来控制的。在大多数宿主中,默认应用程序域内部并不运行任何代码。而是由宿主(或“进程”)来新建应用程序域,以便应用程序域可以独立于进程而关闭。在很多应用程序中,理想的情况是客户端代码和服务器端代码分别在不同应用程序域中执行。通常这种要求是出于安全性和隔离等原因的考虑。
进程和应用程序域之间的关系类似于应用程序和应用程序域与 ServiceHostWCF 之间的关系。如图 5-1 所示,每个进程都至少有一个应用程序域,并且每个应用程序域都可以承载零个或更多的 WCF ServiceHost 实例。WCF 需要一个 Windows 进程内部至少要承载一个应用程序域。
图 5-1. 进程、应用程序域和 WCF ServiceHost 关系
注意 尽管可以实例化多个 ServiceHost 实例,但每个应用程序域内保留一个 ServiceHost 实例更便于操作。您可以在一个宿主内使用多个端点公开多个服务接口。更高级的宿主(例如,IIS 和 WAS)确实可以实例化多个 ServiceHost 实例,以提供隔离和不同的安全上下文。
因此,宿主的主要任务是向 WCF ServiceHost 提供 Windows 工作进程和应用程序域。此外,WCF 依赖于应用程序域提供的安全和配置功能。Windows 进程始终使用默认标识运行,WCF 服务可随时使用这个现成的标识。但是,WCF 提供了几个级别的模拟用户的功能(详见本书第 7 章)。如果您不使用这些功能,则由运行服务的 Windows 进程提供安全上下文。前面几章提到过,默认情况下 WCF 依赖于 .NET Framework 中的配置功能,您可以通过应用程序域对其进行访问。
某些宿主还具有管理所运行的应用程序的其他功能。最为突出的是,IIS 还具备自动进程回收、资源限制、日志记录、运行状况指示器等其他功能。您可以通过整个章节的学习了解有关这些主题的详细内容。(不同 IIS 版本具有受 WCF 支持的不同的可管理性功能。最为明显的,Windows XP 中的 IIS 5.1 在管理用户界面方面就受到一些限制。)
Microsoft 在确保服务开发人员无需过分考虑承载环境方面所做的努力是值得肯定的。ServiceHost 排除了所有技术性的难点,使您可以重点关注服务逻辑,而不必过多地考虑如何承载服务。您必须根据自己的具体要求选择一个宿主。WCF 主要是作为编程模型而编写的,其主要设计目的之一是为了实现“宿主的不可知”。ServiceHost 不关心自身在哪里被实例化,只要您希望服务可被访问时它正在运行即可。也就是说,它需要一个运行 .NET 应用程序域的进程。
在选择应用程序类型时,必须考虑某些特定要求(例如,程序属于控制台应用程序还是 WinForms 应用程序等)。ServiceHost 必须被实例化才能提供运行服务所需的承载环境。典型的 .NET 应用程序(例如,控制台应用程序和 WinForms 应用程序)通常运行在用户桌面计算机上。这些环境并非始终运行,它们可以承载您的服务,但却并非典型的适用于企业的宿主。我们认为适用于企业的宿主应该能够支持更大规模的面向服务的体系结构,在这种体系结构中,多个系统需要依赖服务所公开的关键业务功能。这些适用于企业的宿主通常能够满足诸如高可用性的要求。因此,我们不能将控制台或 WinForms 应用程序做为适用于企业的宿主。
通常情况下,服务运行在服务器上,并由操作员进行管理和操作。管理服务器的操作员一般不希望在服务器重新启动时手动启动控制台应用程序或 WinForms 应用程序。为了让服务应用程序能够在数据中心运行,对于企业级面向服务的情况来说,唯一可行的方案就是在 IIS 上承载服务,或将其作为一项 Windows 服务。
有时,您需要在用户的桌面计算机上实现进程间通信。在这种情况下,只有当用户使用应用程序时,服务才是活动的。需要进行进程间通信的典型应用程序就是控制台应用程序和 WinForms 应用程序。这些应用程序适合承载这些类型的服务。
要能够确定哪种宿主最适合您的情况,您应当考虑到非功能性要求。一般来讲,非功能性要求规定了应用程序的技术要求,以确保其达到应用程序要求的质量和可维护性。对于 WCF 应用程序来说,非功能性要求实际涉及以下内容:
• | 可用性:希望何时能够访问您的服务? |
• | 可靠性:当服务由于某些原因出现中断时会发生什么问题?这将如何影响服务的其他使用者? |
• | 可管理性:是否需要便捷地了解承载 WCF 服务的宿主上所发生的情况? |
• | 版本控制:是否需要提供对旧版本服务的支持?是否知道谁在使用您的服务? |
• | 部署:要采用何种部署模型?是否要通过 Microsoft Installer 进程和 Visual Studio 部署包进行安装,还是使用 xcopy 就可以满足需要? |
• | 状态:服务是无状态的吗?是否需要会话? |
根据这些非功能性要求,您可以确定哪些宿主是符合您的需求的。为了帮助您做出选择,本章后面的内容将介绍不同的承载环境及其优缺点。
注意 由于对自身的运行环境并不了解,因此 WCF 编程模型总是有可能切换到不同宿主,但这并不意味着您必须更改服务实施。首先,您需要在控制台应用程序中进行自承载,以测试并确定服务的原型。
承载 WCF 服务最灵活、最便捷的方法就是进行自承载。要能够自承载服务,必须满足两个条件。第一,需要 WCF 运行时;第二,需要可以承载 ServiceHost 的托管 .NET 应用程序。您需要自己动手编写启动和停止宿主的代码。
下面是自承载的优点:
• | 易用性:只需几行代码即可使服务运行。 |
• | 灵活性:通过 ServiceHost<T> 的 Open() 和 Close() 方法,可以轻松控制服务的生存期。 |
• | 易调试性:可以使用熟悉的调试方式对自承载环境中承载的 WCF 服务进行调试,而不必连接到单个应用程序来激活服务。 |
• | 易部署性:通常,部署简单 Windows 应用程序与使用 xcopy 一样容易。您不必在服务器场和类似地方部署复杂的方案,即可部署简单的 Windows 应用程序来充当 WCF ServiceHost。 |
• | 支持所有绑定和传输:自承载并不限制您仅能使用现有的绑定和传输技术。在 Windows XP 和 Windows Server 2003 上,IIS 限制您只能使用 HTTP。 |
下面是自承载的缺点:
• | 可用性受到限制:服务只有在应用程序运行时才能被访问。 |
• | 功能受到限制:自承载的应用程序在对高可用性、易管理性、可靠性、可恢复性、版本控制和部署方案的支持方面受到一定限制。至少,现有的 WCF 无法提供这些支持,因此在自承载的情况中,您必须自己实现这些功能;例如,默认情况下 IIS 提供了这些功能中几项。 |
换句话说,对于企业级方案来说不应考虑自承载方式。自承载适用于企业项目的开发或演示阶段。此外,当您希望用户桌面应用程序进行相互通信或在点对点情况下,可以对服务进行自承载。本书第 12 章对此进行了描述。
第 3 章介绍了几个自承载的方案示例,这些示例全都使用简单的控制台应用程序。为了在实际工作环境中更好地说明自承载,本章提供了一个 WinForms 应用程序,该程序所承载的服务用于跟踪 QuickReturns Ltd. 案例研究中证券商发布的报价。
在此方案中,有两个不同的 WinForms 应用程序。一个是证券商管理器应用程序,证券商可以使用该程序发布报价并进行证券交易。另一个程序是单独的 WinForms 应用程序,用于跟踪发布的报价。如列表 5-1 所示,该程序公开一个服务,所公开的服务实现了 ITradeTrackingService 约定,从而实现对报价的跟踪。证券商管理器应用程序会在成功通过 TradeService 发布报价后调用该服务。
列表 5-1. TradeTrackingService 的 ServiceContract
using System.ServiceModel; using QuickReturns.StockTrading.ExchangeService.DataContracts; namespace QuickReturns.StockTrading.TradeTrackingService.Contracts { [ServiceContract()] interface ITradeTrackingService { [OperationContract()] void PublishQuote(Quote quote); } }
在 Windows 服务中承载 WCF 服务是一种合理的选择。不应将 Windows 服务与 WCF 服务混为一谈。它们都使用“服务”一词,但却具有不同的含义。Windows 服务是由操作系统管理的进程。Windows 提供了服务控制管理器,用于控制操作系统上安装的服务。Windows 通过服务来支持诸如网络、USB、远程访问、消息队列等操作系统功能。您可以使用 Visual Studio 2005,利用 Windows 服务项目模板(如图 5-2 所示)创建 Windows 服务。
图 5-2. Visual Studio 2005 Windows 服务项目模板
Windows 服务项目模板会生成一个项目,其中包含两个文件:service1.cs 文件和 program.cs 文件。其中 service1.cs 文件包含服务实现,而 program.cs 文件则用于实例化并实质上承载 Windows 服务。要在 Windows 服务内部承载 WCF 服务,只需执行 Windows 服务的 Start() 方法和 Stop() 方法,如列表 5-2 所示。由于启动 Windows 服务的范例与启动 WCF ServiceHost 内的服务相似,因此最后需要将 WCF 服务的生存期与 Windows 服务的生存期相连。
列表 5-2. 承载 WCF ServiceHost 的 Windows 服务
using System; using System.ServiceModel; using System.ServiceProcess; using QuickReturns.StockTrading.ExchangeService; namespace QuickReturns.StockTrading.ExchangeService.Hosts { public partial class ExchangeWindowsService : ServiceBase { ServiceHost host; public ExchangeWindowsService() { InitializeComponent(); } protected override void OnStart(string[] args) { Type serviceType = typeof(TradeService); host = new ServiceHost(serviceType); host.Open(); } protected override void OnStop() { if(host != null) host.Close(); } } }
由此可见,编写用于承载 WCF 服务的 Windows 服务非常容易,而且与本章前面的自承载方案相比,它还有几个好处。另一方面,编写承载 WCF 服务的 Windows 服务也有一些您必须了解的缺点。
首先让我们看一下优点:
• | 可以自动启动:Windows 服务控制管理器允许将启动类型设置为自动,从而可以在 Windows 启动立即启动服务,而不必在计算机上进行交互登录。 |
• | 可以恢复:Windows 服务控制管理器内建了对发生失败后重新启动服务的支持。 |
• | 安全标识:Windows 服务控制管理器允许您选择运行服务所使用的特定安全标识,包括内置的系统或网络服务帐户。 |
• | 可管理性:通常情况下,Windows 操作员对那些用于进行 Windows 服务安装和配置的服务控制管理器和其他管理工具都非常熟悉。这将使 Windows 服务在实际工作环境中更容易被采纳;但是,为了保证服务的可维护性,您可能需要添加某些检测和日志记录功能。 |
• | 支持所有绑定和传输:自承载并不限制您仅能使用现有的绑定和传输技术。在 Windows XP 和 Windows Server 2003 上,IIS 限制您只能使用 HTTP。 |
接下来是 Windows 服务的一些缺点:
• | 部署: 必须通过 .NET Framework Installutil.exe 实用工具或通过安装包中的自定义操作来安装服务。 |
• | 功能受到限制:Windows 服务在对高可用性、易管理性、版本控制和部署方案的支持方面同样也受到一定限制。实际上,您必须自己编写自定义代码来满足这些要求,而 IIS 在默认情况下就带有这些功能的其中几项。Windows 服务确实添加了可恢复性和一些安全功能,但有些任务仍然需要您亲手去做。 |
要能够在服务控制管理器中安装服务,必须在项目中添加安装程序。Visual Studio 2005 允许您方便地完成该操作:
1. |
在 Windows 服务项目中打开 Service 类的设计器视图。 |
2. |
单击设计器背景以选择服务本身,而并非其任何内容。 |
3. |
在“属性”窗口中,单击属性列表下灰色区域中的“添加安装程序”链接,如图 5-3 所示。默认情况下,该操作将在项目中添加一个包含两个安装程序的组件类。组件名为 ProjectInstaller,它包含的安装程序是服务的安装程序和该服务相关进程的安装程序。 图 5-3. Windows 服务项目的“添加安装程序”功能 |
4. |
访问 ProjectInstaller 的设计器视图,并单击 ServiceInstaller1。 |
5. |
在“属性”窗口中,将“ServiceName”属性设置为“QuickReturns Exchange 服务”。 |
6. |
将“StartType”属性设置为“自动”,如图 5-4 所示。 图 5-4. QuickReturns Exchange 服务的属性窗口 |
7. |
访问 ProjectInstaller 的设计器视图,并单击“serviceProcessInstaller1”。 |
8. |
在“属性”窗口中,将“帐户”属性设置为“网络服务”,如图 5-5 所示。 图 5-5. QuickReturns Exchange 服务的属性窗口 |
为了能够创建可用于安装 Windows 服务的安装程序,必须向解决方案添加 Visual Studio 安装程序和部署项目。以下步骤描述了如何向解决方案添加安装程序和部署项目:
1. |
选择“文件” | “添加” | “新建项目”。 |
2. |
在“新建项目”对话框中,选择“其他项目类型”类别,选择“安装和部署”,然后选择“安装项目”,如图 5-6 所示。 图 5-6. Visual Studio 2005 安装项目模板 |
3. |
在解决方案资源管理器中,右键单击安装项目,指向“添加”,然后选择“项目输出”,如图 5-7 所示。此时将显示“添加项目输出组”对话框。 图 5-7. 添加 Windows 服务项目输出 |
4. |
选择 Windows 服务项目。 |
5. |
从列表框中,选择“主输出”,然后单击“确定”。 |
此操作将向安装项目添加 Windows 服务的主输出的项目项。现在,添加用于安装可执行文件的自定义操作。若要向安装项目添加自定义操作,请执行以下步骤:
1. |
在解决方案资源管理器中,右键单击安装项目,指向“视图”,然后选择“自定义操作”,如图 5-8 所示。此时将显示“自定义操作”视图。 图 5-8. 打开“自定义操作”视图 |
2. |
右键单击“自定义操作”,选择“添加自定义操作”。 |
3. |
双击列表框中的应用程序文件夹将它打开,从 Windows 服务项目中选择“主输出”,然后单击“确定”。主输出将添加到自定义操作的所有四个节点中:安装、提交、回滚和卸载。 |
4. |
生成安装项目。 |
编译项目时,输出的是 Microsoft 安装程序文件 (.msi) ,通过该文件可以将服务安装到 Windows 服务控制管理器中。
注意 本章介绍生成 Windows 服务和 Windows 服务安装程序的基础知识。如果将 Windows 服务设置为在不受限制的 Localsystem 帐户下运行或基本合适的网络服务帐户下运行,就安全最佳方法而言,这并非最佳选择。通常,操作员能够在安装期间选择凭据,或在安装之后通过服务控制管理器管理控制台管理单元(可以通过 Windows 计算机管理进行访问)来调整安全标识设置。有关开发 Windows 服务的详细信息和最佳方法,请参阅本书第 7 章、MSDN 帮助或 .NET 开发专著。
在 IIS 上的 Web 服务开发长期以来一直是 ASP.NET 的领地。ASP.NET 1.0 发布后,Web 服务框架成为它的一部分。Microsoft 利用 ASP.NET HTTP 管道使 Web 服务在 Windows 平台上成为现实。遗憾的是,ASP.NET 和 Web 服务之间的这种紧密耦合在面向服务的世界中产生了几个限制,对 HTTP 的依赖性是主要原因。在不同宿主上运行 ASP.NET HTTP 管道很困难,因此很少采用这种方案。甚至在此后,ASP.NET Web 服务(也称为 ASMX 服务)在部署方案和配置依赖性方面一直是非常面向 Web 的。Microsoft 最初发布了几个版本的 Web 服务增强 (WSE),以弥补 ASP.NET Web 服务的某些局限,尤其是消除在实现 WS-* 协议方面的限制。但是,WSE 非常依赖于 ASP.NET Web 服务实现。
在以前几章中介绍过,WCF 服务采用了完全不同的途径来实现面向服务。WCF 的统一编程模型基于严格分层的模型,以分解面向 Web 的范例,并使服务模型和通道层与受支持的传输方式断开连接。此模型允许 WCF 支持几个不同的宿主,其中 IIS 是最重要的。
构建 WCF 是为了支持 Windows XP、Windows Server 2003、Windows Vista 和 Windows Server 2007。自从 IIS 5.1(与 Windows XP 一起发布)以来,有了很多变化。但是,Microsoft 仍然继续支持旧版上的 WCF。这可能是因为 Microsoft .NET Framework 和 CLR 提供的功能所导致的,该功能是构建 WCF 的基础。在以下几节中,将介绍不同 IIS 版本的进程模型之间的差异和 WCF 服务的结果。
为了能够解释这些差异,我们首先必须解释 IIS 的核心功能。IIS 长期以来一直支持在一个计算机上运行多个站点和多个应用程序。为了做到这一点,IIS 引入了公用地址模型,该模型分为三个主要区域:
• | 站点(注意:与 Windows XP 一起发布的 IIS 5.1 只支持一个站点。) |
• | 应用程序 |
• | 虚拟目录 |
站点绑定到特定方案、网络地址和端口组合。IIS 不仅支持 HTTP,而且依据版本还支持 FTP、NNTP 和 SMTP。可以在相同站点下和在相同方案、网络和端口组合下运行多个应用程序。应用程序的典型 URI 是 http://localhost/MyApplication。虚拟目录只是映射到站点网络空间的文件夹,它可以是文件系统中的其他某处。这样,就可以使应用程序的实际内容或代码与作为相同站点组成部分的其他应用程序分隔开来。
在 IIS 6.0 中,Microsoft 对 IIS 进程模型做了一些重要更改。IIS 进程模型被拆分成可以由站点和应用程序共享的应用程序池,在这里,每个应用程序都运行在它自己的应用程序域中。“应用程序池”是称为 W3wp.exe 的单独 Windows 工作进程,并且只在它需要启动时才会启动。换句话说,IIS 带有应用程序激活模型,它允许 IIS 在它收到与应用程序池绑定的特定应用程序的请求时启动该应用程序池。这样,IIS 就能在一个服务器上承载数千个应用程序,而不必一直运行数千个进程。IIS 的激活体系结构在服务世界中是有趣的模型,本章的“Windows 激活服务”节将对此进行介绍。
图 5-9 显示在 HTTP 协议堆栈底部的 IIS 6.0 核心体系结构以及在其顶部的至少四个不同进程。
图 5-9. IIS 6.0 核心体系结构
• | Lsass.exe: 负责 IIS 的安全功能:实现 Windows 身份验证和安全套接字层 (SSL)。 |
• | Inetinfo.exe: 承载非 HTTP 服务和 IIS Admin 服务(包括元数据库)的进程。 |
• | SvcHost.exe: 可以承载操作系统服务的进程;在使用 IIS 的情况下,它承载 Web (HTTP) 服务。 |
• | W3wp.exe: 工作进程。IIS 可以有多个 W3wp.exe 进程,每个应用程序池一个。若要支持在单独进程中拆分一个应用程序的 Web 园方案,则有多个相同工作进程的实例。这可以提供额外的可伸缩性和性能优势。 |
注意 我们要在这里描述 IIS 6.0 体系结构,因为它是发布 WCF 之前最广泛使用的 IIS 版本。此外,WCF 支持 IIS 6.0,并且该模型与使用 IIS 7.0 和 Windows 激活服务时选择的实现非常类似,本章后面将对此进行介绍。IIS 5.1 和 IIS 6.0 之间的主要差异是站点和应用程序池的数量受到限制。IIS 5.1 只支持绑定到一个应用程序池的一个站点。
若要在 IIS 中承载 WCF 服务,需要有一个扩展名为 .svc 的新物理文件。该文件将服务与其实现相关联,并且是 IIS 自动创建 ServiceHost 的手段。IIS 将接管服务与 ServiceHost 之间的交互,不必再由您自己实例化和启动 ServiceHost。.svc 文件的第一行包含一条夹在 ASP.NET <% Page %> 指令内的指令,用于告诉承载环境此文件指向哪个服务。然后,服务代码可以驻留在内嵌代码行内(如列表 5-3 所示)、在注册于 GAC 的单独程序集中、在驻留于应用程序的 Bin 文件夹内的程序集中、或者在驻留于应用程序的 App_Code 文件夹下的 C# 文件中。最常见方案是在配置文件中定义端点。在 IIS 中,必须在 Web.config 文件中定义端点,下一节将对此进行解释。
列表 5-3 显示一个基于前面的 TradeService 服务的示例 .svc 文件。它有内嵌于代码行内的服务代码。列表 5-4 显示一个示例 .svc 文件,其中,代码驻留于 App_Code 文件夹内。
列表 5-3. 包含内嵌代码的 ExchangeServiceInline.svc 文件
<%@ServiceHost Language="C#" Service="QuickReturns.StockTrading.ExchangeService.TradeServiceInline" %> using System; using System.Collections; using System.ServiceModel; using QuickReturns.StockTrading.ExchangeService.Contracts; using QuickReturns.StockTrading.ExchangeService.DataContracts; namespace QuickReturns.StockTrading.ExchangeService { [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, IncludeExceptionDetailInFaults=true)] public class TradeServiceInline : ITradeService { public Quote GetQuote(string ticker) { ... } public void PublishQuote(Quote quote) { ... } } }
列表 5-4. 包含外部代码的 ExchangeService.svc 文件
<% @ServiceHost language="C#" Service=" QuickReturns.StockTrading.ExchangeService.TradeService" CodeBehind="~/App_Code/TradeService.cs" %>
在 IIS 中进行承载意味着您必须在要承载服务的应用程序的 Web.config 文件中设置 WCF 配置。Web.config 文件中的服务配置类似于自承载服务。列表 5-5 显示一个 TradeService 服务的 Web.config 示例文件。
列表 5-5. 用于配置 IIS 中承载服务的 Web.config
<?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.serviceModel> <services> <service name="QuickReturns.StockTrading.ExchangeService.TradeService" behaviorConfiguration="tradeServiceBehavior"> <endpoint name="basicHttpBinding" address="" binding="basicHttpBinding" contract="QuickReturns.StockTrading.ExchangeService.? Contracts.ITradeService"/> <endpoint name="mexHttpBinding" contract="IMetadataExchange" binding="mexHttpBinding" address="mex" /> </service> <service name="QuickReturns.StockTrading.ExchangeService.TradeServiceInline" behaviorConfiguration="tradeServiceBehavior"> <endpoint name="basicHttpBinding" address="" binding="basicHttpBinding" contract="QuickReturns.StockTrading.ExchangeService.? Contracts.ITradeService"/> <endpoint name="mexHttpbinding" contract="IMetadataExchange" binding="mexHttpBinding" address="mex" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="tradeServiceBehavior" > <serviceMetadata httpGetEnabled="true" /> </behavior> <behavior name="returnFaults" returnUnknownExceptionsAsFaults="true"/> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
请注意,服务的 address 属性为空。.svc 文件确定服务的 base 地址。但是,可以提供其他字符串用于设置相对于 .svc 文件的端点地址。例如,可以使用以下格式:
http://localhost:8080/QuickReturns/Exchange.svc/ExchangeService
在配置文件中指定的服务 name 属性充当了对应于 ExchangeService.svc 的查找键,它告诉承载环境此配置属于哪个服务。端点级别的其他属性与前面的解释相同。
在 IIS 中,Web 配置文件可以嵌套在站点、应用程序和虚拟目录内。WCF 将接受所有配置文件,并将服务及其端点合并在一起。这意味着,嵌套的 Web.config 文件将相互叠加,在层次结构的底部读取的最后一个文件优先于在层次结构中更高的文件。
在 IIS 中承载 WCF 服务的默认行为是该 IIS 控制 ServiceHost 的实例化。这将使您无法在消息到达服务之前有启动和关闭代码。当然,无启动和关闭代码的优点是可以减少可能引起错误的代码。IIS 为您提供了在代码行方面比控制台应用程序更容易的承载环境。但是,有时仍然需要有避免此限制的手段。要在实例化 ServiceHost 时这样做并影响 IIS,可以建立您自己的工厂,用于创建自定义宿主。这样,就可以访问任何事件或改写任何方法。
为了支持自定义 ServiceHost 激活,应当实现自己的 Factory,它继承自 ServiceHostFactory,这是可以实例化自定义宿主的工厂类。提供该类是为了关联 ServiceHost 的事件。您可以使用该类并将该类型作为 Factory 属性放在 .svc 文件中,如列表 5-6 所示。通过改写 ServiceHostFactory 类的 CreateServiceHost 方法,可以执行与在自承载方案中相似的任务,第 3 章对此进行了介绍。在其他方面,这将使您能够抽象逻辑,以便从外部配置建立说明,或为要使用的基础库、项目、部门或公司创建更合适的基类。
列表 5-7 显示用于创建宿主的 TradeServiceCustomHost 和 TradeServiceCustomHostFactory 的代码。
列表 5-6. 包含 CustomServiceHostFactory 的 .svc 文件
<% @ServiceHost Language="C#" Debug="true" Service="QuickReturns.StockTrading.ExchangeService.TradeService" Factory="QuickReturns.StockTrading.ExchangeService. TradeServiceCustomHostFactory" %> 列表 5-7. TradeServiceCustomHostFactory 和 TradeServiceCustomHost using System; using System.ServiceModel; using System.ServiceModel.Activation; namespace QuickReturns.StockTrading.ExchangeService { public class TradeServiceCustomHostFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost( Type serviceType, Uri[] baseAddresses) { TradeServiceCustomHost customServiceHost = new TradeServiceCustomHost(serviceType, baseAddresses); return customServiceHost; } } public class TradeServiceCustomHost : ServiceHost { public TradeServiceCustomHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) { } protected override void ApplyConfiguration() { base.ApplyConfiguration(); } } }
在 IIS 中承载 WCF 服务时,WCF 服务可以使用 ASP.NET 应用程序的所有功能。您必须知道这些功能,因为它们会在服务世界中导致意外的行为。主要功能之一是应用程序回收,包括应用程序域回收和进程回收。通过 IIS 管理控制台,可以在希望发生回收时配置不同的规则。可以为内存、时间和请求处理数量设置某些阈值,如图 5-10 所示。当 IIS 回收工作进程时,还将回收工作进程中的所有应用程序域。通常,当基于 ASP.NET 的 Web 应用程序中的关键文件更改时,应用程序域也将回收。例如,在更改 Web.config 文件或 Bin 文件夹中的程序集时,将发生该操作。
图 5-10. 应用程序池回收设置
注意 此处描述的进程回收包括 Windows Server 2003 中的回收。若要在 Windows XP 和 IIS 5.1 中启用进程回收,可以从 Microsoft 网站下载 IIS 5.0 进程回收工具。进程回收工具作为服务在运行 IIS 5.0 或 IIS 5.1 的计算机上运行。
修改 .svc 文件之后,还将回收应用程序域。承载环境将尝试按时正常关闭所有 WCF 服务的打开连接。如果由于某种原因使服务无法按时关闭,系统将强制中止它们。通过 HostingEnvironmentSettings 配置设置,可以影响回收的行为,如列表 5-8 所示。idleTimeout 设置确定应用程序域在回收前的空闲时间长度(秒)。shutdowntimeout 设置确定正常关闭应用程序前的时间长度(秒)。发生此超时后,它将强制应用程序关闭。
列表 5-8. 包含回收设置的 hostingenvironment 节的 Web.config
<system.web> <hostingEnvironment idleTimeout="20" shutdownTimeout="30"/> </system.web>
使用 WCF 会话时,理解这些回收功能很重要。通常,在安全和可靠消息方案中有这种情况,本书的第 6 章和第 8 章将对此进行介绍。默认情况下,WCF 将会话状态存储在内存中。这是与 ASP.NET 会话状态不同的实现,它没有需要切换到持久会话状态存储的配置。但在安全和可靠消息方案中,您可以并且应当受益于 ASP.NET 实现。通过使用 WCF 的 ASP.NET 兼容性功能,可以获得 ASP.NET 会话状态的 SQL Server 和状态服务器实现,以支持企业可用的方案。在下一节中,将介绍如何受益于 WCF ASP.NET 兼容性模式。
如果在负载平衡或者甚至 Web 园的环境中承载 WCF 服务,并且在该环境中后续的会话请求可以被此环境内的不同宿主或进程处理,则需要对会话状态进行进程外持久存储。最新的 WCF 不支持会话状态的持久存储。相反,WCF 将它的所有会话状态存储在内存中。如果在 IIS 中承载 WCF 服务,最后可以使用回收方案,上一节对此进行了描述。WCF 依赖于会话状态的 ASP.NET 实现,而不是为会话全部再次建立持久存储。此方式有一个严重的限制:使服务仅限于 HTTP。
ASP.NET 会话状态不是受 ASP.NET 兼容性模式支持的唯一功能。它还支持诸如 HttpContext、globalization 和模拟等功能,就像用于 ASP.NET Web 服务 (ASMX) 一样。有关启用进程外会话状态的特定于 ASP.NET 的功能,请参考 MSDN 帮助。
若要查看 ASP.NET 兼容性模式的限制,必须用 AspNetCompatibilityRequirements 属性显式标记服务,如列表 5-9 所示。
列表 5-9. AspNetCompatibilityRequirements 属性
namespace QuickReturns.StockTrading.ExchangeService { [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ReturnUnknownExceptionsAsFaults=true)] [AspNetCompatibilityRequirements( RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)] public class TradeService : ITradeService { ... } }
AspNetCompatibilityRequirementsMode 属性有以下允许值。
表 5-1. AspNetCompatibilityRequirementsMode 属性的值 | |
值 | 说明 |
NotAllowed |
指示服务可能“永远不能”运行在 ASP.NET 兼容性模式中。如果在方案中服务实现不能在 ASP.NET 兼容性模式中工作(例如,在服务不是为 HTTP 生成的方案中),则必须设置此项。 |
Allowed |
指示服务“可能”运行在 ASP.NET 兼容性模式中。只有当您知道服务可能在此模式中工作时,才能选取此值。 |
Required |
指示服务“必须”运行在 ASP.NET 兼容性模式中。如果服务需要进行持久会话存储,请选取此值。 |
选择“Required”选项时,WCF 将验证服务的所有受支持的端点都是 HTTP 端点,并且,如果它们不是,则会在 ServiceHost 初始化期间产生异常。除了 AspNetCompatibilityRequirements 属性以外,还必须设置 aspNetCompatibilityEnabled,如列表 5-10 所示。
列表 5-10. 启用了 ASP.NET 兼容性的配置
<?xml version="1.0"?> <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0"> <system.serviceModel> <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/> <services> ... </services> <behaviors> ... </behaviors> </system.serviceModel> </configuration>
注意 本书附带的示例代码包含在 ExchangeServiceInline.svc 文件中承载的 TradeService 服务,它被配置为在 ASP.NET 兼容性模式中运行。您可以在第 5 章的解决方案文件(请参考示例代码下载链接)中找到它。
Windows 2000 附带的 IIS 5.0 拆分了 IIS 进程模型,并引入了工作进程。此更改的主要原因是为了隔绝应用程序,以便 IIS 可以承载相互依赖较少的不同应用程序。IIS 5.0 与 Windows 2000 一起发布,而 IIS 5.1 与 Windows XP 一起发布。WCF 不支持在带 IIS 5.0 的 Windows 2000 上承载服务;因此,我们将只详细考查 IIS 5.1。IIS 5.1 受支持,但它有仅一个站点的限制,并且每个应用程序都运行在一个称为 aspnet_wp.exe 的工作进程中。IIS 5.1 对于开发 ASP.NET 网站和 WCF 服务是很好的版本。它不是为企业使用而准备的,因为它有连接限制,并且只运行在早期的 Windows 版本或 Windows XP 的客户端版本上。在本章中,我们将讨论 IIS 5.1。
在图 5-11 中,可以看到 IIS 5.1 的进程模型。体系结构被拆分成两部分。左侧的 W3svc.exe 承载 HTTP 侦听器、启动工作进程并管理配置。另一侧的工作进程则使 IIS 5.1 能够承载托管的 .NET 应用程序,在这里,ASPNET_ISAPI.dll 负责创建托管 .NET 应用程序域。请注意,在 Windows XP 上,W3svc.exe Windows 服务与 SMTP 和 FTP 服务一起承载在 SvcHost.exe 进程中。
图 5-11. IIS 5.1 进程模型体系结构
注意 不必有 IIS 即可运行 ASP.NET 和 WCF 服务。例如,可以使用 Visual Studio 2005 附带的 ASP.NET 开发 Web 服务器。在发布 Windows XP 时,Visual Studio 还没有此功能。必须使用 IIS 5.1 才能在 Windows XP 上开发 Web 应用程序。
到 Windows Server 2003 时,Microsoft 引入了内核模式 HTTP 堆栈,称为 HTTP.SYS。HTTP.SYS 通过 W3svc.exe 插入 IIS 6.0 体系结构中。W3svc.exe 是用户模式组件,用于桥接内核模式的 HTTP.SYS 实现,并将它连接到在 IIS 5.1 中已有的进程和配置管理系统。到 IIS 6.0 时,应用程序池的概念更加普及。尽管在 IIS 5.1 中只有托管 (ASP.NET) 应用程序可以承载在单独的应用程序池中,但在 IIS 6.0 中所有类型的应用程序都可以承载在单独的应用程序池中。ASPNET_ISAPI.dll 仍然负责启动在托管 ASP.NET 世界中的应用程序域。图 5-12 说明了 IIS 6.0 中的进程模型。
图 5-12. 在 IIS 6.0 中承载的 IIS 6.0 进程模型体系结构
下面的详细步骤说明如何在 IIS 6.0 中承载 .NET 3.0 WCF 服务。我们将使用在前面描述的示例在 IIS 6.0 中进行承载。
1. |
请在示例代码文件夹中打开包含 ExchangeServiceIISHost 文件夹的文件夹。 |
2. |
下一步是在 IIS 中为该文件夹创建虚拟目录。可以通过 IIS 管理器导航;但为简单起见,只需右键单击此文件夹,然后选择“属性”。 |
3. |
一旦出现属性对话框,请单击“Web 共享”选项卡。只需单击“共享此文件夹”单选按钮,将显示“编辑别名”。将别名从“ExchangeServiceIISHost”重命名为“ExchangeService”。可以启用“目录浏览”以使您更容易查看并单击网站中的项目。通常,这是只用于开发的设置;关于 Web 共享设置,请参见图 5-13。 警告 此设置允许用户浏览站点中的所有文件,就像使用 Windows 资源管理器一样。虽然是好功能,但请在实际运行环境中使用时一定要小心。 |
图 5-13. Web 共享“编辑别名”对话框
1. |
此时,只需单击“确定”几次,即可退出对话框。现在,应当可以通过以下网址 http://localhost/ExchangeService 访问站点。但是,我们仍然必须检查为此站点设置的 ASP.NET 的版本。如果只安装了 .NET 2.0(就是说从未安装 .NET 1.1),则应当不用做其他操作,但检查一下是有好处的。因此,请打开 IIS 管理器(“开始” | “控制面板” | “管理工具” | “Internet 信息服务”)。一旦看到“属性”对话框,请单击“ASP.NET”选项卡,然后使用下拉框将 ASP.NET 的版本切换到 .NET 3.0(受支持的版本)2.0.50727(RTM 版本)。 |
2. |
对于我们的示例,有一个额外的步骤,用于使“匿名”请求能够访问资源。匿名请求是指没有与 HTTP 请求关联的标识或 Windows 主体的任何请求。 |
单击“目录安全”选项卡,然后在对话框的“匿名访问和身份验证控制”区域下单击“编辑”。确保选项“匿名访问”被启用。这将允许我们的示例运行,而不会涉及如何为请求提供身份验证凭据。
此时,如果使用 Internet Explorer 浏览到 http://localhost/ExchangeService 位置,将能够看到一个目录列表(只要设置与上一图中相似)。如果单击 Service.svc,将转到由 *.svc 扩展的 System.ServiceModel.Activiation.HttpHandler 生成的默认帮助屏幕。
此时,将执行与在客户端应用程序中相同的步骤,要么直接通过使用 Svcutil.exe 实用程序生成代理类,要么右键单击项目并通过“添加服务”加载项功能生成代理,本章后面的“使用 WCF 服务”一节将对此进行介绍。
此示例附带的解决方案有完整的控制台客户端,它可以调用我们刚创建的 WCF 服务。
IIS 7.0 推动了 Web 服务器领域中的又一重大演进。可以在图 5-14 中看到两个重要改变。第一,现在特定于协议的侦听器适配器支持所有四种 WCF 传输,而不是仅限于 IIS 6.0 中的 HTTP 传输。此外,出现了称为 Windows 激活服务 (WAS) 的新操作系统服务。W3svc.exe 和 WAS 都运行在称为 SvcHost.exe 的操作系统宿主的内部。为了能够将 IIS 6.0 进程模型的强大功能与 WCF 结合使用,则需要进行这些更改。您可能会问“为什么?”好的,WCF 服务也工作在 IIS 5.1 和 IIS 6.0 中,那么,通过在 IIS 中推广进程模型和激活功能可以获得什么好处呢?很简单:通过推广激活概念使它与协议无关,而不是绑定到 HTTP,可以将平台的激活功能扩展到几乎所有传输类型。
图 5-14. IIS 7.0 进程模型体系结构
在新发布的 Windows Vista 和 Windows Server 2007 中,Microsoft 转移了 IIS 的进程管理和配置功能,并使它在操作系统内部普遍可用。这使建立于该模型上的任何应用程序都能基于传入的消息使用运行时激活和生成工作进程的功能。
HTTP、TCP/IP、命名管道和 MSMQ 的特定于协议的侦听器适配器运行于它们自己的进程内部,并将特定传输桥接到 WAS。侦听器适配器要求 WAS 激活工作进程,然后将实际通信转交给这些工作进程内部的特定协议处理程序。因此,WAS 现在拥有 W3svc.exe 中具备的所有功能。通过将此责任拆分成多个单独的进程,其他三种传输也受益于过去内置在 IIS 6.0 中但只用于 HTTP 的进程模型和激活功能。总而言之,使用 IIS 7.0 可以跨越 IIS 中提供的任何传输类型承载任何 WCF 服务。在下一节中,将介绍 WAS 激活的工作原理,以及如果希望在 Windows Vista 或 Windows Server 2007 上的 IIS 7.0 和 WAS 内部承载 WCF 服务时必须注意的事项。
若要在 IIS 7.0 内部承载本书中使用的 TradeService,您要做的就是配置 IIS,并将为 IIS 6.0 创建的 .svc 文件放在您将创建的站点中。利用以下步骤您将能够在 Windows Server 2007 上配置 IIS 7.0、WAS 和 .NET Framework 3.0,并使 TradeService 运行在 IIS 7.0 内部:
1. |
启动服务器管理器(位于“管理工具”中)。 |
2. |
向服务器添加 Web 服务器 (IIS) 角色。 |
3. |
注意,安装 Web 服务器时将自动添加 WAS。 |
4. |
在 IIS 的“详细设置”屏幕上,选择“ASP.NET”,并在“安全”下选择“基本和 Windows 身份验证”。让其余选项保持默认设置。 这将安装 IIS 和 WAS。 |
5. |
默认情况下,Windows Server 2007 不附带安装 .NET Framework 3.0。若要安装 .NET Framework 3.0,请打开“添加功能向导”(“控制面板” | “程序” | “Windows 功能”)。 |
6. |
单击“添加功能”,并选择“NET Framework 3.0”(如果要用 WCF MSMQ 传输进行实验)。还应选择“MSMQ”。 |
现在,就可以准备在 IIS 7.0 上运行 WCF 服务了。下一步是在 IIS 中创建在其中运行服务的应用程序。这需要使用 Internet 信息服务 (IIS) 管理器。可以在“开始”菜单的“管理工具”中找到 IIS 管理工具。然后,导航到您的服务器和您的网站,最后找到默认网站。右键单击默认网站,并选择“创建应用程序”,如图 5-15 所示。
图 5-15. 在 IIS 管理器中新建应用程序
现在,需要指定本地计算机上的一个文件夹,用于承载应用程序的 .svc 文件。如图 5-16 所示,可以为应用程序指定一个用于访问服务的名称 (http://localhost/<chosenname>) 和驻留文件的文件夹,然后选择应用程序池。
图 5-16. 在 IIS 管理器中为新应用程序设置属性
如果正确完成所有操作,则可以通过 IIS 7.0 访问您的服务。通过导航到新创建的应用程序可以测试实际效果,例如:
http://localhost:8080/QuickReturns/Exchange.svc/ExchangeService
WAS 使您能够承载任何 WCF 服务,以便在 IIS 模型内部支持任何传输。WAS 接管了最初 IIS 6.0 中 W3svc.exe Windows 服务的创建工作进程和提供配置的工作(并运行在 Inetinfo.exe 进程的内部)。WAS 和 IIS 现在共享用于定义站点、应用程序、应用程序池和虚拟目录的配置存储区。在这一节中,我们将介绍用 WAS 激活的过程,如图 5-17 所示。
默认情况下,如果没有向新启动的服务器发出请求,Windows 将运行五个服务(如果启用了所有协议)。下面是这些 Windows 服务:
• | WAS |
• | 万维网发布服务(承载侦听器适配器) |
• | NET.TCP 侦听器适配器 |
• | NET.PIPE 侦听器适配器 |
• | NET.MSMQ 侦听器适配器 |
图 5-17. 用 WAS 为 HTTP 请求激活工作进程
侦听器适配器启动时,它们将向 WAS 进行注册,并接收对应其特定协议的 WAS/IIS 配置。由此,侦听器适配器可以感知它们应当支持的站点和应用程序。然后,每个侦听器适配器开始侦听由配置提供的合适端口,这样,它就可以将进入的请求分派给合适的应用程序。
一旦第一个请求进入,侦听器适配器就将调用 WAS 以激活工作进程,其中包括作为请求目标的特定应用程序的托管 .NET 应用程序域。
然后,请求被递交给工作进程内部的所谓应用程序域协议处理程序,以处理请求并将响应返回给客户端。它不关心请求是 WCF 服务请求、ASP.NET 请求还是对 IIS 7.0 的任何其他请求。创建激活进程是为了使工作进程能够在请求到来时启动。
为了在应用程序域内部启动 WCF ServiceHost,应用程序域协议处理程序必须调用称为 EnsureServiceAvailable 的静态方法。该方法与协议无关,并且将激活整个服务,包括所有端点和传输(而不仅是调用该方法的协议处理程序的传输)。
注意 在侦听器适配器和协议处理程序的内部,尤其对于 HTTP 和 TCP 协议发生了一些不可思议的事情。在单独进程中所承载的侦听器适配器内部,套接字被打开。然后,当第一个请求到来时,实际上套接字将被从侦听器适配器转交给应用程序域协议处理程序,以便能够处理第一个请求和任何后续请求!
本章前一节介绍了用于承载服务的不同方案。此外,还介绍了哪种承载方案可以满足哪些业务要求(或非功能性要求)。通常,可以采用“为什么不是 IIS?”的方法。这是什么意思呢?IIS 在功能方面提供了最佳选择,尤其是在服务要公开多个系统所依赖的关键业务功能的情形下。如果选择 IIS,就必须选择使用 IIS 6.0 还是 IIS 7.0,由于新的激活功能,显然应当选择后者。在需要进程间通信的情形下,WinForms 和控制台应用程序都是可行方案。Windows 服务本质上只是 IIS 的替代方案,并且通常在建立服务器产品或需要对服务的激活和寿命期进行高级控制时使用它。
在下一节中,我们将介绍为使用服务而提供的选项,以及承载方案对使用者端意味着什么。
在前一节中,我们介绍了不同的承载方案。而所选的承载方案会影响使用者端。使用 WCF 服务可以有多种方式。如果客户端正在使用 WCF,则生产效率将非常高,因为 WCF 附带的工具可以生成用于调用 WCF 服务的代理类。WCF 主要通过 SvcUtil.exe 来提供标准和工具支持,SvcUtil.exe 将作为主要的元数据解释工具。它与 WCF Framework 利用反射询问具有合适属性的类型这一功能结合在一起,使生成和使用 WCF Framework 与现有框架相比,复杂性更低。此外,Visual Studio 2005 带有易用的功能,可以向项目添加服务引用,并可无缝地自动生成代理类。
实际上,您可以有以下选择:
• | 从服务检索 WSDL,并手动制作代理来调用服务。这是客户端没有 WCF 时的典型方案。关于此方案,请参考第 13 章。 |
• | 使用 Visual Studio 2005 的“添加服务引用”功能,并让它生成要在客户端上使用的代理。 |
• | 使用 SvcUtil.exe 工具生成代理类。 |
在下面几节中,我们将介绍后面两个选项:Visual Studio 2005 和 SvcUtil.exe。
服务代理使您能够以面向对象的方式使用服务。代理类对服务所使用的通信模型进行抽象,这样,客户端开发人员不会直接意识到他正在与(远程)服务对话。这就像在调用本地代码一样。代理类可实现服务的服务接口,从而使您能够调用服务接口上的方法,就好像它们是本地方法。代理是为服务接口中使用的任何自定义类型而生成的。列表 5-11 包含 QuickReturns Ltd. 示例中为 TradeService 服务生成的代理的片段。它演示了在客户端有一个可用 Quote 映射到服务器端上的 Quote 对象,尽管它们是不同的类。Quote 对象按照合同进行序列化,以便它在服务端可以序列化为服务端版本的 Quote 数据合同。此外,可以看到 GetQuote 和 PlaceQuote 方法调用一个基类,而该基类最后将以所配置的传输方式跨服务边界进行调用。
列表 5-11. 为 TradeService 服务生成的示例代理
namespace SimpleClientWithProxy.ExchangeService { [DataContract()] public partial class Quote : object, IExtensibleDataObject { // 省略了打印代码中的 Quote 数据成员,见示例代码 } } [GeneratedCode("System.ServiceModel", "3.0.0.0")] [ServiceContract()] public interface ITradeService { [ OperationContract(Action = "http://tempuri.org/ITradeService/GetQuote", ReplyAction = "http://tempuri.org/ITradeService/GetQuoteResponse")] Quote GetQuote(string ticker); [ OperationContract(Action = "http://tempuri.org/ITradeService/PublishQuote", ReplyAction = "http://tempuri.org/ITradeService/PublishQuoteResponse")] void PublishQuote(Quote quote); } [GeneratedCode("System.ServiceModel", "3.0.0.0")] public interface ITradeServiceChannel : ITradeService, IClientChannel { } [GeneratedCode("System.ServiceModel", "3.0.0.0")] public partial class TradeServiceClient : ClientBase<ITradeService>, ITradeService { // 省略了打印代码中的一些构造函数,见示例代码 public SimpleClientWithProxy.ExchangeService.Quote GetQuote(string ticker) { return base.Channel.GetQuote(ticker); } public void PublishQuote( SimpleClientWithProxy.ExchangeService.Quote quote) { base.Channel.PublishQuote(quote); } }
与创建 ASP.NET 代理相似,如果在 IDE 中右键单击项目,可以看到三个用于添加引用的选项,如图 5-18 所示。
图 5-18. 添加对 WCF 服务的引用
您要查找的选项是“添加服务引用”。此菜单选项是 SvcUtil.exe 实用程序周围的包装(下一节将对此进行介绍),它实际上将产生具有所需参数的进程。一旦选择了“添加服务引用”,就将看到在图 5-19 中显示的对话框。
图 5-19. “添加服务引用”对话框
一旦在对话框中单击“确定”,该加载项将产生 SvcUtil.exe,并生成需要的代理类和必需的配置文件(或修改它),并将所需引用添加到项目中。现在,项目的引用将列出 WCF 程序集。
注意 要使该操作有效,必须运行 Windows ServiceHost,或更改 URL 以指向 IIS 中承载的任何服务(使 URL 指向任何 .svc 文件)。
现在,即可开始在服务层中安排第一个服务调用。示例解决方案文件按以下方式进行了修改,以帮助您查看代码:
• | 解决方案上的“设置启动项目”已选中多个项目。 |
• | ExchangeServiceIISHost Web 项目的“使用动态端口”已设置为 False,并且“端口号”使用硬编码设置。 |
需要将对象的简短说明添加到项目中。在 SvcUtil.exe(“添加服务引用”)调用期间,在项目中自动添加了下面的项和引用。其中一些只是为了帮助 Visual Studio 集成;其他则是通过代理直接使用服务所必需的。
• | 服务引用:在此文件夹中,我们添加了两项。第一,“映射”文件为通过 Visual Studio 加载项生成和重新生成代理提供支持。第二,ExchangeService.cs 代表具体的代理类实现,它利用命名空间 System.ServiceModel 提供简单的集成类。 |
• | 配置:第二项是 App.config 文件。App.config 文件(在 Visual Studio 构建过程中将自动重命名为“<程序集名称>.config”)提供运行时 WCF 配置参数。如果看一看此文件的内部,将发现大量设置,其中很多是默认的或多余的。常见做法是,在生成该文件后使用 WCF SvcConfigEditor.exe 编辑器实用程序管理该文件。此实用程序位于 Windows SDK Bin 目录下。还可以在“Visual Studio 2005 工具”菜单中找到它。图 5-20 显示了该工具的实现。 |
图 5-20. SvcConfigEditor.exe
从图 5-20 中的“SvcConfigEditor.exe”屏幕上可以看到,通过配置可以管理数量巨大的详细属性。这是 WCF 的最强大的优势之一:能够对具体实现的很多方面进行控制,而不会影响核心服务实现。服务实现不需要更改即可从基于 HTTP 的协议迁移到另一个面向消息的协议这一概念就是一个示例。若要获得有关该工具的功能的详细信息,请参考本书的第 3 章、第 6 章或 MSDN 帮助。
一种替代方法是直接利用 SvcUtil.exe 实用程序,而不是 Visual Studio 加载项。在从 Visual Studio 中直接执行时,Visual Studio 加载项将再次带参数调用 SvcUtil.exe 以生成代理。通过查看“输出”窗口,并在下拉列表中将“显示输出”设置为“服务引用”,可以看到命令行和该命令的结果。
若要手动生成,可通过选择“开始” | “所有程序” | “Microsoft Windows SDK” | “CMD”,以选择 CMD 窗口。此命令提示符很有用,因为它的路径被设置为 SDK 工具和实用工具所在的二进制目录。
您将使用 SvcUtil.exe 命令行工具生成可在 SimpleClientWithProxy 项目中使用的两个输出。但是,本章附带的示例代码使用了上一节介绍的“添加服务引用”方法。此处介绍的步骤解释了如何生成与“添加服务引用”相同的输出。它生成的输出文件是客户端代理源代码文件和应用程序配置文件。然后,这些文件将合并到客户端项目中。SvcUtil.exe 可以生成这二者。在此示例中,以下命令(它只有一行,尽管此处显示多行)将产生代理类和配置文件:
列表 5-12. 用于产生代理类和配置文件的命令
svcutil /config:app.config /out:"ExchangeService.cs" /language:csharp /n:*, SimpleClientWithProxy.ExchangeService "http://localhost/ExchangeService/? ExchangeService.svc"
警告 要让此操作有效,需要一个正在运行的 Windows ServiceHost 版本,或者必须更改 URL 以指向 IIS 中承载的任何服务(使 URL 指向本章讨论的任何 .svc 文件)。此外,服务需要 metadataexchange 端点,第 3 章对此进行了介绍。本章附带的代码配置了 metadataexchange 端点,但在本章中它不在内嵌代码内!
命令有很好的自解释功能。/n 开关表明生成的代理类应当属于哪个命名空间。最后一个参数是可以在其上找到架构信息的服务端点的 URL。注意,?wsdl 可以替换为 ?mex,因为 SvcUtil.exe 同时支持两种发现方法。通过从命令提示符执行 svcutil.exe /?,可以获得进一步帮助。
下一步是获得输出文件 ExchangeService.cs 和 App.config,并将它们合并到项目中。通过从 Visual Studio 2005 中的“项目”菜单选择“添加现有项”,可以将第一个文件 ExchangeService.cs 直接添加到项目中。
第二个文件必须作为应用程序配置 (App.config) 文件添加到项目中。如果项目还没有 App.config 文件,则可以从“项目”菜单中再次选择“添加现有项”以添加该文件。如果已有现成的 App.config,则必须合并 system.serviceModel 部分,以确保具备所有适当的子元素。
在了解了有关承载的可选方案的所有内容后,您将能够构建 WCF 应用程序,并在任何需要的地方承载它们。此外,您还能够解释在最新可用环境(Windows Vista 或 Windows Server 2007 上的 IIS 7.0 与 WAS)中进行承载的好处。
作者简介
Chris Peiris 是应用程序集成方面的热心作者。他在澳大利亚的 Avanade 公司担任解决方案设计师。他经常在有关 Microsoft 技术的专业开发人员会议上发言。Chris 为包括 15Seconds、ASPToday、Wrox (Apress) 和 Developer Exchange (DevX) 在内的各种在线刊物编写了很多文章、评论和专栏。他还与他人共同编写了很多有关 WCF、Web 服务、UDDI、C#、IIS、Java 和安全方面的书籍。Chris 目前主要关注 WCF、WinFX、IBM Message Broker、BizTalk 和其他 EAI 实现。若要查看 Chris 的完整作品列表和详细联系信息,请访问 http://www.chrispeiris.com/。
Dennis Mulder 于 1997 年开始他的职业生涯,专注于 Microsoft 技术。在 2004 年 8 月,他开始服务于 Avanade,这是一家 Microsoft 和 Accenture 的合资公司。目前,他主要关注 Microsoft 平台的几个领域,具体包括面向服务的领域、集成和软件工厂。作为在荷兰的顾问,Dennis 通过利用 Microsoft 平台的强大功能与企业客户共同合作解决其问题。Dennis 经常在荷兰 Microsoft 会议和用户组中发言,在 2006 年初,他就已经成为 INETA 的发言人。可以通过 [email protected] 或他的博客 http://www.dennismulder.net/ 与 Dennis 联系。
Avanade 是全球 IT 咨询公司,致力于使用 Microsoft 平台帮助企业取得盈利增长。通过利用拓展 Microsoft 技术的成熟解决方案,Avanade 帮助企业增加收入、降低成本并对创新技术进行再投资,以获得竞争优势。我们的顾问通过汇聚我们全球雇员的洞察力、创新和才干,按照每个客户的要求、时间线和预算提供服务。有关其他信息,可以访问 http://www.avanade.com/。