65.9K
CodeProject 正在变化。 阅读更多。
Home

WCF: 从初学者的角度来看 & 教程

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.81/5 (99投票s)

2013年3月25日

CPOL

19分钟阅读

viewsIcon

275057

downloadIcon

5861

本文试图深入探讨 WCF 是什么,如何编写 WCF 服务

引言

嗯,一个月前我写了一篇关于 ASP.NET Web 服务的文章,可以在这里找到 https://codeproject.org.cn/Articles/524983/Web-Services-From-a-beginners-perspective,我收到一条评论说 .ASMX Web 服务现在很少用了,这在一定程度上是正确的。因此,我决定写一篇文章来介绍 WCF,如何编写 WCF 服务以及相关内容。

我们还是尽快开始文章吧。

嗯,WCF 代表 **Windows Communication Foundation**,它最初随 **.NET 3.0** 框架与 **WPF**、**Windows CardSpace** 和 **WorkFlow Foundation** 一起发布。

从初学者的角度来看,WCF 到底是什么意思?让我们将缩写分解成单个实体并尝试调试。它包含三个词:a) Windows b) Communication c) Foundation。

初学者可能会看一眼这些词,然后想,嗯,它涉及到 Windows 平台,用于通信和连接应用程序。嗯,他/她第一次猜对了一半……

可以总结一个想到的定义:WCF 是一种在 Windows 平台上开发和部署服务所用的技术。不同的书籍对 WCF 有不同的描述,但核心思想几乎相同,都指向在 Windows 平台上开发和部署服务。

MSDN 说,WCF 是一个构建面向服务应用程序的框架。所以 WCF basically 围绕着开发高度依赖服务的应用程序。

WCF 的必要性

接下来可能萦绕在脑海中的问题是为什么需要 WCF,它有什么用?是的,在有了初步了解后,这确实是最可能提出的问题。在 WCF 之前,有一些技术可以完成客户端和服务器之间的通信任务,它们各有优缺点。例如

  • ** .ASMX Web 服务** 允许从任何平台访问内容。
  • ** MSMQ** 允许消息排队,这样即使服务器断开连接,客户端和服务器之间的通信也是可能的。
  • ** .NET Remoting** 服务允许在 Windows 操作系统上客户端和服务器之间传输数据。

因此,如果开发人员需要开发具有上述所有功能的架构,他需要学习上述技术,这是一项艰巨的任务。因此,Microsoft 引入了 WCF 来克服这些缺点。基本上,WCF 将上述技术统一到一个编程模型中,以便于开发面向服务的架构。

我希望读者现在已经对 WCF 有了初步的了解,我们继续。

WCF 架构

下面是 WCF 架构图(来源:Google Images)

WCF 具有多层架构,即 **Contracts 层**、**Service Runtime 层**、**Messaging 层** 和 **Activation and Hosting 层**。我将尝试用简单的语言解释主要的架构内容。

Contracts 层

通俗地说,合同可以看作是两个或多个方之间就某些商品或服务达成的协议。合同将定义需要提供哪些服务,如何提供,有关地点等的详细信息。WCF Contracts 层也是如此。**它是两台机器之间关于要交换的消息的条款和条件的协议。** 让我们看看 Contracts 层中的各个项目。

  • **数据合同 (Data Contract):** 服务和客户端之间关于要交换数据的协议。它还定义了服务为了与客户端交互而应使用的数据结构和参数。
  • **消息合同 (Message Contract):** 允许控制 WCF 生成和使用的 SOAP 消息。它还提供对消息头和消息体的直接访问,以便根据需要修改 SOAP 消息。在正常情况下,开发人员通常不太关注消息合同,但当需要互操作性或需要在消息级别维护安全性时,就会出现消息合同及其使用的需求。
  • **服务合同 (Service Contract):** 定义服务支持的操作类型。它还向客户端公开某些信息,例如
  1. 消息中的数据类型。
  2. 操作的位置,或方法的定义位置
  3. 协议信息和序列化格式
  4. 消息交换模式(消息的行为是一次性、双工还是请求/响应类型)
  • **策略和绑定 (Policy and Binding):** 指定重要信息,如安全性和协议。

让我们切换到 Service Runtime 层

