理解 Windows Communication Foundation (WCF) 的初学者教程






4.77/5 (275投票s)
我们将尝试了解 WCF 背后的基本概念,并尝试实现一个小型 WCF 服务。
引言
本文档是对 Windows Communication Foundation (WCF) 的介绍。我们将尝试了解 WCF 背后的基本概念,并尝试实现一个小型 WCF 服务。我们还将演示一些小型示例,说明如何使用 WCF 服务。
背景
正如我在之前关于 Web 服务 的文章中所说,应用程序之间的通信非常重要。Web 服务提供了一种有效的促进应用程序之间通信的方式。但是 Web 服务也有其局限性。Web 服务的主要局限性在于通信只能通过 HTTP 进行。Web 服务的第二个局限性是它提供单工通信,无法使用 Web 服务实现半双工或全双工通信。
当我们发现无法使用 Web 服务实现我们想要的目标时,Windows Communication Foundation (WCF) 就派上用场了,即支持其他协议,甚至支持双工通信。通过 WCF,我们可以定义一次服务,然后对其进行配置,使其能够通过 HTTP、TCP、IPC 甚至消息队列进行使用。我们可以使用服务器端脚本 (ASP.NET)、JavaScript 对象表示法 (JSON) 甚至 REST (Representational State Transfer) 来消费 Web 服务。
下表说明了 Web 服务和 WCF 服务之间的区别
Web服务 | WCF 服务 |
通信只能通过 HTTP 进行 | 通信可以通过 HTTP、TCP、IPC 甚至 MSMQ 进行。 |
只能进行单工和请求-响应通信 | 可以配置为进行单工、请求-响应甚至全双工通信。 |
它们在 HTTP 上以无状态方式运行,并托管在 IIS 等 Web 服务器中 | 它们可以以多种方式托管,如在 IIS 中、在 Windows 服务中,甚至可以自托管。 |
注意:除了这些区别之外,还有一些与实例管理、会话和数据表示/序列化相关的其他区别。此处不作讨论,因为这些内容对初学者来说可能会有些离题。
WCF 服务可以形象地理解为
理解基础知识
当我们说 WCF 服务可以用于通过不同协议以及从不同类型的应用程序进行通信时,我们需要了解如何实现这一点。如果我们想从一个应用程序使用 WCF 服务,那么我们有三个主要问题:
- 从客户端的角度来看,WCF 服务位于何处?
- 客户端如何访问服务,即协议和消息格式是什么?
- 服务向客户端提供哪些功能?
一旦我们有了这三个问题的答案,创建和消费 WCF 服务就会容易得多。WCF 服务具有终结点 (endpoint) 的概念。WCF 服务提供客户端应用程序可以用来与 WCF 服务通信的终结点。上述问题的答案就是 WCF 服务的 ABC,事实上也是 WCF 服务的主要组成部分。因此,让我们逐个解决每个问题。
地址 (Address):与 Web 服务一样,WCF 服务也提供一个 URI,客户端可以使用该 URI 来访问 WCF 服务。此 URI 称为 WCF 服务的地址。这将为我们解决“WCF 服务位于何处?”的第一个问题。
绑定 (Binding):一旦我们能够找到 WCF 服务,我们就应该考虑如何(从协议的角度)与服务通信。绑定定义了 WCF 服务如何处理通信。它还可以定义其他通信参数,如消息编码等。这将为我们解决“如何与 WCF 服务通信?”的第二个问题。
契约 (Contract):现在我们只剩下关于 WCF 服务所提供功能的问题了。契约定义了 WCF 服务向客户端提供的公共数据和接口。
使用代码
作为一名 ASP.NET 开发人员,我们可能会需要使用 WCF 服务,或者可能需要编写 WCF 服务。接下来,我们将实现一个小型 WCF 服务,看看如何实现 WCF 的 ABC。然后,我们将编写一个小型应用程序来消费这个 WCF 服务。
我们将创建的服务将为 Pair
数据类型提供算术运算。这个 Pair
类型也将由我们的服务暴露给应用程序。我们将仅为 Pair
数据类型提供加法和减法功能。
注意:我们将把这个 WCF 服务托管在一个 ASP.NET 网站中,即 IIS 托管,并从一个 ASP.NET 网站中消费它。所以,让我们创建一个空的 ASP.NET 网站,然后向其中添加一个 WCF 服务。
创建 WCF 服务
让我们从 WCF 服务的数据契约 (Contract) 部分开始。我们需要从服务中公开一个 Pair
数据类型,因此这个类必须用 DataContract
属性进行装饰。此属性指定该数据类型可供 WCF 服务的消费者使用。此外,该类的公共属性必须用 DataMember
属性进行装饰,以指定客户端可以使用这些属性,并指示它们将需要序列化和反序列化。
[DataContract]
public class Pair
{
int m_first;
int m_second;
public Pair()
{
m_first = 0;
m_second = 0;
}
public Pair(int first, int second)
{
m_first = first;
m_second = second;
}
[DataMember]
public int First
{
get { return m_first; }
set { m_first = value; }
}
[DataMember]
public int Second
{
get { return m_second; }
set { m_second = value; }
}
}
现在我们已经指定了服务所公开的数据契约。接下来是指定服务契约和该服务的主要操作。让我们创建一个接口,其中将列出该服务提供的主要功能。然后,我们将必须用 ServiceContract
属性装饰此接口,以指定此接口由该服务公开,并且可供客户端使用。
然后,我们将为该服务提供的所有主要操作编写方法,并用 OperationContract
属性装饰它们,以指定此接口的这些操作可供客户端使用。
public interface IPairArihmeticService
{
[OperationContract]
Pair Add(Pair p1, Pair p2);
[OperationContract]
Pair Subtract(Pair p1, Pair p2);
}
现在我们已经指定了我们小型服务的所有 DataContract
、ServiceContract
和 OperationContract
。现在服务中剩下的主要工作是实现功能。为此,让我们创建一个小型类来实现我们刚刚创建的接口。
public class PairArihmeticService : IPairArihmeticService
{
Pair IPairArihmeticService.Add(Pair p1, Pair p2)
{
Pair result = new Pair();
result.First = p1.First + p2.First;
result.Second = p1.Second + p2.Second;
return result;
}
Pair IPairArihmeticService.Subtract(Pair p1, Pair p2)
{
Pair result = new Pair();
result.First = p1.First - p2.First;
result.Second = p1.Second - p2.Second;
return result;
}
}
让我们尝试想象一下我们到目前为止所做的工作。这张类图将显示我们创建的类,并用属性对其进行装饰,以指定数据契约、服务契约和操作契约。
我们的契约部分已经声明和定义。现在让我们看看如何配置其他内容。我们需要让此服务对客户端应用程序可见,并让客户端应用程序从中提取元数据信息。为此,我们需要在 web.config 中指定服务行为。
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
这里需要注意的重要一点是 httpGetEnabled="true"
,它使此服务在客户端请求时能够提供其元数据。现在,让我们构建此网站来构建我们的 WCF 服务。让我们将 .SVC 文件设置为启动页并运行网站,看看会发生什么。
消费 WCF 服务
我们已经了解了如何创建 WCF 服务。现在让我们看看如何消费 WCF 服务。让我们从在同一解决方案中添加一个默认的 ASP.NET 网站开始。然后,我们需要为我们刚刚创建的 WCF 服务添加一个服务引用。
添加此服务引用主要会做两件事:
- 在 web.config 文件中创建用于访问此服务的地址和绑定部分。
- 为我们创建
proxy
类以访问服务。
因此,让我们先看看 web.config 中的地址和绑定,以完成 WCF 服务的 ABC 部分。
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHttpBinding_IPairArihmeticService"/>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://:1062/WcfTestWebSite/PairArihmeticService.svc"
binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IPairArihmeticService"
contract="PairServiceReference.IPairArihmeticService"
name="BasicHttpBinding_IPairArihmeticService"/>
</client>
</system.serviceModel>
此 web.config 显示了 WCF 服务的地址、用于使用 Web 服务的绑定以及此 Web 服务公开的契约。所有这些都是通过从服务中提取元数据生成的。
现在让我们看看如何使用生成的代理类。我们将使用这个代理类来调用 WCF 服务的方法,然后从中提取结果。
PairServiceReference.Pair p1 = new PairServiceReference.Pair();
p1.First = Convert.ToInt32(txtP1First.Text);
p1.Second = Convert.ToInt32(txtp1Second.Text);
PairServiceReference.Pair p2 = new PairServiceReference.Pair();
p2.First = Convert.ToInt32(txtP2First.Text);
p2.Second = Convert.ToInt32(txtp2Second.Text);
PairServiceReference.PairArihmeticServiceClient pairServiceClient =
new PairServiceReference.PairArihmeticServiceClient();
PairServiceReference.Pair addResult = pairServiceClient.Add(p1, p2);
PairServiceReference.Pair minusResult = pairServiceClient.Subtract(p1, p2);
lblsum.Text = addResult.First.ToString() + ", " + addResult.Second.ToString();
lblminus.Text = minusResult.First.ToString() + ", " + minusResult.Second.ToString();
注意:上面的代码片段引用了控件 ID。请参阅源代码了解详情。
现在我们已经成功地从我们的 ASP.NET 网站消费了 WCF 服务。在结束之前,让我们构建此网站并查看结果。
注意:在使用源代码时,必须更新并重新添加服务引用,因为正在使用的服务的地址特定于我的系统。在其他系统上可能会有所不同。
关注点
我们在这里试图做的是理解 WCF 服务的一些基本概念。我们创建了一个示例 WCF 服务。我们还创建了一个示例网站来消费 WCF 服务。
在托管、访问和使用 WCF 服务方面有多种选择。我们只看了一种特定的方式。一个很好的练习是更改此服务,使其可以通过 AJAX 访问。WCF 服务更多地涉及一些代码和一些配置。如果我们想为该服务使用不同的 ABC 集,那么代码(逻辑)将不会改变,唯一需要的更改将是配置。
历史
- 2012 年 6 月 18 日:初版。