Windows Communication Foundation FAQ 快速入门 - 第二部分






4.67/5 (52投票s)
Windows Communication Foundation FAQ 快速入门 -
更新了 WCF-第一部分、WPF、WWF、WCF 跟踪 FAQ、8 步在 WCF BasicHttpBinding 上启用 Windows 身份验证、BasicHttpBinding 和 WsHttpBinding 的区别以及 WCF FAQ 第三部分 – 10 个安全相关 FAQ、SilverLight FAQ 第一部分和第二部分、LINQ 第一、二、三部分以及使用 LINQ to SQL 实现一对多和一对一关系的链接。
Windows Communication Foundation FAQ 快速入门 - 第二部分
引言 您能解释一下 WCF 中的双工契约吗? 我们如何在单个服务器上使用两种不同的协议托管服务? 我们如何在 WCF 中使用 MSMQ 绑定? 您能解释一下 WCF 中的事务吗? WCF 提供了哪些不同的事务隔离级别? 我们可以使用 MSMQ 进行事务处理吗? MSMQ 可以进行双向通信吗? 什么是易失性队列? 什么是死信队列? | 这个 10 分钟的短视频解释了如何在 WCF 服务中使用 SSL 实现传输安全。![]() |
引言
在本节中,我们将快速浏览 WCF 的 FAQ。我相信阅读完本文后,您将对 WCF 的基础知识有很好的理解。
单击 此处 查看 Windows Communication Framework (WCF) - 第一部分
单击 此处 查看 Windows Presentation Foundation (WPF)
单击 此处 查看 Windows Workflow Foundation (WWF)
单击 此处 查看 WCF 跟踪 FAQ
单击 此处 查看在 WCF BasicHttpBinding 上启用 Windows 身份验证的 8 个步骤
单击 此处 查看 BasicHttpBinding 和 WsHttpBinding 之间的区别
单击 此处 查看 WCF FAQ 第三部分 – 10 个安全相关 FAQ
单击 此处 查看 21 个重要的 SilverLight FAQ - 第一部分
单击 此处 查看(动画和转换)SilverLight FAQ - 第二部分
单击 此处 查看使用 LINQ to SQL 实现一对多和一对一关系
LINQ FAQ 第一部分:- LINQNewbie.aspx
LINQ FAQ 第二部分:- LINQFAQPart2
LINQ FAQ 第三部分:- LINQ FAQ 第三部分
您能解释一下 WCF 中的双工契约吗?
在双工契约中,当客户端发起操作时,服务器端会提供一个回调 URI 引用回客户端。所以客户端使用代理类发起调用,当服务器完成工作后,它会通过回调通道通知客户端。这就是 WCF 中的双工消息传递。如果您还记得之前的问题,我们那时无法知道服务器何时完成了它的任务。
图 18:- 双工服务代码
让我们通过一个小的示例来理解双工的概念。代码片段如上图所示。我们将扩展之前在第一个问题中展示的示例,只是现在我们将在 `doHugeTask` 完成后向客户端提供通知。
第一步是修改服务类。上面是服务类的代码片段。同样,我们给它们编号以便我们可以逐行理解如何实际实现。下面是逐号的解释:
1 - 在服务契约属性中,我们需要指定回调契约属性。这个回调契约属性将包含定义回调的接口。
2 - 这是客户端调用的接口。为了使其异步,我们在 `doHugeTask` 方法上定义了一向属性。
3 - 这是最重要的接口。因为它形成了服务器和客户端之间的通信桥梁。服务器将使用 `Completed` 方法调用客户端。客户端需要在客户端提供 `completed` 方法的实现,服务器将在 `doHugeTask` 方法完成后调用该方法。
4 和 5 - 在这里我们实现了 `IDuplex` 接口并提供了 `doHugeTask()` 方法的实现。
6 - 这是一个重要步骤。`OperationContext.Current.GetCallBackChannel` 将用于回调客户端。
7 - 我们将使用 HTTP 协议公开服务。在本示例中,因为我们要进行双工通信,所以我们需要使用 `wsDualHttpBinding` 而不是仅仅使用简单的 `Http Binding`。然后将这个新的绑定配置分配给托管服务的终结点。
这完成了双工的服务端解释。
图:- 19 双工客户端代码
上面是客户端的代码片段。所以让我们用数字来解释上面的代码:
1- 我们实现了 `completed` 方法。这是服务器在 `doHugeTask` 完成后将调用的回调方法。
2- 在此步骤中,我们创建了 `Instance Context` 类的对象。`Instance Context` 代表服务的上下文信息。`Instance Context` 的主要用途是处理传入的消息。简而言之,代理用于向服务器发送消息,而 `Instance Context` 用于接收传入的消息。
3 - 在此步骤中,我们将 `Instance Context` 对象传递给代理的构造函数。这很有必要,因为服务器将使用相同的通道与客户端通信。
4 - 此部分显示了两个窗口。上面的窗口是服务器的输出,下面的窗口是客户端的输出。您可以在下面的窗口中看到服务器已成功回调客户端。
注意:- 您可以在 WCFDuplex 文件夹中找到相同的源代码。随时进行实验。尝试使用 WCF 双工基础知识创建一个简单的客户端到客户端聊天项目,我相信您的疑问将彻底消除。
我们如何在单个服务器上使用两种不同的协议托管服务?
让我们首先理解这个问题到底意味着什么。假设我们已经创建了一个服务,并且希望使用 HTTP 和 TCP 来托管这个服务。您可能在想,为什么要用两种不同的协议来托管服务呢?当我们托管服务时,多种类型的客户端都会使用它,而它们可能有自己的通信协议。一个好的服务应该能够根据使用它的客户端来降级或升级其协议。
让我们通过一个小的示例来托管 `ServiceGetCost` 服务,使用 TCP 和 HTTP 协议。
注意:- 您可以在提供的 CD 的“WCFMultipleProtocolGetHost”文件夹中找到下面的示例。
下面是从同一示例中粘贴的代码片段?像往常一样,我们已经给它们编号,下面是解释:
1 和 2 - 由于我们将服务托管在两种协议上,所以我们需要创建两个 `Uri` 对象。您也可以通过配置文件来指定 URI。在创建服务主机对象时,将这两个 `Uri` 对象作为构造函数参数传递。
图 20:- 多协议托管的服务端代码
3 – 在配置文件中,我们需要定义两个绑定和终结点,因为我们将服务托管在多种协议上。
一旦我们完成了服务端编码,就是时候创建一个客户端了,通过它可以切换协议并查看结果。下面是多协议托管的客户端代码片段。
图 21:- 多协议客户端代码
让我们来理解这段代码:
1 - 在生成的配置文件中,我们添加了两个终结点。当生成配置文件时,它只为一种协议生成。另一个终结点需要手动添加。
2 - 为了测试这一点,我们有一个列表框,其中包含终结点中给出的名称值。
3 - 在列表框的选择事件中,我们加载了选定的协议。选定的协议字符串需要提供给代理类,最后调用代理类的 `GetTotalCost`。
我们如何在 WCF 中使用 MSMQ 绑定?
首先让我们理解为什么 MSMQ 会出现,然后其余的就会顺理成章。让我们考虑一个场景,您的客户端需要将数据上传到中央服务器。如果一切顺利,并且服务器 24 小时都在运行,那么就不会有问题。如果服务器不可用,客户端将失败,数据将不会被传递。这就是 MSMQ 出现的原因。它消除了对服务器的持久连接的需要。因此,您所做的是部署一个 MSMQ 服务器,让客户端将消息发布到这个 MSMQ 服务器。当您的实际服务器运行时,它只需从队列中提取消息。简而言之,客户端和服务器不需要同时启动并运行。在 WCF 中,我们有客户端和服务模型,而在实际应用中,两者同时不可用是非常普遍的。
为了使用 MSMQ,您需要通过点击“安装 Windows 组件”并选择“MSMQ 队列”来安装消息队列。完成后,我们就可以开始使用 WCF 来创建 MSMQ 示例了。
图 22:- MSMQ 安装
这个示例很简单。我们从客户端发送一些消息,然后让服务器离线。由于服务器离线,消息将被发布到 MSMQ 服务器。然后我们运行服务器服务,服务应该会提取消息并显示出来。
图 23:- MSMQ 服务端代码演练
上面的片段是服务端代码。所以让我们理解整个片段:
1 – 首先是消息队列的名称,如果服务器未运行,消息将发送到这里。服务器名称可以从配置文件中获取。您可以在上面的片段中看到我们在 `App.config` 文件中定义了 `Mismanage`。
2 – 我们首先检查这个队列是否存在,如果存在就继续。如果不存在,则创建队列。请注意,您需要导入 `using System.Messaging` 命名空间。然后,如果队列不存在,我们可以使用 `Message Queue` 来创建队列。
3 – 最让您惊讶的第一件事是,为什么我们要创建一个带有 HTTP 协议的 URI,因为我们要使用 MSMQ。好吧!这有点棘手,但也很有趣。我们知道,为了连接到此服务,我们需要使用 SVCUTIL 生成客户端代理。因此,这个 URI 将帮助我们做到这一点。它实际上并不会被客户端用来连接。
4 – 我们需要我们的终结点和 MSMQ 绑定。
5 和 6 – 同样,像往常一样,我们需要一个接口和它的实现。在实现中,我们创建了一个名为 `sendMessage` 的方法。
在执行完上述步骤后,运行服务器并使用 SVCUTIL 工具生成客户端代理。
现在来到最后一步,创建一个客户端。您需要做的唯一更改是在 `app.config` 中将地址更改为 MSMQ 服务器。在这里,我们只是循环了十次并发送了一个离线消息。请注意要保持服务器离线。
图 24:- MSMQ 客户端代码
现在您可以转到计算机管理,您可以看到您的队列消息正在等待服务器读取。运行服务器,下面的应该是输出。如果您再次查看,您会发现队列中没有消息了。
图 25:- MSMQ 服务端显示
理解何时使用 MSMQ 协议是重要的概念之一。当预期客户端和服务器不会同时可用时,这是最佳选择。
您能解释一下 WCF 中的事务吗?
WCF 提供了哪些不同的事务隔离级别?
事务确保一组相关的活动作为一个单一的原子单元发生。简单来说,单元中的每一项活动要么必须全部成功,要么必须全部失败。WCF 提供了一个中央事务系统,可用于处理事务操作。WCF 提供的一个重要功能是为数据库和非数据库活动提供单一的统一事务系统。例如,`BeginTrans` 和 `CommitTrans` 是数据库相关的语法,但我们不能将它们用于其他活动,比如我们想在一个事务中将所有消息上传到 MSMQ 服务器。需要注意的是,WCF 事务遵循 WS 规范。这意味着任何其他语言(如 JAVA)都可以利用此事务……我认为这是 WCF 拥抱其他语言的最佳部分。
图 26:- WCF 中的事务
为了支持事务,服务本身应该首先支持事务。上面是服务器服务和客户端的简单代码片段以及相应的解释:
上面的代码片段是服务器服务的,下面的代码片段是客户端的。
1 - 在接口级别,操作契约被 `[TransactionFlow]` 属性修饰。它有三个值:`Allowed`(表示操作可以或可能不用于事务)、`NotAllowed`(表示从不用于事务)和 `Required`(表示服务只能用于事务)。下面的代码片段目前表示此服务只能与事务一起使用。
2 - 在这一部分,`[ServiceBehavior]` 属性指定了事务隔离级别属性。事务隔离指定了与其他应用程序最兼容的隔离程度。所以让我们回顾一下您可以在事务隔离中提供哪些不同的级别。
受事务影响的数据称为易失性数据。
Chaos:- 更高级别隔离的事务的待定更改不能被覆盖。
Read Committed:- 易失性数据可以被修改,但在事务期间不能被读取。
Read Uncommitted:- 在事务期间,易失性数据可以被读取和修改。
Repeatable Read:- 在事务期间,易失性数据可以被读取但不能被修改,并且可以添加新数据。
Serializable:- 易失性数据只能被读取。但是,不允许修改和添加新数据。
Snapshot:- 易失性数据可以被读取。但是,在修改数据之前,它会验证是否有其他事务更改了数据。如果有,则会引发错误。
默认情况下,`System.Transactions` 基础结构创建 `Serializable` 事务。
3 - 这定义了服务内的事务行为。[OperationBehavior] 有一个名为 `TransactionScope` 的属性。`TransactionScope` 设置表示操作必须在事务范围内调用。您还可以看到 `TransactionAutoComplete` 设置为 `true`,这表示如果没有错误,事务将默认完成。如果您不将 `TransactionAutoComplete` 设置为 `true`,您将需要调用 `OperationContext.Current.SetTransactionComplete()` 来完成事务。
现在让我们演练一下客户端代码的服务。
4 和 5 - 您可以看到,从客户端,我们需要在调用 `UpdateAccounts` 方法时定义隔离级别和范围。
我们可以使用 MSMQ 进行事务处理吗?
在进行 MSMQ 处理时,项目中可能会出现这种情况,即我们希望所有消息都被上传到 MSMQ,或者所有消息都从 MSMQ 读取。在任何消息从 MSMQ 读取后,它都会从队列中删除。因此,有时这可能很关键,如果读取或上传消息时出现异常。如前所述,WCF 事务可以应用于数据库以及 MSMQ 等其他操作。所以让我们通过一个小的示例来理解这一点。
下面是 MSMQ 事务的编号代码片段。
1 - `SendMessage` 是服务中公开的方法。我们将此方法标记为 `TransactionScopeRequired=true`。
2 - 在客户端,我们使用了 `TransactionScope` 来表示我们正在启动一个到 MSMQ 服务器的事务。您可以看到我们使用 `SendMessage` 将消息发送到 MSMQ。
3- 之后,我们可以使用 `Complete` 或 `Dispose` 方法来完成或回滚事务。
下面的 MSMQ 事务代码确保要么所有消息都发送到服务器,要么都不发送。从而满足了事务的一致性属性。
图 27:- 事务代码片段
MSMQ 可以进行双向通信吗?
是
什么是易失性队列?
项目中存在一些情况,您希望消息能够及时送达。消息的及时送达比丢失消息更重要。在这些情况下,可以使用易失性队列。
下面是显示如何配置易失性队列的代码片段。您可以看到绑定配置属性设置为 `Volatile Binding`。这段代码可以确保消息按时送达,但有可能丢失数据。
<appSettings>
<!-- 使用 appSetting 配置 MSMQ 队列名称 -->
<add key="queueName" value=".\private$\ServiceModelSamplesVolatile" />
</appSettings>
<system.serviceModel>
<services>
<service name="Samples.StockTickerServ"
behaviorConfiguration="CalculatorServiceBehavior">
...
<!-- 定义 NetMsmqEndpoint -->
<endpoint address="net.msmq:///private/ServiceModelSamplesVolatile"
binding="netMsmqBinding"
bindingConfiguration="volatileBinding"
contract="Samples.InterfaceStockTicker" />
...
</service>
</services>
<bindings>
<netMsmqBinding>
<binding name="volatileBinding"
durable="false"
exactlyOnce="false"/>
</netMsmqBinding>
</bindings>
...
</system.serviceModel>
什么是死信队列?
队列的主要作用是您不需要客户端和服务器同时运行。因此,消息可能会在队列中停留很长时间,直到服务器或客户端读取它。但也有一些情况,消息在某个时间点后就变得没有用了。因此,这些类型的消息如果在规定时间内未送达,就不应发送给用户。
下面是定义消息在队列中应停留多长时间的配置片段。
<bindings>
<netMsmqBinding>
<binding name="MyBindings"
deadLetterQueue="Custom"
customDeadLetterQueue="net.msmq:///private/ServiceModelSamples"
timeToLive="00:00:02"/>
</netMsmqBinding>
如需进一步阅读,请观看以下面试准备视频和分步视频系列。