**Service Runtime 层** 指定和管理服务在服务运行期间发生的各种行为。服务行为,或者可以亲切地称为 **Service Behaviors**,基本上是修改和控制 WCF 运行时特性的对象。以下是 Service Runtime 层管理的 Service Behaviors 列表

  • **节流行为 (Throttling Behavior):** 确定处理的消息数量,该数量根据服务需求而变化。
  • **错误行为 (Error Behavior):** 指定在运行时任何消息出错时应采取的行动类型。
  • **元数据行为 (Metadata Behavior):** 指定元数据是否跨网络可用。
  • **实例行为 (Instance Behavior):** 指定可用于处理消息的服务实例数量。
  • **消息检查 (Message Inspection):** 在运行时完全或部分检查消息。
  • **事务行为 (Transaction Behavior):** 启用事务操作,如果在运行时任何过程失败,事务将回滚。
  • **调度行为 (Dispatch Behavior):** 确定消息的处理和分派。
  • **并发行为 (Concurrency Behavior):** 指定消息是顺序处理还是并发处理。
  • **参数筛选 (Parameter Filtering):** 筛选消息头并根据消息头的筛选器执行预设操作。

让我们讨论一下 **Messaging 层** 的内容:

Messaging 层负责交换模式及其格式。它由以下组件和通道组成

  • **WS-Security 通道 (WS-Security Channel):** 通过实现 WS-Security 规范来启用消息安全性。您可以在此处找到 WS Security 的广泛介绍:http://msdn.microsoft.com/en-us/library/ms977327.aspx
  • **WS 可靠消息通道 (WS Reliable Messaging Channel):** 保证消息的送达。
  • **编码器 (Encoders):** 为消息提供多种编码器,如 Binary、XML、Text、MTOM。
  • **HTTP 通道 (HTTP Channel):** 表明使用 HTTP 来传输消息。
  • **TCP 通道 (TCP Channel):** 表明使用 TCP 来传输消息。
  • **事务流通道 (Transaction Flow Channel):** 管理事务性消息模式。
  • **命名管道通道 (Named Pipe Channel):** 启用进程间通信。
  • **MSMQ 通道 (MSMQ Channel):** 使服务能够与 MSMQ 配合使用。

让我们继续讨论 **Hosting and Application 层**

这一层提供了多种服务激活和托管的选项。托管可以有两种类型:自托管,或托管在外部代理上,例如 IIS。此层提供的各种选项如下:

  • **Windows 激活服务 (Windows Activation Services):** 当 WCF 应用程序部署在运行 WAS 的系统上时,可以自动激活它们。
  • **.EXE:** WCF 服务也可以作为可执行文件运行。
  • **Windows 服务 (Windows Services):** WCF 服务也可以作为 Windows 服务运行。
  • **COM+:** WCF 服务也可以作为 COM+ 应用程序运行。

在讨论完架构后,让我们继续讨论 WCF 的功能,这也是一个重要的领域。

WCF 的功能

WCF 的功能可以描述如下:

  • 终结点支持
  • 改进的传输层
  • 排队支持
  • 改进的事务处理
  • 改进的安全性
  • 在各种环境中提供托管支持
  • AJAX 集成和 JSON 支持

让我们从简要讨论每个方面开始

**终结点支持 (Endpoint Support):** 终结点基本上是网络中可以发送消息的资源或实体。终结点负责客户端和服务之间的通信。终结点的元素包括

  • 用于定位服务的地址
  • 用于与服务通信的绑定
  • 用于指定与服务通信时要执行功能的合同。
  • 用于指定服务终结点运行时行为的终结点行为。

这些地址、绑定和合同通常被称为 WCF 的 ABC。

让我们来讨论一下这些 ABC。

**地址 (Addresses):** 要将消息发送到服务,您需要知道它的地址。WCF 中的地址将包含以下项目

  • 方案 (Scheme): 基本上是使用的传输协议。
  • 计算机 (Machine): 计算机的完全域名。
  • 端口 (Port): 定义服务运行的端口号。
  • 路径 (Path): 服务的路径。

例如可以写成:

  • scheme://domain_name:port/path
  • https://:8080/services/MyFirstService

