WCF – 快速指南
WCF – 快速指南
WCF – 概述
WCF 代表 Windows 通信基础。WCF 的基本特征是互操作性。它是 Microsoft 用于构建面向服务的应用程序的最新技术之一。基于基于消息的通信的概念,其中统一表示 HTTP 请求,WCF 使具有统一的 API 成为可能,而无需考虑不同的传输机制。
WCF 于 2006 年作为 Windows Vista 的 .NET 框架的一部分首次发布,然后进行了多次更新。WCF 4.5 是现在广泛使用的最新版本。
WCF 应用程序由三个组件组成 –
- WCF服务,
- WCF 服务主机,以及
- WCF 服务客户端。
WCF 平台也称为服务模型。
WCF的基本概念
信息
这是一个通信单元,由除身体以外的几个部分组成。客户端和服务之间的所有类型的通信都会发送和接收消息实例。
端点
它定义了要发送或接收消息的地址。它还指定了描述消息将如何发送以及定义消息集的通信机制。端点的结构包括以下部分 –
地址
地址指定接收消息的确切位置,并指定为统一资源标识符 (URI)。它表示为 scheme://domain[:port]/[path]。看看下面提到的地址 –
net.tcp://localhost:9000/ServiceA
这里,’net.tcp’ 是 TCP 协议的方案。域是“localhost”,可以是机器或网络域的名称,路径是“ServiceA”。
捆绑
它定义了端点通信的方式。它由一些绑定元素组成,这些元素构成了通信的基础设施。例如,绑定声明用于传输的协议(如 TCP、HTTP 等)、消息编码格式以及与安全性和可靠性相关的协议。
合同
它是一组操作,用于指定端点向客户端公开的功能。它通常由一个接口名称组成。
托管
从 WCF 的角度来看,托管是指 WCF 服务托管,它可以通过许多可用选项来完成,例如自托管、IIS 托管和 WAS 托管。
元数据
这是 WCF 的一个重要概念,因为它促进了客户端应用程序和 WCF 服务之间的轻松交互。通常,WCF 服务的元数据在启用时自动生成,这是通过检查服务及其端点来完成的。
WCF客户端
为以方法的形式公开服务操作而创建的客户端应用程序称为 WCF 客户端。这可以由任何应用程序托管,甚至是服务托管的应用程序。
渠道
通道是客户端与服务通信的媒介。不同类型的通道堆叠在一起,称为通道堆栈。
肥皂
尽管被称为“简单对象访问协议”,但 SOAP 并不是一种传输协议;相反,它是一个包含标题和正文部分的 XML 文档。
WCF的优势
-
它可以与其他服务互操作。这与 .NET Remoting 形成鲜明对比,在后者中客户端和服务都必须具有 .Net。
-
与 ASMX(活动服务器方法)Web 服务相比,WCF 服务提供增强的可靠性和安全性。
-
在 WCF 中实现安全模型和绑定更改不需要对编码进行重大更改。只需更改一些配置即可满足约束条件。
-
WCF 具有内置的日志记录机制,而在其他技术中,必须进行必要的编码。
-
WCF 集成了 AJAX 并支持 JSON(JavaScript 对象表示法)。
-
它为即将到来的 Web 服务标准提供可扩展性和支持。
-
它有一个非常强大的默认安全机制。
WCF – 与 Web 服务
WCF 和下面列出的 Web 服务之间存在一些主要差异。
-
属性– WCF 服务由 ServiceContract 和 OperationContract 属性定义,而 Web 服务由 WebService 和 WebMethod 属性定义。
-
协议– WCF 支持一系列协议,即 HTTP、命名管道、TCP 和 MSMQ,而 Web 服务仅支持 HTTP 协议。
-
托管机制– WCF 托管有各种激活机制,即 IIS(Internet 信息服务)、WAS(Windows 激活服务)、自托管和 Windows 服务,但 Web 服务仅由 IIS 托管。
-
服务– WCF 支持强大的安全性、可信赖的消息传递、事务和互操作性,而 Web 服务仅支持安全服务。
-
Serializer – WCF 通过使用 System.Runtime.Serialization 支持 DataContract 序列化程序,而 Web 服务通过使用 System.Xml.Serialization 支持 XML 序列化程序。
-
工具– ServiceMetadata 工具 (svcutil.exe) 用于为 WCF 服务生成客户端,而 WSDL.EXE 工具用于为 Web 服务生成相同的客户端。
-
异常处理– 在 WCF 中,通过使用 FaultContract 以更好的方式处理未处理的异常。它们不会像在 Web 服务中那样作为 SOAP 错误返回给客户端。
-
哈希表– 可以在 WCF 中序列化哈希表,但在 Web 服务中并非如此。
-
绑定– WCF 支持多种类型的绑定,如 BasicHttpBinding、WSDualHttpBinding、WSHttpBinding 等,而 Web 服务仅支持 SOAP 或 XML。
-
多线程– WCF 通过使用 ServiceBehavior 类支持多线程,而这在 Web 服务中不受支持。
-
Duplex Service Operations – 除了支持单向和请求-响应服务操作之外,WCF 还支持双工服务操作,而 Web 服务不支持双工服务操作。
WCF – 开发者工具
开发 WCF 服务应用程序,主要有两种工具——Microsoft Visual Studio 和 CodePlex。Microsoft Visual Studio 是一个完整的开发工具包,是开发大量不同应用程序(如 ASP.NET Web 应用程序、桌面应用程序、移动应用程序等)所必需的。
Microsoft Visual Studio 使用 .NET 框架功能。另一方面,CodePlex 是微软的一个开源项目托管站点,它提供了几个用于 WCF 服务应用程序开发的免费工具。
微软视觉工作室
Microsoft Visual Studio 有很多版本,最初它 (Visual Studio 2005) 并不是 WCF 开发的热心支持者。目前,Visual Studio 2008 是唯一可用于开发 WCF 服务应用程序的 Microsoft IDE。
如今,最新版本的Microsoft Visual Studio 2010 也是开发WCF 服务应用程序的首选工具。Visual Studio 中还有一个现成的模板,用于开发 WCF 服务应用程序。
选择这样的模板会导致添加文件用于以下目的 –
- 服务合同
- 服务实现
- 服务配置
必要的属性会自动添加,并且 Microsoft Visual Studio 甚至无需编写任何代码即可创建一个简单的“Hello World”服务。
代码集
CodePlex 由 Microsoft 于 2006 年 6 月推出,从那时起,它已被世界各地的大量开发人员用于成功创建 .NET 项目。CodePlex 提供的一些用于开发 WCF 服务应用程序的工具如下 –
-
wscf.blue – 这是一个 Microsoft Visual Studio 加载项,也是“合同优先”的开发工具集,可促进 WCF 服务操作的定义,并相应地生成代码框架。一个重要的链接是 – https://wscfblue.codeplex.com
-
WCFProxyGenerator – 这也是一个 Microsoft Visual Studio 插件。该工具用于扩展客户端生成并提供额外的错误处理。有关此特定开发工具的更多信息,请访问https://wcfproxygenerator.codeplex.com
-
WCFMock – WCF 服务的测试可能是一项复杂的任务,该开发工具通过其有用的类为 WCF 服务的单元测试提供了方便的解决方案。有关此工具的更多信息,请访问https://wcfmock.codeplex.com
另一个以简单方式开发 WCF 服务应用程序的免费工具是 WCFStorm。它的 LITE 版本提供了许多引人注目的功能,用于动态调用和测试 WCF 服务、编辑服务绑定、修改 WCF URL 端点等。
WCF – 架构
WCF 具有分层架构,可为开发各种分布式应用程序提供充分的支持。下面详细解释该架构。
合同
合约层紧邻应用层,包含类似于现实世界合约的信息,该合约指定服务的操作以及它将提供的可访问信息的类型。合同基本上分为以下简要讨论的四种类型 –
-
服务合同– 该合同向客户端以及外部世界提供有关端点产品以及通信过程中使用的协议的信息。
-
数据合同– 服务交换的数据由数据合同定义。客户端和服务都必须同意数据合同。
-
消息合同– 数据合同由消息合同控制。它主要对 SOAP 消息参数的类型格式进行定制。这里需要说明的是,WCF 使用 SOAP 格式进行通信。SOAP 代表简单对象访问协议。
-
Policy and Binding – 与服务通信有一定的先决条件,这些条件由策略和绑定合同定义。客户需要遵守此合同。
服务运行时
服务运行时层就在契约层之下。它指定了在运行时发生的各种服务行为。有许多类型的行为可以进行配置并归入服务运行时。
-
节流行为– 管理处理的消息数量。
-
错误行为– 定义任何内部服务错误发生的结果。
-
元数据行为– 指定元数据对外界的可用性。
-
Instance Behavior – 定义需要创建的实例数以使它们可供客户端使用。
-
交易行为– 在发生任何故障时启用交易状态的更改。
-
Dispatch Behavior – 控制 WCF 基础结构处理消息的方式。
-
并发行为– 控制在客户端 – 服务器通信期间并行运行的功能。
-
参数过滤– 具有在调用之前验证方法参数的过程。
消息传递
该层由若干个通道组成,主要处理两个端点之间要通信的消息内容。一组通道形成通道堆栈,构成通道堆栈的两种主要通道类型如下 –
-
传输通道– 这些通道位于堆栈的底部,负责使用 HTTP、TCP、点对点、命名管道和 MSMQ 等传输协议发送和接收消息。
-
协议通道– 出现在堆栈的顶部,这些通道也称为分层通道,通过修改消息来实现线级协议。
激活和托管
WCF 架构的最后一层是服务实际托管或可以执行以便客户端轻松访问的地方。这是通过下面简要讨论的各种机制来完成的。
-
IIS – IIS 代表 Internet 信息服务。它通过服务使用 HTTP 协议提供了无数的优势。这里不需要有激活服务码的主机码;相反,服务代码会自动激活。
-
Windows 激活服务– 这通常称为 WAS,随 IIS 7.0 一起提供。通过使用 TCP 或 Namedpipe 协议,基于 HTTP 和非 HTTP 的通信在这里都是可能的。
-
自托管– 这是一种 WCF 服务作为控制台应用程序自托管的机制。这种机制在选择所需协议和设置自己的寻址方案方面提供了惊人的灵活性。
-
Windows 服务– 使用此机制托管 WCF 服务是有利的,因为由于没有运行时激活,这些服务将保持激活状态并可供客户端访问。
WCF – 创建 WCF 服务
创建 WCF 服务是使用 Microsoft Visual Studio 2012 的一项简单任务。下面给出了创建 WCF 服务的分步方法以及所有必需的编码,以便更好地理解该概念。
- 启动 Visual Studio 2012。
- 单击新项目,然后在 Visual C# 选项卡中,选择 WCF 选项。
创建了一个 WCF 服务,它执行基本的算术运算,如加法、减法、乘法和除法。主要代码在两个不同的文件中——一个接口和一个类。
WCF 包含一个或多个接口及其实现的类。
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; namespace WcfServiceLibrary1 { // NOTE: You can use the "Rename" command on the "Refactor" menu to // change the interface name "IService1" in both code and config file // together. [ServiceContract] Public interface IService1 { [OperationContract] int sum(int num1, int num2); [OperationContract] int Subtract(int num1, int num2); [OperationContract] int Multiply(int num1, int num2); [OperationContract] int Divide(int num1, int num2); } // Use a data contract as illustrated in the sample below to add // composite types to service operations. [DataContract] Public class CompositeType { Bool boolValue = true; String stringValue = "Hello "; [DataMember] Public bool BoolValue { get { return boolValue; } set { boolValue = value; } } [DataMember] Public string StringValue { get { return stringValue; } set { stringValue = value; } } } }
下面给出了它的类背后的代码。
using System; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Runtime.Serialization; usingSystem.ServiceModel; usingSystem.Text; namespace WcfServiceLibrary1 { // NOTE: You can use the "Rename" command on the "Refactor" menu to // change the class name "Service1" in both code and config file // together. publicclassService1 :IService1 { // This Function Returns summation of two integer numbers publicint sum(int num1, int num2) { return num1 + num2; } // This function returns subtraction of two numbers. // If num1 is smaller than number two then this function returns 0 publicint Subtract(int num1, int num2) { if (num1 > num2) { return num1 - num2; } else { return 0; } } // This function returns multiplication of two integer numbers. publicint Multiply(int num1, int num2) { return num1 * num2; } // This function returns integer value of two integer number. // If num2 is 0 then this function returns 1. publicint Divide(int num1, int num2) { if (num2 != 0) { return (num1 / num2); } else { return 1; } } } }
要运行此服务,请单击 Visual Studio 中的“开始”按钮。
当我们运行此服务时,会出现以下屏幕。
单击 sum 方法后,将打开以下页面。在这里,您可以输入任意两个整数并单击“调用”按钮。该服务将返回这两个数字的总和。
与求和一样,我们可以执行菜单中列出的所有其他算术运算。这是他们的快照。
单击 Subtract 方法时会出现以下页面。输入整数,单击 Invoke 按钮,并获得如下所示的输出 –
单击乘法方法会出现以下页面。输入整数,单击 Invoke 按钮,并获得如下所示的输出 –
单击 Divide 方法会出现以下页面。输入整数,单击 Invoke 按钮,并获得如下所示的输出 –
调用服务后,您可以从这里直接在它们之间切换。
WCF – 托管 WCF 服务
创建 WCF 服务后,下一步是托管它,以便客户端应用程序可以使用它。这称为 WCF 服务托管。可以使用以下四种方式中的任何一种来托管 WCF 服务 –
-
IIS 托管– IIS 代表 Internet 信息服务。它的工作模型类似于 ASP.NET 的工作模型,同时承载 WCF 服务。IIS 托管的最佳功能是自动处理服务激活。IIS 托管还提供进程运行状况监控、空闲关闭、进程回收和更多功能以促进 WCF 服务托管。
-
自托管– 当 WCF 服务托管在托管应用程序中时,它被称为自托管。它需要开发人员为 ServiceHost 初始化编写必要的编码。在自托管中,WCF 服务可以托管在各种应用程序中,例如控制台应用程序、Windows 窗体等。
-
WAS 托管– 在 Windows 激活服务 (WAS) 中托管 WCF 服务是最有利的,因为它具有进程回收、空闲时间管理、通用配置系统以及对 HTTP、TCP 等的支持等功能。
-
Windows 服务托管– 对于本地系统客户端,最好将 WCF 服务作为窗口服务托管,这称为窗口服务托管。所有版本的 Windows 都支持这种类型的托管,在这里,服务控制管理器可以控制 WCF 服务的进程生命周期。
WCF – IIS 托管
在 IIS(Internet 信息服务)中承载 WCF 服务是一个循序渐进的过程。下面详细说明了 IIS 托管,并附有所需的编码和屏幕截图,以了解该过程。
步骤 1 – 启动 Visual Studio 2012 并单击文件 → 新建 → 网站。选择“WCF 服务”和位置为 http。这将在 IIS 中托管服务。单击确定。
Step 2 – 下面给出了界面背后的代码。
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Web; using System.Text; // NOTE: You can use the "Rename" command on the "Refactor" menu to // change the interface name "IService" in both code and config file // together. [ServiceContract] Public interface IService { [OperationContract] String GetData(int value); [OperationContract] CompositeType GetDataUsingDataContract(CompositeType composite); // TODO: Add your service operations here } // Use a data contract as illustrated in the sample below to add // composite types to service operations. [DataContract] Public class CompositeType { Bool boolValue = true; String stringValue = "Hello "; [DataMember] Public bool BoolValue { get { return boolValue; } set { boolValue = value; } } [DataMember] Public string StringValue { get { return stringValue; } set { stringValue = value; } } }
Step 3 – 下面给出了类文件背后的代码。
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Web; using System.Text; // NOTE: You can use the "Rename" command on the "Refactor" menu to // change the class name "Service" in code, svc and config file // together. Public class Service : IService { Public string GetData(int value) { Return string.Format("You entered: {0}", value); } Public CompositeType GetDataUsingDataContract(CompositeType composite) { if(composite == null) { thrownewArgumentNullException("composite"); } if(composite.BoolValue) { composite.StringValue += "Suffix"; } return composite; } }
步骤 4 – 服务文件 (.svc) 包含服务名称和文件名背后的代码。该文件用于了解服务。
<%@ ServiceHost Language = "C#" Debug = "true" Service = "Service" CodeBehind = "~/App_Code/Service.cs" %>
步骤 5 – 配置文件中提到了服务器端配置。这里只提到了一个配置为“wsHttpBinding”的端点;我们也可以有多个具有不同绑定的端点。由于我们要在 IIS 中托管,我们必须仅使用 http 绑定。
<?xml version = "1.0"?> <configuration> <!-- Note: As an alternative to hand editing this file you can use the web admin tool to configure settings for your application. Use the Website->Asp.Net Configuration option in Visual Studio. A full list of settings and comments can be found in machine.config.comments usually located in \Windows\Microsoft.Net\Framework\vx.x\Config --> <configSections> <sectionGroup name = "system.web.extensions" ype = "System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"> <sectionGroup name = "scripting" type = "System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"> <section name = "scriptResourceHandler" type = "System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" requirePermission = "false" allowDefinition = "MachineToApplication"/> <sectionGroup name = "webServices" type = "System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"> <section name = "jsonSerialization" type = "System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" requirePermission = "false" allowDefinition = "Everywhere"/> <section name = "profileService" type = "System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" requirePermission = "false" allowDefinition = "MachineToApplication"/> <section name = "authenticationService" type = "System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" requirePermission = "false" allowDefinition = "MachineToApplication"/> <section name = "roleService" type = "System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" requirePermission = "false" allowDefinition = "MachineToApplication"/> </sectionGroup> </sectionGroup> </sectionGroup> </configSections> <appSettings/> <connectionStrings/> <system.web> <!-- Set compilation debug="true" to insert debugging symbols into the compiled page. Because this affects performance, set this value to true only during development. --> <compilation debug = "true"> <assemblies> <add assembly = "System.Core, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = B77A5C561934E089"/> <add assembly = "System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add assembly = "System.Data.DataSetExtensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = B77A5C561934E089"/> <add assembly = "System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add assembly = "System.Xml.Linq, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = B77A5C561934E089"/> </assemblies> </compilation> <!-- The <authentication> section enables configuration of the security authentication mode used by ASP.NET to identify an incoming user. --> <authentication mode="Windows"/> <!-- The <customErrors> section enables configuration of what to do if/when an unhandled error occurs during the execution of a request. Specifically, it enables developers to configure html error pages to be displayed in place of a error stack trace. <customErrors mode = "RemoteOnly" defaultRedirect = "GenericErrorPage.htm"> <error statusCode = "403" redirect = "NoAccess.htm" /> <error statusCode = "404" redirect = "FileNotFound.htm" /> </customErrors> --> <pages> <controls> <add tagPrefix = "asp" namespace = "System.Web.UI" assembly = "System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add tagPrefix = "asp" namespace = "System.Web.UI.WebControls" assembly = "System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> </controls> </pages> <httpHandlers> <remove verb = "*" path = "*.asmx"/> <add verb = "*" path = "*.asmx" validate = "false" type = "System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add verb = "*" path = "*_AppService.axd" validate = "false" type = "System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add verb = "GET,HEAD" path = "ScriptResource.axd" type = "System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" validate = "false"/> </httpHandlers> <httpModules> <add name = "ScriptModule" type = "System.Web.Handlers.ScriptModule, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> </httpModules> </system.web> <system.codedom> <compilers> <compiler language = "c#;cs;csharp" extension = ".cs" warningLevel = "4" type = "Microsoft.CSharp.CSharpCodeProvider, System, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089"> <providerOption name = "CompilerVersion" value = "v3.5"/> <providerOption name = "WarnAsError" value = "false"/> </compiler> <compiler language = "vb;vbs;visualbasic;vbscript" extension = ".vb" warningLevel = "4" type = "Microsoft.VisualBasic.VBCodeProvider, System, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089"> <providerOption name = "CompilerVersion" value = "v3.5"/> <providerOption name = "OptionInfer" value = "true"/> <providerOption name = "WarnAsError" value = "false"/> </compiler> </compilers> </system.codedom> <!-- The system.webServer section is required for running ASP.NET AJAX under Internet Information Services 7.0. It is not necessary for previous version of IIS. --> <system.webServer> <validation validateIntegratedModeConfiguration="false"/> <modules> <remove name = "ScriptModule"/> <add name = "ScriptModule" preCondition = "managedHandler" type = "System.Web.Handlers.ScriptModule, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> </modules> <handlers> <remove name = "WebServiceHandlerFactory-Integrated"/> <remove name = "ScriptHandlerFactory"/> <remove name = "ScriptHandlerFactoryAppServices"/> <remove name = "ScriptResource"/> <add name = "ScriptHandlerFactory" verb = "*" path = "*.asmx" preCondition = "integratedMode" type = "System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add name = "ScriptHandlerFactoryAppServices" verb = "*" path = "*_AppService.axd" preCondition = "integratedMode" type = "System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add name = "ScriptResource" preCondition = "integratedMode" verb = "GET,HEAD" path = "ScriptResource.axd" type = "System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> </handlers> <!--To browse web app root directory during debugging, set the value below to true. Set to false before deployment to avoid disclosing web app folder information.--> <directoryBrowse enabled = "true"/> </system.webServer> <runtime> <assemblyBinding appliesTo = "v2.0.05727" xmlns =" urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name = "System.Web.Extensions" publicKeyToken = "31bf3856ad364e35"/> <bindingRedirect oldVersion = "1.0.0.0-1.1.0.0" newVersion = "3.5.0.0"/> </dependentAssembly> <dependentAssembly> <assemblyIdentity name = "System.Web.Extensions.Design" publicKeyToken =" 31bf3856ad364e35"/> <bindingRedirect oldVersion = "1.0.0.0-1.1.0.0" newVersion = "3.5.0.0"/> </dependentAssembly> </assemblyBinding> </runtime> <system.serviceModel> <services> <service name = "Service" behaviorConfiguration = "ServiceBehavior"> <!-- Service Endpoints --> <endpoint address = "" binding = "basicHttpBinding" contract = "IService"> <!-- Upon deployment, the following identity element should be removed or replaced to reflect the identity under which the deployed service runs. If removed, WCF will infer an appropriate identity automatically. --> <identity> <dns value="localhost"/> </identity> </endpoint> <endpoint address = "mex" binding = "mexHttpBinding" contract = "IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name = "ServiceBehavior"> <!-- To avoid disclosing metadata information, set the value below to false 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 false avoid disclosing exception information --> <serviceDebug includeExceptionDetailInFaults = "false"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
步骤 6 – 您需要提及服务文件名,以及配置文件中提到的地址。此处给出了 IIS 的屏幕截图。
单击开始 → 运行 → inetmgr 这将打开以下窗口。
步骤 7 – 运行将产生以下屏幕的应用程序。
WCF – 自托管
此处,WCF 服务托管在控制台应用程序中。下面给出了以顺序方式具有适当步骤的过程,解释了整个过程。
第 1 步– 首先,让我们创建服务合同及其实现。创建一个控制台应用程序并将其命名为 MyCalculatorService。这是一个返回两个数字相加的简单服务。
步骤 2 – 现在,右键单击解决方案资源管理器中的引用,然后单击添加引用。以下窗口打开;将 System.ServiceModel 引用添加到项目中。
第 3 步– 创建一个 ISimpleCalculator 接口,将 ServiceContract 和 OperationContract 属性添加到类和函数,如下所示。您将在后面的课程中了解更多关于这些合同的信息。这些合同将向外界公开使用此服务的方法。
第 4 步– 该文件背后的代码如下 –
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace MyCalculatorWCFService { [ServiceContract()] Public interface ISimpleCalculator { [OperationContract()] int Add(int num1, int num2); } }
第 5 步– MyCalculatorService 是 IMyCalculatorService 接口的实现类,如下所示。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyCalculatorWCFService { Class SimpleCalculator : ISimpleCalculator { Public int Add(int num1, int num2) { return num1 + num2; } } }
第 6 步– 现在,我们已准备好提供服务。让我们开始实施托管流程。创建一个新的控制台应用程序并将其命名为“MyCalculatorWCFServiceHost”。
步骤 7 – 添加 system.servicemodel 和项目 MyCalculatorWCFService 的引用。
这背后的代码如下 –
using System; using System.Collections.Generic; using System.Linq; using System.Text; using MyCalculatorWCFService; using System.ServiceModel; using System.ServiceModel.Description; namespace MyCalculatorWCFServiceHost { class Program { static void Main(string[] args) { //Create a URI to serve as the base address UrihttpUrl = newUri("http://localhost:8090/MyCalculatorWCFService/SimpleCalculator"); //Create ServiceHost ServiceHost host = newServiceHost(typeof(MyCalculatorWCFService.ISimpleCalculator), httpUrl); //Add a service endpoint host.AddServiceEndpoint(typeof(MyCalculatorWCFService.ISimpleCal culator), newWSHttpBinding(), ""); //Enable metadata exchange ServiceMetadataBehaviorsmb = newServiceMetadataBehavior(); smb.HttpGetEnabled = true; host.Description.Behaviors.Add(smb); //Start the Service host.Open(); Console.WriteLine("Service is host at " + DateTime.Now.ToString()); Console.WriteLine("Host is running... Press key to stop"); Console.ReadLine(); } } }
WCF – WAS 托管
要理解 WAS 托管的概念,我们需要理解系统是如何配置的以及如何创建服务契约,从而实现对托管服务的不同绑定。
首先,为非协议启用 WCF。在开始创建服务之前,我们需要配置系统以支持 WAS。以下是配置 WAS 的步骤 –
-
单击开始菜单 → 控制面板 → 程序和功能,然后单击左侧窗格中的“打开或关闭 Windows 组件”。
-
展开“Microsoft .Net Framework 3.0”并启用“Windows Communication Foundation HTTP Activation”和“Windows Communication Foundation Non-HTTP Activation”。
-
接下来,我们需要将 Binding 添加到默认网站。例如,我们将默认网站绑定到 TCP 协议。转到开始菜单 → 程序 → 附件。右键单击“命令提示符”,然后从上下文菜单中选择“以管理员身份运行”。
-
执行以下命令 –
C:\Windows\system32\inetsrv> appcmd.exe set site "Default Web Site" -+bindings.[protocol='net.tcp',bindingInformation='808:*']
此命令通过修改位于“C:\Windows\system32\inetsrv\config”目录中的 applicationHost.config 文件,将 net.tcp 站点绑定添加到默认网站。同样,我们可以为默认网站添加不同的协议。
创建 WAS 托管服务
Step-1 – 打开 Visual Studio 2008 并单击 New → WebSite 并从模板中选择 WCF Service,并将位置选择为 HTTP,如下所示 –
Step-2 – 通过创建接口 IMathService 创建合约。将 ServiceContract 属性添加到接口,并将 OperationContract 属性添加到方法声明。
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.Text; // NOTE: You can use the "Rename" command on the "Refactor" menu to // change the interface name "IService" in both code and config file // together. [ServiceContract] Public interface IMathService { [OperationContract] int Add(int num1, int num2); [OperationContract] int Subtract(int num1, int num2); }
Step-3 – IMathService 接口的实现如下所示 –
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.ServiceModel; using System.ServiceModel.Web; using System.Text; // NOTE: You can use the "Rename" command on the "Refactor" menu to // change the class name "Service" in code, svc and config file // together. Public class MathService : IMathService { Public int Add(int num1, int num2) { return num1 + num2; } Public int Subtract(int num1, int num2) { return num1 - num2; } }
Step-4 – 服务文件如下所示。
<%@ServiceHostLanguage="C#"Debug="true"Service="MathService"CodeBehind="~/App_Code/MathService.cs"%>
Step-5 – 在 web.Config 文件中,使用“netTcpBinding”绑定创建端点,服务元数据将使用元数据交换点发布。因此,创建元数据交换端点,地址为“mex”,绑定为“mexTcpBinding”。如果不发布服务元数据,我们就无法使用 net.tcp 地址创建代理,例如 –
svcutil.exe net.tcp://localhost/WASHostedService/MathService.svc).
<?xml version = "1.0" ?> <configuration> <!-- Note: As an alternative to hand editing this file you can use the web admin tool to configure settings for your application. Use the Website->Asp.Net Configuration option in Visual Studio. A full list of settings and comments can be found in machine.config.comments usually located in \Windows\Microsoft.Net\Framework\vx.x\Config --> <configSections> <sectionGroup name = "system.web.extensions" type = "System.Web.Configuration.SystemWebExtensionsSectionGroup, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"> <sectionGroup name = "scripting" type = "System.Web.Configuration.ScriptingSectionGroup, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken =3 1BF3856AD364E35"> <section name = "scriptResourceHandler" type = "System.Web.Configuration.ScriptingScriptResourceHandlerSection, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" requirePermission = "false" allowDefinition = "MachineToApplication"/> <sectionGroup name = "webServices" type = "System.Web.Configuration.ScriptingWebServicesSectionGroup, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"> <section name = "jsonSerialization" type = "System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" requirePermission = "false" allowDefinition = "Everywhere"/> <section name = "profileService" type = "System.Web.Configuration.ScriptingProfileServiceSection, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" requirePermission = "false" allowDefinition = "MachineToApplication"/> <section name = "authenticationService" type = "System.Web.Configuration.ScriptingAuthenticationServiceSection, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" requirePermission = "false" allowDefinition = "MachineToApplication"/> <section name = "roleService" type = "System.Web.Configuration.ScriptingRoleServiceSection, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" requirePermission = "false" allowDefinition = "MachineToApplication"/> </sectionGroup> </sectionGroup> </sectionGroup> </configSections> <appSettings/> <connectionStrings/> <system.web> <!-- Set compilation debug="true" to insert debugging symbols into the compiled page. Because this affects performance, set this value to true only during development. --> <compilation debug = "true"> <assemblies> <add assembly = "System.Core, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = B77A5C561934E089"/> <add assembly = "System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add assembly = "System.Data.DataSetExtensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = B77A5C561934E089"/> <add assembly = "System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add assembly = "System.Xml.Linq, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = B77A5C561934E089"/> </assemblies> </compilation> <!-- The <authentication> section enables configuration of the security authentication mode used by ASP.NET to identify an incoming user. --> <authentication mode="Windows"/> <!-- The <customErrors> section enables configuration of what to do if/when an unhandled error occurs during the execution of a request. Specifically, it enables developers to configure html error pages to be displayed in place of a error stack trace. <customErrors mode = "RemoteOnly" defaultRedirect = "GenericErrorPage.htm"> <error statusCode = "403" redirect = "NoAccess.htm" /> <error statusCode = "404" redirect = "FileNotFound.htm" /> </customErrors> --> <pages> <controls> <add tagPrefix = "asp" namespace = "System.Web.UI" assembly = "System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add tagPrefix = "asp" namespace = "System.Web.UI.WebControls" assembly = "System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> </controls> </pages> <httpHandlers> <remove verb = "*" path = "*.asmx"/> <add verb =" *" path =" *.asmx" validate="false" type = "System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add verb = "*" path = "*_AppService.axd" validate = "false" type = "System.Web.Script.Services.ScriptHandlerFactory,System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add verb = "GET,HEAD" path = "ScriptResource.axd" type = "System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35" validate = "false"/> </httpHandlers> <httpModules> <add name = "ScriptModule" type = "System.Web.Handlers.ScriptModule, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> </httpModules> </system.web> <system.codedom> <compilers> <compiler language = "c#;cs;csharp" extension = ".cs" warningLevel = "4" type = "Microsoft.CSharp.CSharpCodeProvider, System, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089"> <providerOption name = "CompilerVersion" value = "v3.5"/> <providerOption name = "WarnAsError" value = "false"/> </compiler> <compiler language = "vb;vbs;visualbasic;vbscript" extension = ".vb" warningLevel = "4" type = "Microsoft.VisualBasic.VBCodeProvider, System, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089"> <providerOption name = "CompilerVersion" value = "v3.5"/> <providerOption name = "OptionInfer" value = "true"/> <providerOption name = "WarnAsError" value = "false"/> </compiler> </compilers> </system.codedom> <!-- The system.webServer section is required for running ASP.NET AJAX under Internet Information Services 7.0. It is not necessary for previous version of IIS. --> <system.webServer> <validation validateIntegratedModeConfiguration = "false"/> <modules> <remove name = "ScriptModule"/> <add name = "ScriptModule" preCondition = "managedHandler" type = "System.Web.Handlers.ScriptModule, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> </modules> <handlers> <remove name = "WebServiceHandlerFactory-Integrated"/> <remove name = "ScriptHandlerFactory"/> <remove name = "ScriptHandlerFactoryAppServices"/> <remove name = "ScriptResource"/> <add name = "ScriptHandlerFactory" verb = "*" path = "*.asmx" preCondition = "integratedMode" type = "System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add name = "ScriptHandlerFactoryAppServices" verb = "*" path = "*_AppService.axd" preCondition = "integratedMode" type = "System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> <add name = "ScriptResource" preCondition = "integratedMode" verb = "GET,HEAD" path = "ScriptResource.axd" type = "System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version = 3.5.0.0, Culture = neutral, PublicKeyToken = 31BF3856AD364E35"/> </handlers> <!-- To browse web app root directory during debugging, set the value below to true. Set to false before deployment to avoid disclosing web app folder information. --> <directoryBrowse enabled="true"/> </system.webServer> <runtime> <assemblyBinding appliesTo = "v2.0.05727" xmlns = "urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name = "System.Web.Extensions" publicKeyToken = "31bf3856ad364e35"/> <bindingRedirect oldVersion = "1.0.0.0-1.1.0.0" newVersion = "3.5.0.0"/> </dependentAssembly> <dependentAssembly> <assemblyIdentity name = "System.Web.Extensions.Design" publicKeyToken = "31bf3856ad364e35"/> <bindingRedirect oldVersion = "1.0.0.0-1.1.0.0" newVersion = "3.5.0.0"/> </dependentAssembly> </assemblyBinding> </runtime> <system.serviceModel> <services> <service behaviorConfiguration = "ServiceBehavior" name = "Service"> <endpoint address = "" binding = "basicHttpBinding" contract = "IMathService"> <identity> <dns value = "localhost" /> </identity> </endpoint> <endpoint address = "mex" binding = "mexHttpBinding" contract = "IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name = "ServiceBehavior"> <!-- To avoid disclosing metadata information, set the value below to false 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"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
启用与托管服务的不同绑定
-
转到开始菜单 → 程序 → 附件。右键单击“命令提示符”,然后从上下文菜单中选择“以管理员身份运行”。
-
执行以下命令——
C:\Windows\system32\inetsrv>appcmd set app "Default Web Site/WASHostedService" /enabledProtocols:http,net.tcp
它将产生以下输出 –
WCF – Windows 服务托管
Windows 服务托管的操作很简单。下面给出了带有必要编码和屏幕截图的步骤,它们以简单的方式解释了该过程。
第 1 步– 现在让我们创建一个 WCF 服务。打开 Visual Studio 2008 并单击新建 → 项目并从模板中选择类库。
步骤 2 – 将参考 System.ServiceModel 添加到项目中。这是用于创建 WCF 服务的核心程序集。
步骤 3 – 接下来,我们可以创建 ISimpleCalulator 接口。添加服务和操作合同属性,如下所示 –
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace WindowsServiceHostedService{ [ServiceContract] public interfaceISimpleCalculator { [OperationContract] int Add(int num1, int num2); [OperationContract] int Subtract(int num1, int num2); [OperationContract] int Multiply(int num1, int num2); [OperationContract] double Divide(int num1, int num2); } }
第 4 步– 实现 ISimpleCalculator 接口,如下所示 –
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace WindowsServiceHostedService { Class SimpleCalulator : ISimpleCalculator { Public int Add(int num1, int num2) { return num1 + num2; } Public int Subtract(int num1, int num2) { return num1 - num2; } Public int Multiply(int num1, int num2) { return num1 * num2; } Public double Divide(int num1, int num2) { if (num2 != 0) return num1 / num2; else return 0; } } }
第 5 步– 构建项目并获取 dll。现在,我们已准备好使用 WCF 服务。我们将看到如何在 Windows 服务中托管 WCF 服务。
注意– 在这个项目中,提到我们在同一个项目中创建合同和服务(实现)。但是,如果您在不同的项目中同时拥有两者,这始终是一个好习惯。
步骤 6 – 打开 Visual Studio 2008 并单击新建 → 项目并选择 Windows 服务。
第 7 步– 添加“WindowsServiceHostedService.dll”作为对项目的引用。该程序集将充当服务。
步骤 8 – 服务的 OnStart 方法可用于编写 WCF 的托管代码。我们必须确保我们只使用一个服务主机对象。OnStop 方法用于关闭服务主机。以下代码显示了如何在 Windows 服务中托管 WCF 服务。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Linq; using System.ServiceProcess; using System.Text; using System.ServiceModel; using System.ServiceModel.Description; namespace WCFHostedWindowsService { Partial class WCFHostedWindowsService : ServiceBase { ServiceHostm_Host; Public WCFHostedWindowsService() { InitializeComponent(); } Private void InitializeComponent() { thrownewNotImplementedException(); } protectedoverridevoidOnStart(string[] args) { if (m_Host != null) { m_Host.Close(); } //Create a URI to serve as the base address UrihttpUrl = newUri("http://localhost:8090/WindowsServiceHostedService/SimpleCalculator"); //Create ServiceHost m_Host = newServiceHost typeof(WindowsServiceHostedService.SimpleCalulator), httpUrl); //Add a service endpoint m_Host.AddServiceEndpoint (typeof(WindowsServiceHostedService.ISimpleCalculator), newWSHttpBinding(), ""); //Enable metadata exchange ServiceMetadataBehaviorsmb = newServiceMetadataBehavior(); smb.HttpGetEnabled = true; m_Host.Description.Behaviors.Add(smb); //Start the Service m_Host.Open(); } protectedoverridevoidOnStop() { if (m_Host != null) { m_Host.Close(); m_Host = null; } } staticvoid Main() { ServiceBase[] ServicesToRun; ServicesToRun = newServiceBase[] { newWCFHostedWindowsService(); } ServiceBase.Run(ServicesToRun); } } }
步骤 9 – 为了安装服务,我们需要有 Windows 服务的安装程序类。所以在项目中添加一个新的Installer类,该类继承自Installer类。下面给出的是显示服务名称、启动类型等的代码。
using System; using System.Collections.Generic; using System.Text; using System.ServiceProcess; using System.Configuration.Install; using System.ComponentModel; using System.Configuration; namespace WCFHostedWindowsService { [RunInstaller(true)] Public class WinServiceInstaller : Installer { Private ServiceProcessInstaller process; Private ServiceInstaller service; Public WinServiceInstaller() { process = newServiceProcessInstaller(); process.Account = ServiceAccount.NetworkService; service = newServiceInstaller(); service.ServiceName = "WCFHostedWindowsService"; service.DisplayName = "WCFHostedWindowsService"; service.Description = "WCF Service Hosted"; service.StartType = ServiceStartMode.Automatic; Installers.Add(process); Installers.Add(service); } } }
步骤 10 – 构建项目以获取可执行文件 WCFHostedWindowsService.exe。接下来,我们需要使用 Visual Studio 命令提示符安装服务。因此,通过单击开始→所有程序→Microsoft Visual Studio 2008→Visual Studio 工具→ Visual Studio 命令提示符打开命令提示符。使用 install util 实用程序应用程序,您可以安装服务,如下所示。
WCF – 使用 WCF 服务
WCF 服务允许其他应用程序访问或使用它们。WCF 服务可以通过多种方式使用,具体取决于托管类型。在这里,我们将解释为以下每个流行的托管选项使用 WCF 服务的分步方法 –
- 使用 IIS 5/6 中托管的 WCF 服务
- 使用自托管的 WCF 服务
- 使用 Windows 激活服务中托管的 WCF 服务
- 使用托管在 Windows 服务中的 WCF 服务
使用 IIS 5/6 中托管的 WCF 服务
下面详细讨论使用 IIS 5/6 中承载的 WCF 服务的过程。此外,讨论还包括如何创建代理和控制台应用程序。
步骤 1 – 一旦服务托管在 IIS 中,我们必须在客户端应用程序中使用它。在创建客户端应用程序之前,我们需要为服务创建一个代理。客户端应用程序使用此代理与服务交互。要创建代理,请运行 Visual Studio 2008 命令提示符。使用服务实用程序,我们可以创建代理类及其配置信息。
svcutilhttp://localhost/IISHostedService/Service.svc
执行此命令后,我们将在默认位置生成两个文件。
-
MyService.cs – WCF 服务的代理类
-
output.config – 有关服务的配置信息
第 2 步– 现在,我们将开始使用 Visual Studio 2008(客户端应用程序)创建控制台应用程序。
第 3 步– 添加引用“System.ServiceModel”;这是 WCF 的核心 dll。
第 4 步– 创建一个代理类。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyServiceClient { Class Program { Static void Main(string[] args) { // Creating Proxy for the MyService ServiceClient Client = newServiceClient(); Console.WriteLine("Client calling the service..."); Console.WriteLine("Hello Ram"); Console.Read(); } } }
输出显示如下 –
使用自托管 WCF 服务
在这里,将逐步解释使用自托管 WCF 服务的整个过程,并在必要时提供充足的编码和屏幕截图。
第 1 步– 托管服务,现在我们需要为客户端实现代理类。有多种创建代理的方法。
-
使用 SvcUtil.exe,我们可以创建代理类及其带有端点的配置文件。
-
向客户端应用程序添加服务引用。
-
实现 ClientBase<T> 类
在这三种方法中,实现 ClientBase<T> 是最佳实践。如果您使用的是其他两种方法,我们需要在每次对 Service 实现进行任何更改时创建一个代理类。但对于 ClientBase<T> 而言,情况并非如此。它只会在运行时创建代理,因此它会处理所有事情。
为此,创建一个代理类,其中包括 System.ServiceModel 和 MyCalculatorService 的引用。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using MyCalculatorService; namespace MyCalculatorServiceProxy { // WCF create proxy for ISimpleCalculator using ClientBase Public class MyCalculatorServiceProxy : ClientBase<ISimpleCalculator>, ISimpleCalculator { Public int Add(int num1, int num2) { //Call base to do funtion returnbase.Channel.Add(num1, num2); } } }
现在,创建一个控制台应用程序,其中包括 System.ServiceModel 和 MyCalculatorServiceProxy 的引用。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using MyCalculatorServiceProxy; namespace MyCalculatorServiceClient { classProgram { Static void Main(string[] args) { MyCalculatorServiceProxy.MyCalculatorServiceProxy proxy = newMyCalculatorServiceProxy.MyCalculatorServiceProxy(); Console.WriteLine("Client is running at " + DateTime.Now.ToString()); Console.WriteLine("Sum of two numbers. 5 + 5 =" + proxy.Add(5,5)); Console.ReadLine(); } } }
步骤 2 – 应将端点(与服务相同)信息添加到客户端应用程序的配置文件中。
<?xmlversion = "1.0"encoding = "utf-8" ?> <configuration> <system.serviceModel> <client> <endpoint address ="http://localhost:8090/MyCalculatorServiceProxy/ISimpleCalculator" binding = "wsHttpBinding" contract "MyCalculatorServiceProxy.ISimpleCalculator"> </endpoint> </client> </system.serviceModel> </configuration>
步骤 3 – 在运行客户端应用程序之前,您需要运行该服务。下面显示的是客户端应用程序的输出。
使用 WAS 中托管的 WCF 服务
使用托管在 WAS 中的 WCF 服务是一个简单的过程,只需几个步骤。步骤如下 –
- 将代理类和配置文件添加到客户端应用程序。
- 为 MathServiceClient 创建对象并调用该方法。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespaceWASHostedClient { classProgram { staticvoid Main(string[] args) { MathServiceClient client = newMathServiceClient(); Console.WriteLine("Sum of two number 5,6"); Console.WriteLine(client.Add(5, 6)); Console.ReadLine(); } } }
输出如下所示。
使用 Windows 服务中托管的 WCF 服务
下面详细介绍了如何使用托管在 Windows 服务中的 WCF 服务的分步过程,并附有编码和说明。
一旦成功托管,我们就可以为服务创建一个代理类并开始在客户端应用程序中使用。在这里,它显示为 IIS 托管类型消耗。
添加ServiceModel的引用。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespaceWindowServiceClient { classProgram { staticvoid Main(string[] args) { //Creating Proxy for the MyService MyServiceClient client = newMyServiceClient(); Console.WriteLine("Client calling the service..."); Console.WriteLine("Sum of two numbers 5,6"); Console.WriteLine(client.Add(5, 6)); Console.WriteLine("Subtraction of two numbers 6,5"); Console.WriteLine(client.Sub(6, 5)); Console.WriteLine("Multiplication of two numbers 6,5"); Console.WriteLine(client.Mul(6, 5)); Console.WriteLine("Division of two numbers 6,3"); Console.WriteLine(client.Div(6, 3)); Console.Read(); } } }
输出显示如下 –
WCF – 服务绑定
WCF 服务绑定是一组几个元素,其中每个元素定义服务与客户端通信的方式。传输元素和消息编码元素是每个绑定的两个最重要的组件。在本章中,我们将讨论常用的各种 WCF 服务绑定。
基本绑定
BasicHttpBinding 类提供基本绑定。它使用 HTTP 协议将 WCF 服务传输和表示为 ASP.NET Web 服务(ASMX Web 服务),以便使用 ASMX Web 服务的旧客户端可以方便地使用新服务。
基本绑定设置为 Silverlight 启用的 WCF Web 服务中的默认绑定,并且是 Web 服务样式通信的标准绑定。它不支持可靠的消息传递。
下面给出的代码片段描述了基本绑定的默认设置。
<basicHttpBinding> <binding name = "basicHttpBindingDefaults" allowCookies = "false" bypassProxyOnLocal = "false" hostNameComparisonMode = "StrongWildcard" maxBufferPoolSize = "524288" maxBufferSize = "65536" maxReceivedMessageSize = "65536" messageEncoding = "Text" proxyAddress = "" textEncoding = "utf-8" transferMode = "Buffer" useDefaultWebProxy = "true" closeTimeout = "00:01:00" openTimeout = "00:01:00" receiveTimeout = "00:10:00" sendTimeout = "00:01:00"> <readerQuotas maxArrayLength = "16384" maxBytesPerRead = "4096" maxDepth = "32" maxNameTableCharCount = "16384" maxStringContentLength = "8192"/> <security mode = "None"> <transport clientCredentialType = "None" proxyCredentialType = "None" realm = ""/> <message algorithmSuite = "Basic256" clientCredentialType = "UserName" /> </security> </binding> </basicHttpBinding>
上述默认设置有其明显的局限性,因为消息大小有限且没有安全模式。但是,基本绑定的定制解决了这个问题,如下所示。
<basicHttpBinding> <binding name = "basicHttpSecure" maxBufferSize = "100000" maxReceivedMessageSize = "100000"> <readerQuotas maxArrayLength = "100000" maxStringContentLength = "100000"/> <security mode = "TransportWithMessageCredential" /> </binding> </basicHttpBinding>
网络服务绑定
Web 服务 (WS) 绑定由 WSHttpBinding 类提供。它与基本绑定非常相似,并使用相同的传输协议,但提供了几个 WS-* 规范,例如 WS-Reliable Messaging、WS-Transactions、WS-Security 等等。简而言之,WSHttpBinding 等于 basicHttpBinding 和 WS-* 规范的总和。下面给出的代码片段描述了 WS 绑定的默认设置 –
<wsHttpBinding> <binding name = "wsHttpBindingDefaults" allowCookies = "false" bypassProxyOnLocal = "false" closeTimeout = "00:01:00" hostNameComparisonMode = "StrongWildcard" maxBufferPoolSize = "524288" maxReceivedMessageSize = "65536" messageEncoding = "Text" openTimeout = "00:01:00" receiveTimeout = "00:10:00" proxyAddress = "" sendTimeout = "00:01:00" textEncoding = "utf-8" transactionFlow = "false" useDefaultWebProxy = "true" > <readerQuotas maxArrayLength = "16384" maxBytesPerRead = ."4096" maxDepth = "32" maxNameTableCharCount = "16384" maxStringContentLength = "8192"/> <reliableSession enabled = "false" ordered = "true" inactivityTimeout = "oo:10:00" /> <security mode = "Message"> <message algorithmSuite = "Basic256" clientCredentialType = "Windows" esatalishSecurityContext = "true" negotiateServiceCredential = "true" /> <transport clientCredentialType = "Windows" proxyCredentialType = "None" realm = ""/> </security> </binding> </wsHttpBinding>
工控机绑定
IPC 绑定使用命名管道并由 netNamedPipeBinding 类提供。这是所有可用绑定中最快和最安全的绑定。尽管此处不支持消息级安全性,但由于强大的传输安全性,消息在默认情况下是安全的。下面给出的是描述 IPC 绑定默认设置的代码片段 –
<netNamedPipeBinding> <binding name = "netPipeDefaults" closeTimeout = "00:01:00" hostNameComparisonMode = "StrongWildcard" maxBufferPoolSize = "524288" maxBufferSize = "65536" maxConnections = "10" maxReceivedMessageSize = "65536" openTimeout = "00:01:00" receiveTimeout = "00:10:00" sendTimeout = "00:01:00" transactionFlow = "false" transactionProtocol = "OleTransactions" transferMode = "Buffered"> <readerQuotas maxArrayLength = "16384" maxBytesPerRead = "4096" maxDepth = "32" maxNameTableCharCount = "16384" maxStringContentLength = "8192"/> <security mode = "Transport"> </security> </binding> </netNamedPipeBinding>
其他类型的服务绑定
-
TCP 绑定– 由 NetTCPBinding 类提供,此绑定使用 TCP 协议在同一网络内进行通信,并以二进制格式进行消息编码。与其他绑定相比,这种绑定被认为是最可靠的。
-
WS Dual Binding – 这种类型的绑定更像 WSHttpBinding,唯一的例外是它促进双向通信,即客户端和服务都可以发送和接收消息。它由 WSDualHttpBinding 类提供。
-
Web 绑定– Web 绑定旨在通过使用 HTTP-GET、HTTP-POST 等以 HTTP 请求的形式表示 WCF 服务。它由 WebHttpBinding 类提供,通常与社交网络一起使用。
-
MSMQ Binding – 它由 NetMsmqBinding 类提供,用于提供解决方案,以防服务在与客户端发送的时间不同的时间处理消息。MSMQ 绑定使用 MSMQ 进行传输,并为分离的消息排队提供支持。MSMQ 是 Microsoft 提供的消息队列实现。
-
联合 WS 绑定– 它是一种特定形式的 WS 绑定,并提供对联合安全的支持。它由 WSFederationHttpBinding 类提供。
-
Peer Network Binding – 由 NetPeerTCPBinding 类提供,主要用于文件共享系统。它使用 TCP 协议,但使用对等网络作为传输。在这种网络中,每台机器(节点)充当其他节点的客户端和服务器。对等网络绑定用于文件共享系统,如 torrent。
-
MSMQ 集成绑定– 由 MsmqIntegrationBinding 类提供,它有助于与通过 MSMQ(Microsoft 消息队列)进行通信的现有系统进行通信。
除此之外,还可以创建自定义绑定。但是,由于可以调整每个 WCF 绑定的配置属性,因此很少需要创建自定义绑定。
WCF – 实例管理
WCF 用于将一组消息(客户端请求)绑定到服务实例的一组技术称为实例管理。WCF 支持三种类型的实例激活,本章将讨论它们。
每次通话服务
每次调用服务是 WCF 的默认实例激活模式。为每次调用服务配置 WCF 服务时,会为客户端调用或请求正在进行的时间跨度创建 CLR 对象。CLR 代表公共语言运行时,它包括 WCF 中的服务实例。
在每次调用服务中,每个客户端请求都会实现一个新的专用服务实例,并且与其他类型的实例激活相比,其内存消耗更少。
InstanceContextMode 属性需要设置为 InstanceContextMode.PerCall,以指示 WCF 服务充当每次调用服务。InstanceContextMode 属性属于 ServiceBehavior 属性。因此,可以按如下方式配置每次调用服务 –
[ServiceContract] interface IMyContract {...} [ServiceBehavior (InstanceContextMode = InstanceContextMode.PerCall)] class MyService : IMyContract {...}
此处的服务表示为 IMyContract。下图展示了每次调用服务实例激活的过程。
实现按调用服务
[DataContract] class Param {....} [ServiceContract] interface IMyContract { [OperationContract] void MyMethod(Param objectIdentifier); } class MyPerCallService : IMyContract, IDisposable { public void MyMethod(Param objectIdentifier) { GetState(objectIdentifier); DoWork(); SaveState(objectIdentifier); } void GetState(Param objectIdentifier) {....} void DoWork() {....} void SaveState(Param objectIdentifier) {....} public void Dispose() {....} }
这里,Param 是为上述示例发明的伪类型参数。
每次会话服务
在 WCF 的这种激活模式中,在两个实体(即客户端和特定服务实例)之间维护着一个私有或我们可以说的机密会话。也称为专用会话服务,每会话服务提供一个新的服务实例,该实例保持专用于每个客户端请求,并独立于与该会话感知服务相关的所有其他实例。
要启动每会话服务,需要将 InstanceContextMode 属性设置为 PerSession。在这里,服务实例在整个会话期间都保留在内存中。
激活模式受到可扩展性的影响,因为配置的服务无法支持除少数(或可能多达数百个)之外的任何其他优秀客户端,因为每个专用服务实例都涉及成本。
每个会话服务可以配置为 –
[ServiceBehavior (InstanceContextMode = InstanceContextMode.PerSession)] class MyService : IMyContract {...}
每个会话服务的过程可以描述如下图所示 –
以下代码显示了为使用私有会话而配置的合同和服务。输出表明客户端确实获得了专用服务实例。
服务代码
[ServiceContract(Session = true)] interface IMyContract { [OperationContract] void MyMethod(); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)] class MyService : IMyContract, IDisposable { int m_Counter = 0; MyService() {Console.WriteLine("MyService.MyService()"); } public void MyMethod() { m_Counter++; Console.WriteLine("Counter = " + m_Counter); } public void Dispose() { Console.WriteLine("MyService.Dispose()"); } }
客户代码
MyContractProxy proxy = new MyContractProxy(); proxy.MyMethod(); proxy.MyMethod(); proxy.Close();
输出
MyService.MyService() Counter = 1 Counter = 2 MyService.Dispose()
单例服务
在 WCF 的这种激活模式下,所有相互独立的客户端请求都连接到同一个众所周知的单个实例,而不管它们与服务端点的连接。只有在主机关闭时才会处理单例服务。
此服务仅在创建主机时创建一次。如果主机未提供任何单例实例,则服务返回 NULL。当每个方法调用的工作量很小并且后台没有挂起的操作时,激活模式是最好的。
InstanceContextMode 属性需要设置为 InstanceContextMode.Single 才能启动这个 Singleton 服务。
因此,单例服务可以配置为 –
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] class MySingleton : ... {...}
Singleton 服务的流程如下图所示 –
以下代码用于初始化和托管单例实例。
服务代码
[ServiceContract] interface IMyContract { [OperationContract] void MyMethod( ); } [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] class MySingleton : IMyContract { int m_Counter = 0; public int Counter { get { return m_Counter; } set { m_Counter = value; } } public void MyMethod( ) { m_Counter++; Trace.WriteLine("Counter = " + Counter); } }
主机代码
MySingleton singleton = new MySingleton( ); singleton.Counter = 42; ServiceHost host = new ServiceHost(singleton); host.Open( ); //Do some blocking calls then host.Close( );
客户端代码
MyContractClient proxy = new MyContractClient( ); proxy.MyMethod( ); proxy.Close( );
输出
Counter = 43
WCF – 交易
WCF 中的事务是一组遵循某些属性的操作,统称为 ACID。在这里,如果单个操作失败,整个系统就会自动失败。当在线下订单时,就会发生交易。以下示例有助于以更简单的方式理解交易过程。
例子
假设您从网上商店订购了一台液晶电视,并且您将使用信用卡支付金额。当您输入下订单的必要信息时,两个操作同时发生。
一是从您的银行账户中扣除指定金额,二是供应商账户贷记相同金额。这两个操作都必须成功执行才能成功进行交易。
WCF 事务属性
WCF 事务后跟的四个属性如下 –
-
Atomic – 所有操作必须在交易完成时作为一个不可分割的操作。
-
一致性– 无论操作集是什么,系统始终处于一致性状态,即事务的结果始终符合预期。
-
隔离– 在交易完成之前,系统的中间状态对外部世界的任何实体都是不可见的。
-
耐用性– 无论出现任何类型的故障(硬件、断电等),都将保持承诺状态
在配置 WCF 事务时,需要考虑一些因素。这些是绑定和操作行为。
Binding – WCF 中支持事务的绑定只有少数几个,并且仅从这些绑定中进行选择至关重要,这些绑定在默认情况下保持禁用状态,应该启用以获得对事务的必要支持。这些绑定如下 –
- 网络协议绑定
- 网络命名管道绑定
- WSHttp绑定
- WSDualHttpBinding
- WSFederationHttpBinding
操作行为– 虽然绑定促进了事务传播的路径,但操作负责事务处理以及操作配置。操作行为主要使用两个属性:TransactionFlow 和 TransactionScopeRequired。这里需要注意的是,TransactionFlow 主要有三个值,它们是:Allowed、Mandatory 和 NotAllowed。
下面的代码展示了改变绑定和操作合约的配置是否有利于客户端的传播。
<bindings> <wsHttpBinding> <binding name = "MandatoryTransBinding" transactionFlow = "true"> <reliableSession enabled ="true"/> </binding> </wsHttpBinding> </bindings>
交易协议
WCF 使用三种类型的协议进行交易 –
- 轻的
- 奥莱交易
- WS-原子事务 (WS-AT)
在这三者中,WS-AT 是一种可互操作的协议,支持跨防火墙的分布式事务流。但是,当交易严格基于 Microsoft 技术时,不应使用此协议。
WCF 事务的阶段
WCF 事务有两个阶段,如下图所示。
-
准备阶段– 在此阶段,事务管理器检查所有实体是否已准备好提交事务。
-
提交阶段– 在此阶段,实体的承诺在现实中开始。
下图说明了 WCF 事务的两个阶段的功能。
启用 WCF 事务
要成功启用 WCF 事务,需要按顺序执行一系列六个步骤。下面讨论必要的步骤。
步骤 1 – 创建两个 WCF 服务
这方面的首要步骤是在 WCF 中构建两个服务项目以参与单个事务。数据库事务将在这两个服务上执行,并且可以理解它们是如何通过 WCF 事务统一的。还创建了 WCFTransactions 的 Web 应用程序,以在单个事务范围内使用这两个创建的服务。
步骤 2 – 方法创建及其具有 TransactionFlow 属性的属性
在这里,将为两个 WCF 服务创建一个 UpdateData 方法,以将其插入到具有 OperationContract 属性的数据库中。为了完成这个任务,首先在 ServiceContract 属性的帮助下创建一个接口类。为了在新创建的方法中启用事务,它被归因于 TransactionFlow 并且允许事务使用是 Allowed 值。
[ServiceContract] public interface IService1 { [OperationContract] [TransactionFlow(TransactionFlowOption.Allowed)] void UpdateData(); }
第 3 步 – 使用 TransactionScopeRequired 属性实现 WCF 服务
它是通过使用下面显示的代码完成的 –
[OperationBehavior(TransactionScopeRequired = true)] public void UpdateData() { try { SqlConnection objConnection = new SqlConnection(strConnection); objConnection.Open(); using(SqlTransaction transaction = Program.dbConnection.BeginTransaction()) { Boolean doRollback = false; using(SqlCommand cmd = new SqlCommand( "insert into Customer (Customer name, Customer code) values ('sss', 'sss')"objConnection)) try { cmd.ExecuteNonQuery(); } catch(SqlException) { doRollback = true; break; } } if(doRollback) transaction.Rollback(); else transaction.Commit(); } finally { objConection.Close(); } }
第 4 步 – 通过 WCF 服务配置文件启用事务流
其编码如下 –
<bindings> <wsHttpBinding> <binding name = "TransactionalBind" transactionFlow = "true"/> </wsHttpBinding> </bindings>
将事务允许绑定附加到端点以公开 WCF 服务至关重要。
<endpoint address = "" binding = "wsHttpBinding" bindingConfiguration = "TransactionalBind" contract = "WcfService1.IService1">
第 5 步 – 在单个事务中调用这两个服务
在这里,上述两个服务在一个事务中调用,为此,TransactionScope 对象用于对这两个服务进行分组。调用上述对象的 Complete 方法来提交 WCF 事务。要回滚,将调用 Dispose 方法。
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew)) { try { // Call your webservice transactions here ts.Complete(); } catch (Exception ex) { ts.Dispose(); } }
将 WCF 事务分组到一个范围内的一小段完整代码如下所示 –
using (TransactionScope ts = new TransactionScope(TransactionScopeOption.RequiresNew)) { try { ServiceReference1.Service1Client obj = newServiceReference1.Service1Client(); obj.UpdateData(); ServiceReference2.Service1Client obj1 = new ServiceReference2.Service1Client(); obj1.UpdateData(); ts.Complete(); } catch (Exception ex) { ts.Dispose(); } }
第 6 步 – 测试 WCF 事务
测试在第 6 步也是最后一步完成,在调用第一个 WCF 服务后,会强制发生异常。
WCF – Ria 服务
WCF RIA 服务是一个更高级别的框架,是 .NET 4 和 Silverlight 4 等框架的新组件,它通过提供客户端验证简化了在 Silverlight 中构建复杂业务应用程序的过程。RIA 代表富互联网应用程序。
这里必须要注意的是,Silverlight 是微软提供的框架,非常适合富互联网应用程序,可以作为浏览器插件使用,就像 Adobe Flash 一样。
WCF RIA Service主要是基于WCF服务的标准版。下图说明了 WCF 体系结构的一部分,其中 WCF RIA 服务通常具有其重点。
创建 WCF RIA 服务是更好地理解该概念的下一步。下面给出了分步过程。
步骤 1 – 使用 Silverlight 5 创建一个名为 SLWCFRiaServices.Web 的新 Web 项目,然后通过选择 ADO.NET 实体数据模型添加一个新项目。
第 2 步– 现在通过从数据库生成模型,从实体数据模型向导中选择模型内容。
步骤 3 – 从同一个向导中,选择您的数据连接和数据库对象。
第 4 步– 构建解决方案,以便将来识别数据模型对于您将要创建的域服务不会成为问题。
第 5 步– 现在通过添加新项目在 Web 项目中创建域服务,并确保启用客户端访问。
第 6 步– 在下一步中,将生成一些类,并且必须再次构建它们。
步骤 7 – 在此步骤中,DataDomainContext 由数据源面板显示。
步骤 8 – 在此步骤中,应选择并自定义 DataDomainContext 下方的文章。
第 9 步– 将 DataGrid 控件与数据源连接是此处提交的步骤,以及主题的选择。此处选择了 BureauBlue 主题。
步骤 10 – 最后一步也是最后一步包括转到设计屏幕并通过简单的拖放在 MainPage 的布局区域中添加实体。确保 AutoGenerateColumns = “True” 并运行它以查看输出也很重要。
先决条件
体验 WCF RIA 服务的全部潜力有一些先决条件 –
- 视觉工作室 2010 / 视觉工作室 2012
- Silverlight 开发人员运行时
- 最新版本的 RIA 服务工具包
- SDK(软件开发工具包)
WCF RIA 域服务
域服务由一组与业务相关的数据操作组成。它只不过是一个 WCF 服务,它公开了任何 WCF RIA 服务应用程序的业务逻辑。
WCF RIA 域服务在内部具有托管类 DomainServiceHost,它反过来使用 WCF ServiceHost 类来托管应用程序。为了使客户端项目可以访问域服务,它应该具有 EnableClientAccessAttribute 属性。每当添加新的域服务类时,都会自动应用该属性。
下图显示了 WCF RIA 域服务的架构 –
WCF RIA 服务 – 查询数据
下图显示了如何在客户端创建查询并在服务器端执行以返回可查询的结果。DAL 代表数据访问层。
WCF RIA 服务 – 更新数据
下图显示了如何通过在服务器端执行 CUD(创建更新删除)操作来更新数据。这里需要注意的是,WCF RIA 服务在服务器端始终是无状态的。
WCF – 安全
WCF 服务拥有强大的安全系统,具有两种安全模式或级别,因此只有预期的客户端才能访问这些服务。WCF 在很大程度上缓解了分布式事务中常见的安全威胁。
主要安全功能
WCF 服务有四个关键的安全特性,如下图所示。
-
身份验证– 在这里,身份验证不限于识别消息的发送者,而是相互的,即需要对消息接收者进行身份验证以排除任何类型的中间人攻击的可能性。
-
授权– 这是 WCF 服务为确保安全性而采取的下一步,在这里确定服务是否应授权调用者继续进行。尽管授权不依赖于身份验证,但它通常遵循身份验证。
-
机密性– 呼叫者和服务之间的信息交换是保密的,以限制其他人不打算对其进行解释。为了实现这一点,加密与各种其他机制一起使用。
-
完整性– 最后一个关键概念是保持完整性,即保证消息在从发送者到接收者的过程中没有被任何人篡改。
传输安全模式
WCF 提供以下传输安全模式以确保客户端和服务器之间的安全通信。下面介绍各种传输安全模式。
-
无– 此模式不保证任何类型的消息安全,并且该服务不会获得有关客户端的任何凭据。这种模式风险很大,因为它可能允许消息篡改,因此不推荐。
<wsHttpBinding> <binding name = "WCFSecurityExample"> <security mode = "None"/> </binding> </wsHttpBinding>
-
传输– 此模式是通过使用 TCP、IPC、Https 和 MSMQ 等通信协议实现安全消息传输的最简单方法。这种模式在点对点传输时更有效,主要用于受控环境,即内网应用程序。
<wsHttpBinding> <binding name = "WCFSecurityExample"> <security mode = "Transport"/> </binding> </wsHttpBinding>
-
消息– 安全模式允许相互身份验证并在很大程度上提供隐私,因为消息是加密的并且可以通过 http 传输,这不被视为安全协议。此处提供端到端的安全性,而无需考虑消息传输中涉及多少中介以及是否存在安全传输。该模式通常由 Internet 应用程序使用。
<wsHttpBinding> <binding name = "WCFSecurityExample"> <security mode = "Message"/> </binding> </wsHttpBinding>
-
混合– 此安全模式不经常使用,客户端身份验证仅在客户端级别提供。
<wsHttpBinding> <binding name = "WCFSecurityExample"> <security mode = "TransportWithMessageCredential"/> </binding> </wsHttpBinding>
-
两者– 这种安全模式包括传输安全和消息安全,以提供强大的安全保护,但通常会导致整体性能过载。这个只有 MSMQ 支持。
<netMsmqBinding> <binding name = "WCFSecurityExample"> <security mode = "Both"/> </binding> </netMsmqBinding>
默认情况下,除 BasicHttpBinding 之外的所有 WCF 绑定都具有一定程度的传输安全性。
消息安全级别
消息级安全不依赖于 WCF 协议。它通过使用标准算法加密数据来与消息数据本身一起使用。许多客户端凭据可用于消息安全级别的不同绑定,这些将在下面讨论。
WCF 中消息级别安全的客户端凭据
无– 在这里,加密用于保护消息,而不执行客户端身份验证,这意味着匿名客户端可以访问该服务。除了 BasicHttpBinding,所有 WCF 绑定都支持此客户端凭据。但是应该注意的是,对于 NetNamedPipeBinding,此客户端凭据根本不可用。
-
Windows – 在这里,消息加密和客户端身份验证都针对实时登录用户进行。在这种情况下,与所有其他 WCF 绑定不同,NetNamedPipeBinding 不可用并且 BasicHttpBinding 不提供支持。
-
用户名– 在这里,通过提供用户名对消息进行加密和保护,并且客户端在需要提供密码时进行身份验证。BasicHttpBinding 就像上面的两个客户端凭据一样,不支持 UserName,也不适用于 NetNamedPipeBinding。
-
证书– 除了消息加密,客户端和服务都获得了证书身份验证。此客户端凭据可用,并受除 NetNamedPipeBinding 之外的所有 WCF 绑定的支持。
-
IssuedToken – 来自 Cardspace 等机构的颁发令牌用于验证消息。消息的加密也在此处执行。
以下代码显示了如何在 WCF 消息安全级别/模式中配置客户端凭据。
<netTcpBinding> <binding name = "WCFMessageSecurityExample"> <security mode = "Message"> <message clientCredentialType = "None"/> </security> </binding> </netTcpBinding> <netMsmqBinding>...</netMsmqBinding> </bindings> <behaviors>...</behaviors>
在这里,必须注意传输安全模式比消息安全级别有优势,因为前者更快。它不需要任何额外的编码并提供互操作性支持,因此不会降低整体性能。
但是,从安全的角度来看,消息安全模式更加健壮,独立于协议,提供端到端的安全性。
WCF – 异常处理
WCF 服务开发人员可能会遇到一些不可预见的错误,需要以适当的方式向客户端报告。此类错误称为异常,通常通过使用 try/catch 块来处理,但同样,这是非常特定于技术的。
由于客户端关注的领域不是错误如何发生或导致错误的因素,因此使用 SOAP 故障协定将错误消息从服务传送到 WCF 中的客户端。
故障契约使客户端能够拥有服务中发生的错误的文档化视图。下面的例子可以更好地理解。
第 1 步– 使用除法运算创建一个简单的计算器服务,这将生成一般异常。
using System; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Runtime.Serialization; usingSystem.ServiceModel; usingSystem.Text; namespace Calculator { // NOTE: You can use the "Rename" command on the "Refactor" menu to change // the interface name "IService1" in both code and config file together. [ServiceContract] public interface IService1 { [OperationContract] int divide(int num1, int num2); // TODO: Add your service operations here } }
类文件的编码如下所示 –
现在,当我们尝试将数字 10 除以零时,计算器服务将抛出异常。
异常可以由 try/catch 块处理。
现在,当我们尝试将任何整数除以 0 时,它将返回值 10,因为我们已经在 catch 块中处理了它。
第 2 步– 此步骤中使用 FaultException 将异常信息从服务传达给客户端。
public int Divide(int num1, int num2) { //Do something throw new FaultException("Error while dividing number"); }
步骤 3 – 也可以创建自定义类型以使用 FaultContract 发送错误消息。下面提到了创建自定义类型必不可少的步骤 –
使用数据契约定义类型,并指定要返回的字段。
服务操作由 FaultContract 属性修饰。还指定了类型名称。
创建服务实例以引发异常并分配自定义异常属性。