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

初学者教程:创建 WCF REST 服务

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (102投票s)

2013 年 4 月 3 日

CPOL

6分钟阅读

viewsIcon

634975

downloadIcon

24680

在本文中,我们将尝试了解 WCF REST 服务是什么以及如何创建它。

引言

在本文中,我们将尝试了解 WCF REST 服务是什么。我们将从服务开发人员的角度了解创建启用 REST 的 WCF 服务需要什么。我们将了解如何使用和消费 restful WCF 服务。

免责声明:这是一篇相当老的文章(差不多 5 年了)。我想在这里做个免责声明 - 这不是一个 REST 服务。本文讨论了 REST,但最终使用 WCF 创建了基于 HTTP 的服务。这个创建的 WCF 服务不遵循 REST 架构指南。对此表示歉意(我想我们都会随着时间的推移变得更聪明)。我将更新这篇文章,但在此之前,我觉得这个免责声明应该存在。 

背景

REST 概述

REST 代表 Representational State Transfer(表述性状态传输)。这是一种在分布式环境中交换数据的协议。REST 背后的主要思想是,我们应该将分布式服务视为一种资源,并且我们应该能够使用简单的 HTTP 协议对该资源执行各种操作。

当我们谈论数据库作为资源时,我们通常会谈论 CRUD 操作。即 Create(创建)、Retrieve(检索)、Update(更新)和 Delete(删除)。现在 REST 的哲学是,对于远程资源,所有这些操作都应该是可能的,并且它们应该可以使用简单的 HTTP 协议实现。

现在基本的 CRUD 操作以以下方式映射到 HTTP 协议

  • GET:这映射到 CRUD 操作的 R(检索) 部分。这将用于从远程资源检索所需数据(数据的表示)。
  • POST:这映射到 CRUD 操作的 U(更新) 部分。此协议将更新远程服务器上数据的当前表示。
  • PUT:这映射到 CRUD 操作的 C(创建) 部分。这将为当前发送到服务器的数据创建一个新条目。
  • DELETE:这映射到 CRUD 操作的 D(删除) 部分。这将从远程服务器删除指定的数据。

因此,如果我们以一个包含图书列表数据库的远程资源为例。图书列表可以使用以下 URL 检索

www.testwebsite.com/books

要检索任何特定的书籍,假设我们有一些可用于检索书籍的 ID,可能的 URL 可能如下所示

www.testwebsite.com/books/1

由于这些是 GET 请求,数据只能从服务器检索。要执行其他操作,如果我们使用类似的 URI 结构和 PUTPOST DELETE 操作,我们应该能够从服务器创建、更新和删除资源。我们将在实现部分看到如何完成此操作。

注意: 使用这些 URL 结构可以执行更多复杂的查询。我们不会讨论可以使用各种 URL 模式执行的完整查询操作集。

使用代码

现在我们可以创建一个简单的 WCF 服务,它将在某个数据库上实现所有基本的 CRUD 操作。但是要使此 WCF 服务与 REST 兼容,我们需要在配置、服务行为和契约中进行一些更改。让我们看看我们将创建什么样的 WCF 服务,然后我们将看到如何使其在 REST 协议上可用。

创建启用 REST 的 ServiceContract

我们将创建 Books 表并尝试在此表上执行 CRUD 操作。 

 

为了在服务中执行数据库操作,让我们使用 Entity Framework。这可以通过使用 ADO.NET 调用或其他 ORM 来很好地完成,但我选择了 Entity Framework。(请参阅此文章了解 Entity Framework: 绝对初学者 Entity Framework 简介[^])。生成的实体将如下所示。 

 

现在服务契约将包含 CRUD 操作的函数。让我们为该服务创建 ServiceContract

[ServiceContract]
public interface IBookService
{
    [OperationContract]
    List<Book> GetBooksList();

    [OperationContract]
    Book GetBookById(string id);

    [OperationContract]
    void AddBook(string name);

    [OperationContract]
    void UpdateBook(string id, string name);

    [OperationContract]
    void DeleteBook(string id);
}

目前这是一个非常简单的服务契约,为了指示单个操作可以通过 REST 协议调用,我们需要用附加属性来修饰这些操作。那些将在 HTTP GET 协议上调用的操作,我们需要用 WebGet 属性来修饰它们。那些将由 POST、PUT、DELETE 等协议调用的操作将用 WebInvoke 属性来修饰。

理解 UriTemplate

现在在将这些属性添加到这些操作之前,让我们首先了解 UriTemplate 的概念。UriTemplate 是 WebGet 和 WebInvoke 属性的一个属性,它将帮助我们将来自 HTTP 协议的参数名称与 ServiceContract 的参数名称进行映射。例如,如果有人使用以下 URI

localhost/testservice/GetBookById/2

我们需要将此第一个参数映射到函数的 id 变量。这可以通过使用 UriTemplate 来完成。此外,我们可以专门为 URI 更改函数名称,并且 URI 函数名称将映射到实际的函数名称,即如果我们像这样调用相同的 URL