在上面的例子中,一个服务在本地托管,HTTP 是传输协议,8080 是使用的端口,路径是 services/MyFirstService。

**绑定 (Bindings):** 促进客户端和服务之间的通信。指定用于访问服务的通信协议。以下是预定义绑定元素的列表:
  • basicHttpBinding
  • wsHttpBinding
  • wsDualHttpBinding
  • wsFederationHttpBinding
  • netTcpBinding
  • netNamedPipeBinding
  • netMsmqBinding
  • msmqIntegrationBinding
  • netPeerTcpBinding

嗯,我将简要讨论其中一个绑定,其他绑定的使用和实现细节可以在 MSDN 和 CP 上轻松搜索到……

basicHttpBinding: 这种类型的绑定由 WCF 服务用于配置和公开能够与 .ASMX Web 服务和客户端通信的终结点。使用的传输协议是 HTTP,而使用的消息编码器是 Text/XML。默认情况下,此绑定的安全性是禁用的,要启用安全性,需要配置 BasicHttpSecurityMode。看看下面的代码,了解如何配置 basicHttpBinding 的宿主。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="MyFirstService">
        <host>
          <baseAddresses>
            <add baseAddress="https://:8080/MyFirstservice"/>
          </baseAddresses>
        </host>
        <endpoint address="" binding="basicHttpBinding" contract="MyFirstService">
        </endpoint>
      </service>
    </services>
  </system.serviceModel>
</configuration>

让我们来讨论 WCF ABC 中的 C(合同)

**合同 (Contracts):** 客户端和服务之间的协议。3 个基本合同是:

  • **服务合同 (Service Contracts):** 定义服务的各种方法。
  • **数据合同 (Data Contract):** 定义服务方法使用的数据类型。
  • **消息合同 (Message Contract):** 在创建消息时控制消息头的能力。

**WCF 的第二个功能是改进的传输层:** 与 .ASMX Web 服务不同,WCF 服务使用多种协议在客户端和服务之间进行通信。它使用 HTTP、TCP、HTTPS、命名管道。因此,传输功能得到了改进。

**排队支持 (Queuing Support):** WCF 支持排队,允许将消息存储在队列中,然后及时发送,从而提供一致的通信状态。

**改进的事务支持 (Improved Transactional Support):** WCF 提供了改进的事务支持,这意味着如果在服务运行时任何过程失败,事务将不会提交,而是回滚。

**改进的安全性 (Improved Security):** 身份验证在 WCF 中起着重要作用,WCF 还确保在传输过程中消息的顺序不会被篡改。

**在各种环境中提供托管支持 (Hosting support on various environments):** WCF 允许在多种环境中托管服务,例如 Windows NT 服务、Windows 窗体、控制台应用程序、IIS、Windows 激活服务 (WAS)。IIS 提供了自动启动和停止服务的额外优势。

**AJAX 集成和 JSON 支持 (AJAX Integration and JSON Support):** WCF 支持 ASP.NET AJAX 和 JSON 数据格式,这允许 WCF 服务向 AJAX 客户端公开操作。JSON 是一种用于在启用了 AJAX 的服务与其客户端之间进行数据交换的数据格式。现在让我们开始编写代码部分。

背景

没有特别的先决条件,只需要安装 Visual Studio 2008 客户端即可。

Using the Code

我们将首先编写一个简单的 WCF 服务,并通过内置的 WCF 测试客户端进行测试。

  1. 打开 Visual Studio 2008,然后单击 **文件 > 新建 > 项目**。

  2. 首先创建一个**空白解决方案**。我们将在下一步添加项目。



    将解决方案命名为 MyFirstServiceSolution,并选择要存储代码的位置。

  3. VS 会创建一个解决方案,然后右键单击解决方案资源管理器 **添加 > 新项目**。

  4. 单击“添加 > 新项目”后,将打开一个包含几个选项的对话框。选择**WCF 服务库**,将名称命名为 MyServiceLibrary,选择所需的位置,然后单击“确定”。

  5. 将一个新的 WCF 服务库添加到解决方案中,其中包含 2 个默认类文件:*Service1.cs* 和 *IService1.cs*,提供 WCF 服务库的默认实现。由于我们将自行配置库,因此请删除这两个类文件。

  6. 现在,右键单击 WCF 服务库并添加一个新类文件,将其命名为 *MyService.cs*。

  7. 打开 *MyService.cs*,最初它只有一个名为 MyService 的类。我们需要定义服务需要公开什么样的数据。原始数据类型,如 int、string、float,不需要作为数据合同公开,.NET 引擎基本上都能理解;而用户定义的数据类型,如类、枚举,需要作为数据合同公开。因此,定义一个名为 Maths 的类并在其中定义两个属性。

    Data 合同类的各个成员需要作为数据成员公开。需要添加 System.Runtime.Serialization 命名空间才能使数据合同生效。然后,我们将不得不定义我们的服务合同,它确保服务公开哪些操作。添加一个接口,称之为 IMaths,并在其中添加单独的方法,这些方法将接受 Data 合同类作为参数进行处理。通过包含 System.ServiceModel 命名空间,服务合同将生效。接下来是服务的实际实现,让 MyService 类继承接口及其操作。根据需要定义操作的功能。在下面的代码中,在 MyService 类中定义了常规的算术运算。构建解决方案,应该可以毫无错误地编译。

using System;
<pre>using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.ServiceModel;
namespace MyServiceLibrary
{
    [DataContract]
    public class Maths
    {
       
        [DataMember]
        public int Number1 { get; set; }
        [DataMember]
        public int Number2 { get; set; }
    }
    [ServiceContract]
    public interface IMaths
    {
        [OperationContract]
         int Addition(Maths obj1);
        [OperationContract]
         int Subtraction(Maths obj2);
        [OperationContract]
         int Multiplication(Maths obj3);
        [OperationContract]
         int Division(Maths obj4);
    }
    class MyService:IMaths
    {
        #region IMaths Members
        public int Addition(Maths obj1)
        {
            return (obj1.Number1 + obj1.Number2);
        }
        public int Subtraction(Maths obj2)
        {
            return (obj2.Number1 - obj2.Number2);
        }
        public int Multiplication(Maths obj3)
        {
            return (obj3.Number1 * obj3.Number2);
        }
        public int Division(Maths obj4)
        {
            return (obj4.Number1 / obj4.Number2);
        }
        #endregion
    }
}
  1. 接下来,我们需要配置 *App.Config* 文件。首先,我们需要**更改服务名称**以指向 MyServiceLibrary.MyService。最初它将指向 MyServiceLibrary.Service1,但由于我们删除了 *Service1.cs* 并包含了 MyService.cs,因此我们需要在配置文件中修改服务节点。
  2. 接下来我们需要配置终结点。**更改合同名称**以指向 MyServiceLibrary.IMaths。在这里,我配置了两个不同的终结点,使服务可以通过两种方式进行通信。**使用了 wsHttpBinding 和 basicHttpBinding**。已将基地址更改为更简单的路径。

  3. 嗯,当您尝试调试 WCF 服务并进行所有更改后,可能会出现“访问被拒绝”异常,提示无法访问基址。以管理员模式调试您的 WCF 服务,然后它就会起作用。

  4. 现在让我们调试服务并看看它的工作原理。按 F5,然后将启动一个 WCF 测试客户端,如下所示。.NET 引擎会查找基址并 ping 它以获取服务的元数据,最终向我们显示服务公开的所有操作。

  5. 它显示了两次相同的操作,因为我们添加了两种不同的绑定来使用。双击任何操作,然后您可以提供参数值并调用服务。服务将相应地返回响应。例如,让我们调用“加法”操作,如下所示:

  6. 输入一些随机值并单击“调用”按钮,服务将根据操作的功能返回响应,如下所示:

在上面的例子中,我们从头开始创建了一个 WCF 服务库,它涉及到只创建一个类并在此类中实现所有内容,尽管实际上不必将所有内容都实现在同一个类中。这只是为了演示。