localhost/testservice/Book/2

那么我们可以通过将操作的 UriTemplate 指定为

[OperationContract]
[WebGet(UriTemplate  = "Book/{id}")]
Book GetBookById(string id);

按照同样的思路,让我们也为其他方法定义 UriTemplate

[ServiceContract]
public interface IBookService
{
    [OperationContract]
    [WebGet]
    List<Book> GetBooksList();

    [OperationContract]
    [WebGet(UriTemplate  = "Book/{id}")]
    Book GetBookById(string id);

    [OperationContract]
    [WebInvoke(UriTemplate = "AddBook/{name}")]
    void AddBook(string name);

    [OperationContract]
    [WebInvoke(UriTemplate = "UpdateBook/{id}/{name}")]
    void UpdateBook(string id, string name);

    [OperationContract]
    [WebInvoke(UriTemplate = "DeleteBook/{id}")]
    void DeleteBook(string id);
}

实现服务  

现在服务实现部分将使用 Entity Framework 生成的上下文和实体来执行所有相应的操作。

public class BookService : IBookService
{
    public List<Book> GetBooksList()
    {
        using (SampleDbEntities entities = new SampleDbEntities())
        {
            return entities.Books.ToList();
        }
    }

    public Book GetBookById(string id)
    {
        try
        {
            int bookId = Convert.ToInt32(id);

            using (SampleDbEntities entities = new SampleDbEntities())
            {
                return entities.Books.SingleOrDefault(book => book.ID == bookId);
            }
        }
        catch
        {
            throw new FaultException("Something went wrong");
        }
    }

    public void AddBook(string name)
    {
        using (SampleDbEntities entities = new SampleDbEntities())
        {
            Book book = new Book { BookName = name };
            entities.Books.AddObject(book);
            entities.SaveChanges();
        }
    }

    public void UpdateBook(string id, string name)
    {
        try
        {
            int bookId = Convert.ToInt32(id);

            using (SampleDbEntities entities = new SampleDbEntities())
            {
                Book book = entities.Books.SingleOrDefault(b => b.ID == bookId);
                book.BookName = name;
                entities.SaveChanges();
            }
        }
        catch
        {
            throw new FaultException("Something went wrong");
        }
    }

    public void DeleteBook(string id)
    {
        try
        {
            int bookId = Convert.ToInt32(id);

            using (SampleDbEntities entities = new SampleDbEntities())
            {
                Book book = entities.Books.SingleOrDefault(b => b.ID == bookId);
                entities.Books.DeleteObject(book);
                entities.SaveChanges();
            }
        }
        catch
        {
            throw new FaultException("Something went wrong");
        }
    }
}

Restful WCF 服务配置

现在从 ServiceContract 的角度来看,服务已准备好服务 REST 请求,但要通过 REST 访问此服务,我们还需要对服务行为和绑定进行一些更改。

要使服务通过 REST 协议可用,需要使用的绑定是 webHttpBinding。此外,我们需要设置端点的行为配置并在 endpointBehavior 中定义 webHttp 参数。因此,我们最终的配置将如下所示

 

测试服务

 

现在,为了测试服务,我们只需运行服务并使用 URL 来检索数据。让我们看看我们的 GET 操作的实际情况。

 

现在测试获取单个记录的查询

 

我们已经看到,我们在浏览器中以 XML 格式收到了响应。我们可以使用这些 URL 和 HTTP 协议,而无需通过添加服务引用来使用此服务。

注意: 这里我没有演示 POST、PUT 和 DELETE 的其他操作,但它们都相当直接,一个简单的 HTML 页面使用所需的协议和指定的参数名称发送数据即可执行操作。

使用 JSON

我们还可以将响应和请求格式更改为使用 JSON 而不是 XML。为此,我们需要指定 WebInvoke 属性的属性。

  • RequestFormat:默认值为 WebMessageFormat.XML。要将其更改为 JSON 格式,需要将其设置为 WebMessageFormat.Json
  • ResponseFormat:默认值为 WebMessageFormat.XML。要将其更改为 JSON 格式,需要将其设置为 WebMessageFormat.Json。

让我们在我们的服务契约中再创建一个名为 GetBooksNames 的操作,并将此方法的 ResponseFormat 设置为 Json。

[OperationContract]
[WebGet(ResponseFormat=WebMessageFormat.Json]
List<string> GetBooksNames();

响应现在将以 JSON 格式显示。 

 

现在我们已经有了一个 WCF REST 服务。

 

注意: Visual Studio 中也有现成的模板用于创建 WCF 数据服务,它为我们提供了一种轻松创建启用 REST 的 ODATA 服务的方法。我们可能会单独讨论它们。

关注点

在本文中,我们已经了解了如何创建支持 REST 的 WCF 服务。我们还查看了一个实现相同功能的示例应用程序。很多内容都留作读者的练习(例如使用 POST、PUT 和 DELETE 的操作),但我仍然希望这能提供一些信息。

历史

  • 2013 年 4 月 3 日: 第一版。
© . All rights reserved.