接下来我们将看到如何从客户端调用和使用 WCF 服务。让我们开始吧。

  1. 再次打开您的 Visual Studio,然后单击 **新建 > 网站**,如下所示。

  2. 将打开一个对话框,**选择 WCF 服务**,然后指定要存储它的位置。

  3. 该模板将向解决方案添加一个 WCF 服务项目,其中包含两个类文件 IService.cs、Service.cs 和一个 Service.svc 文件。

  4. 当我们要将服务托管在 IIS 中时,Service.svc 文件很有用。*Service.cs* 和 *IService.cs* 类将提供一些默认的服务实现。暂时将它们保持原样。构建解决方案,将 *Service.svc* 文件设置为启动页并调试。您将看到 ASP.NET 开发服务器会浏览到一个 URL 并返回类似如下的服务实现。这意味着服务已创建并正在运行。

  5. 点击页面中的 URL,您将被重定向到 **Web Services Description Language** (WSDL) 页面。

  6. 让我们查看 Service.svc 文件的结构。
    <%@ ServiceHost Language="C#" Debug="true" Service="Service" CodeBehind="~/App_Code/Service.cs" %>

    上面代码片段中粗体显示的 Service 元素指的是 *theService.cs* 文件中的 Service 类,该类进一步存储在 App_Code 文件夹下。

    以上只是对 WCF 服务及其功能的初步介绍,让我们开始编写一个 WCF 服务并尝试在控制台应用程序中调用它。

  7. 将 *IService.cs*、*Service.cs* 文件重命名为更合适的名字,例如 *IMathService.cs* 和 *MathService.cs*。相应地,您需要修改 *Service.svc* 和 *web.config* 文件中的名称。看看下面的 *IMathService.cs* 代码:
using System;

using System.Collections.Generic;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.Text;

// NOTE: If you change the interface name "IService" here, you must also update the reference to "IService" in Web.config.

[ServiceContract]

public interface IMathService

{

[OperationContract]

int Addition(Math obj1);

[OperationContract]

int Subtraction(Math obj2);

// 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 Math

{

int number1, number2;

[DataMember]

public int Number1

{

get { return number1; }

set { number1 = value; }

}

[DataMember]

public int Number2

{

get { return number2; }

set { number2 = value; }

}

}

在这里,代码中有一个 Math 类,它是一个 DataContract,因为它充当用户定义的数据类型。它有两个成员和两个属性来定义数字。然后我们有一个名为 IMathInterfaceServiceContract,它向客户端公开两个操作。

  1. 看看 *MathService.cs* 文件:
using System;

using System.Collections.Generic;

using System.Linq;

using System.Runtime.Serialization;

using System.ServiceModel;

using System.Text;

// NOTE: If you change the class name "Service" here, you must also update the reference to "Service" in Web.config and in the associated .svc file.

public class MathService : IMathService

{

#region IMathService Members

public int Addition(Math obj1)

{

return (obj1.Number1 + obj1.Number2);

}

public int Subtraction(Math obj2)

{

return (obj2.Number1 - obj2.Number2);

}

#endregion

}

MathService 类继承了 IMathService 接口,并提供了对服务公开的操作的实现。

  1. **构建解决方案,将 Service.svc 设置为启动页并调试**。它应该可以毫无错误地工作,您将在浏览器中看到如下所示的服务页面:

    它显示了如何在客户端应用程序中使用这个 WCF 服务。现在让我们尝试编写一个控制台应用程序来调用这个服务。敬请关注……

  2. 右键单击解决方案,然后单击 **添加 > 新项目**,如下所示:

  3. 将打开一个对话框,从模板列表中选择**控制台应用程序**,**将此应用程序存储在上述服务所在的同一解决方案中**,并为应用程序命名为 DemoClient。

  4. 将添加一个控制台应用程序项目到解决方案中,现在我们需要在这个应用程序中引用 WCF 服务。*右键单击引用 > 添加服务引用*。

  5. 这将打开**添加服务引用**窗口。我们需要搜索要添加的 WCF 服务,在地址文本框中输入其 URL,然后按“转到”。服务将显现,其服务和操作将列出。

    将命名空间命名为 localhost,因为它是域名(提供域名是约定俗成),然后按“确定”。服务引用将被添加到控制台应用程序项目中。

    现在打开控制台应用程序的 program.cs 文件,开始编写代码,如下所示:
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace DemoClient

{

class Program

{

static void Main(string[] args)

{

localhost.MathServiceClient obj = new DemoClient.localhost.MathServiceClient();

localhost.Math mathobj = new DemoClient.localhost.Math();

mathobj.Number1 = 10;

mathobj.Number2 = 5;

Console.WriteLine("Addition continues..");

Console.WriteLine(obj.Addition(mathobj));

Console.WriteLine("Subtraction continues..");

Console.WriteLine(obj.Subtraction(mathobj));

Console.ReadLine();

}

}

}

我将解释上面的代码。我们没有做任何特别的事情,我们只是创建了一个 MathService 客户端对象obj,并尝试访问 WCF 服务中公开的操作。由于 WCF 服务操作接受 Math 类的参数,因此我们必须创建一个 Math 类的对象,如上所示的 mathobj。这个 mathobj 将能够访问 Math 类的属性。然后我们为属性赋了一些值,并直接调用了 WCF 服务公开的各个操作 Addition() 和 Subtraction()。

  1. 现在,我们需要调试我们的控制台应用程序,看看实现是否成功。嗯,**右键单击解决方案中的控制台应用程序名称,并将其设置为“启动项目”**。

  2. 现在调试应用程序,如果一切正常,控制台应用程序将毫无错误地工作,如下所示:

    因此,我们已经非常成功地创建了一个 WCF 服务并通过客户端(在本例中为控制台应用程序)对其进行了调用。

    **我想强调一下,当向应用程序添加服务引用时会发生什么,其内部机制和工作原理**。让我们看看。

  3. 点击服务引用下的 localhost 服务,然后点击**“显示所有文件”**。

  4. **将显示文件列表**,如下所示:

  5. 点击 Reference.cs 下的 Reference.svcmap 分类,其中将包含映射、序列化和代理类等内容。例如:在下图中,我们可以看到一个名为 Math 的部分类已被创建,其中 DataMembers 已被序列化,这意味着用户定义的数据类型 Math 类在 WCF 服务被客户端调用时会被序列化,然后被引用。

  6. 再看下图,操作的实现已经创建,这意味着如果我们要在客户端应用程序中调用这些操作,我们也需要以相同的方式进行编码。此外,我们还可以看到一个名为 MathServiceClient 的代理类已被创建,我们只需要在主方法中实例化该代理类,然后就可以使用 WCF 服务公开的操作了。

要点是,当我们向客户端应用程序添加服务引用时,Visual Studio 会查看服务的 WSDL 文件,下载它,并在 Reference.cs 文件中准备类似的方法和函数。之后,我们只需要在我们的主应用程序中引用这些方法和函数。

我想我现在已经到了文章的结尾。我已经讨论了:
  • WCF 是什么,它的架构、功能、用途。
  • 如何从头开始创建 WCF 服务库并通过 WCF 测试客户端进行测试。
  • 如何创建 WCF 服务并在客户端应用程序中调用它。

在文章的下一部分,我将讨论如何在 ASP.NET Web 应用程序中调用 WCF 服务以及如何使用 ASP.NET AJAX 编写 WCF 服务(这篇文章很快就会发布)……

兴趣点

嗯,在写这篇文章的过程中我学到了很多。

我希望与读者分享的一个技巧是,当您声明 DataContractServiceContract 时,如果这些术语没有高亮显示(显示错误),可能是因为我们没有包含所需的命名空间。您可以按 Ctrl+点键来实施命名空间,而不是手动输入。看看下面的内容:

当您尝试重构接口时,也同样适用。

添加了一个 zip 文件夹,其中包含本文引用的源代码。它基本上有两个文件夹:MyFirstServiceSolution(从头开始编写的 WCF 服务库)和 WCF_WebService(包含一个 WCF 服务和一个控制台应用程序)。请好好利用它。

我希望将部分功劳归于 **MSDN 和 C# 和 ASP.NET 的黑皮书**,我从中参考了某些定义和内容。

本文的续篇可以在这里找到:https://codeproject.org.cn/Articles/570036/WCF-From-a-Beginners-perspective-and-a-tutorial-Se。它帮助读者在 ASP.NET 网站中调用 WCF 服务,并创建支持 AJAX 的 WCF 服务。请查看并享受编写 WCF 服务的乐趣。

历史

WCF 文章 1.0 版本完成于 2013 年 3 月 25 日。

© . All rights reserved.