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

简单演示 WCF RESTful Web 服务

starIconstarIconstarIconstarIconstarIcon

5.00/5 (13投票s)

2015年4月20日

CPOL

28分钟阅读

viewsIcon

63432

downloadIcon

2031

快速了解简单的 WCF RESTful Web 服务!

目录

  1. 引言
  2. WCF RESTful 服务 - 简介
  3. 看看我们的 TweetBL 项目,它定义了简单的业务功能
  4. 创建 WCF RESTful 服务项目(用于 TweetBL 项目的业务功能)
  5. 运行默认的 WCF RESTful 服务项目(Web.config 文件仍有 AJAX 配置)
  6. 修改并运行默认的 Tweet.WCFService.RESTful 项目设置(从 AJAX 切换到 RESTful)
  7. 运行 Tweet.WCFService.RESTful 项目 - 简单的方式!
  8. 构建 WCF RESTful 服务项目(用于 TweetBL 项目的业务功能)
  9. 运行 WCF RESTful 服务项目(现在包含了我们的业务代码)
  10. 创建和测试 WCF RESTFul Web Service 客户端
  11. 最终想法

简介

在本篇文章中,我们将探讨如何创建 WCF RESTful Web Service!

我建议快速阅读这篇 文章,以便快速回顾 WCF 的基本细节。

我将专注于涵盖与 WCF RESTful 服务相关的主题,而不会深入探讨基本的 WCF 相关细节,例如解释操作契约。上面链接的文章解释了这些主题。

另外,这是我写的关于 WCF AJAX Web Service 的文章链接。如你将在本文中看到的,AJAX Web Service 和 RESTful Web Service 有很多相似之处。我提供了链接供您参考,因为两者都利用了 Web API。我建议在继续阅读本文之前快速浏览一下,因为我坚信这将使您更容易理解。

话虽如此,如果您按照本文的指导进行,应该不难理解这个概念。所以,不用担心,您可以稍后再阅读它们

在本文中,我们将使用一个名为 TweetBL 的简单业务层项目作为起点。在本文的整个过程中,我们将把 TweetBL 的业务功能公开为 WCF RESTful Web Service。

在本文中,我们将专注于开发一个 WCF RESTful Web Service,并已尽我所能使其尽可能简单。

遵循 KISS 原则:“保持简单,愚蠢。

那么,让我们开始吧……

WCF RESTful 服务 - 简介

我仍然认为…… Windows Communication Framework (WCF) 和漫威宇宙一样有趣! 没开玩笑。

WCF 是一个支持客户端和服务器之间基于消息通信的框架。

WCF 是高度可配置的……!!

我们将利用 WCF 的这一特性,采用 WebHttp 行为配置选项! WebHttp 行为提供了 XML 和/或 JSON 序列化,而不是使用传统的 SOAP 报文! WebHttp 还为我们服务公开的每个独立操作绑定了自定义路由。

不用说,它还支持下面提到的多种 HTTP 动词:

  1. GET 动词:用于获取数据
  2. PUT 动词:用于更新数据
  3. POST 动词:用于插入数据
  4. DELETE 动词:用于(您猜对了!)删除数据

简而言之,WebHttp 行为提供了 WCF 开发基于 REST 的 Web 服务所需的功能。

注意,我们还将使用 WebHTTPBinding 服务绑定,因为它允许我们使用预定义的行为从 Web 服务连接到服务方法。

此外,WCF RESTful Web Service 仍然是一种 Web API 风格的 Web Service。这意味着 RESTful Web Service 不会生成 WSDL(Web Service Definition Language)文件。

那么,我们一直在谈论 RESTful……它到底是什么?好吧,REpresentational State Transfer (REST) 是一种 Web API Web Service 风格,在访问、更新和检索数据时遵循一些结构化准则(例如统一接口)!

REpresentational State Transfer (REST) 的一些亮点是:

  1. 统一接口 RESTful 对特定操作使用特定的 HTTP 动词
    • GET:翻译为Read(读取)操作
    • PUT:翻译为Update(更新)操作
    • POST:翻译为Insert/Create(插入/创建)操作
    • DELETE:翻译为……嗯,Delete(删除)操作
  2. RESTful Web Services 还偏好一种特定的 URI 风格(在第 3 点的 yourService.com 示例中演示),它们使用这种风格来访问和管理信息(数据/资源)。RESTful 偏好将它们管理的数据表示为资源。
  3. 促进更简洁的 URI 示例:yourService.com/SocialNetworker/1251/Tweets,而不是使用查询字符串 URI…… yourService.com/GetAllTweetsForSocialNetworker?SocialNetworkerId=1251

所以,说够了……

是时候卷起袖子开始干了!

看看我们定义简单业务功能的 TweetBL 项目

我们将把 TweetBL 项目的业务功能公开为 Web Service!

我们将作为 Web Service 公开的项目是一个名为 TweetBL 的简单类库项目。

TweetBL 项目代表了已确定要在 Web 上作为 WCF RESTful Web Service 提供的业务代码。

TweetBL 项目具有以下业务功能(方法),这些功能将被公开为服务。

业务功能方法是:

  1. 更新推文
  2. 保存/插入推文
  3. 删除推文
  4. 按 ID 检索推文,以及
  5. 检索所有推文

TweetBL 项目

TweetBL Project Screen-shot

Tweet.cs 只是一个数据类,它标识了我们要获取/更新/插入和删除的所有数据成员,以管理推文。可以将其视为 Model(数据模型)。

Tweet.cs Class Screen-shot

ManageTweet.cs 是包含业务方法的类,这些方法对 Tweet 数据执行所有必要的处理以进行管理和维护。
注意:由于我们没有使用实际数据库,因此还有一些维护代码,以使事情保持相对简单。

ManageTweet.cs Class Screen-shot

TweetBL 项目之旅结束…… TweetBL 功能就是这样……它确实相当简单!

让我们开始为我们的 TweetBL 项目编写 RESTful Web Service。

一旦完成,我们将把这个 RESTful 服务献给所有敬业的“Twitterati”……:P

创建 WCF RESTful 服务项目(用于 TweetBL 项目的业务功能)

既然我们已经快速浏览了我们的 TweetBL 项目,是时候进入实际代码了……

让我们开始添加一个名为 Tweet.WCFService.RESTful 的新项目。这将是我们的 WCF RESTful 服务项目。

Adding Tweet.WCFService.RESTful Project Screen-shot

选择“Empty”(空)选项,不要选择其他任何选项。

Adding Tweet.WCFService.RESTful Empty Project Screen-shot

Tweet.WCFService.RESTful Project added Screen-shot

上述步骤为我们创建了一个空的 ASP.NET Web 应用程序!

现在,我们将向 Tweet.WCFService.RESTful 项目添加一个 WCF RESTful 服务。

转到“add new item”(添加新项)(在 Tweet.WCFService.RESTful 项目上),然后按照下面的屏幕截图操作。

Tweet.WCFService.RESTful Adding New Item Screen-shot

Tweet.WCFService.RESTful Added New RESTful Service Screen-shot

添加 AJAX 服务后,我们的项目发生了一些更改。

一些 .NET 的引用和库已添加到我们的项目中。我们将介绍一些有趣的部分!

我们的 Web.config 文件也已修改!

我们的 Web.config 文件(默认情况下)已为开发 AJAX 服务进行了修改,但我们很快就会修改它来开发 RESTful 服务。让我们看一下……

Tweet.WCFService.RESTful Web.Config AJAX Configuration Screen-shot

注意*:<enableWebScript /> 行为用于开发 WCF AJAX Web Service。但由于我们正在开发 RESTful Web Service,我们将对 Web.config 进行必要的修改。

此外,我们的 Tweet.WCFService.RESTful 项目还添加了一个 <endpointBehavior>,它将启用对 Web 服务的请求调用监听。

注意使用的绑定“webHttpBinding”。这允许我们的 Web 服务客户端使用 http GETPOST 动词与我们的服务进行通信。请注意,只有用 Operation Contract 属性修饰的方法才会被公开为服务。

除了上述更改外,我们还提供了一个 TweetService.svc 类的模板文件。

Tweet.WCFService.RESTful TweetService.svc templete file Screen-shot

这里与 SOAP over HTTP Web Services 不同,我们没有接口类。

Service ContractOperation Contract 属性直接定义在类上。另外,请注意 AspNetCompatibilityRequirements 属性:此属性表示该服务与 ASP.NET 管道集成。既然我们已经创建了一个项目并快速浏览了默认提供给我们的内容……让我们进一步构建实际的东西!

运行默认 WCF RESTful 服务项目(Web.config 文件仍有 AJAX 配置)

因此,在我们的 WCF 项目 Tweet.WCFService.RESTful 中,让我们通过右键单击 TweetService.svc 并选择“View in browser”(在浏览器中查看)来启动创建项目后获得的默认代码。

Tweet.WCFService.RESTful TweetService.svc view in browser Screen-shot

Tweet.WCFService.RESTful TweetService.svc default service-run in browser Screen-shot

太棒了!自动生成的 HTML 页面。这是一个 Web API 服务,所以没有生成 WSDL!

当然,我们已经走了这么远,测试一下我们在 TweetService.svc 类中看到的默认 DoWork 方法也没有什么坏处。

为此,我们只需要向 DoWork 方法添加一个新属性。新属性是 WebGet,如下面的屏幕截图所示。

Tweet.WCFService.RESTful TweetService.svc WebGet attribute Screen-shot

自然,您会想知道 WebGet 属性做什么?基本上,WebGet 属性使用 GET 动词公开(用它修饰的)操作!现在,通过在服务 URI(在本例中为 TweetService.svc)后附加方法/操作名称(在本例中为 DoWork)到地址栏,我们可以直接通过 Web 浏览器访问我们的 DoWork 服务。

接下来我们将这样做。

添加此新属性后,再次右键单击 TweetService.svc 并选择“View in browser”(在浏览器中查看)。

在路径末尾输入方法 DoWork……然后按 Enter。

Tweet.WCFService.RESTful TweetService.svc DoWork URI Call Screen-shot

我们的劳动成果……

Tweet.WCFService.RESTful TweetService.svc DoWork URI Call result Screen-shot

{"d":null} 是我们调用 DoWork 服务操作后收到的响应。这是 JSON 格式。

调用 AJAX 服务就是这么简单!

我们上面所做的一切都是在运行 WCF AJAX Web Service,因为请记住,我们还没有修改 Web.config 文件来指示这是一个 RESTful Web Service。

我们接下来这样做!

修改并运行默认的 Tweet.WCFService.RESTful 项目设置(从 AJAX 切换到 RESTful)

首先……我们现在需要做的第一件事是为我们的 WebGet 属性定义一个 URI,因为 REST 非常重视简洁的资源 URI。

这意味着 REST 希望我们指定一个特定的 URI 来访问一个特定的方法或一个特定的资源。

为了实现这一点,我们必须向 WebGet 属性传递参数。

准确地说,我们将采用 UriTemplate 参数

TweetService.svc 中的 DoWork 方法修改如下:

// class code...
[OperationContract]
[WebGet(UriTemplate="/DoWork")]
public void DoWork()
{
    // Add your operation implementation here
    return;
}
// class code...

TweetService.svc 类现在……

Tweet.WCFService.RESTful TweetService.svc DoWork URI RESTful Call result Screen-shot

UriTemplate 参数基本上允许我们传递一个 string,它允许我们为托管提供商(在本例中为 Web Dev 服务器)将传入的请求与之匹配的 URI 定义一个模板!

现在我们准备调用 DoWork 服务方法…… RESTful Web Service 风格!

哦……发生了意想不到的事情!

Tweet.WCFService.RESTful TweetService.svc DoWork URI RESTful Call FAIL result Screen-shot

这是一个服务器错误:表明我们使用了“UriTemplate”将 URI 绑定到特定方法,但我们当前配置不允许这样做!(我们仍然处于 AJAX Web Service 配置)。

Tweet.WCFService.RESTful 项目中的 Web.conf 文件进行必要的更改,是时候迁移到 RESTful 配置了。

Web.config 当前状态……

Tweet.WCFService.RESTful Web.config default with enablewebscript Screen-shot

我们特别想从 <enableWebScript /> 切换到 <webHttp /><webHttp> 是一个 WCF 行为,它为我们提供了比 <enableWebScript> 更宽松、更灵活的 HTTP 通信控制。

为什么? 我们要进行这次切换??仍然感到困惑……嗯……即使 <enableWebScript> 也使用 HTTP 动词进行通信以及序列化和反序列化数据(使用 XML 或 JSON),但它这样做是通过默认自动生成的 JavaScript 代理!它有自己的做事方式。

而在 RESTful 中,我们想使用这个默认的 JavaScipt 代理,因为我们希望对 HTTP 动词有更多的控制!我们希望自己决定哪个 HTTP 动词应该绑定到哪个方法……以及我们想要定义和使用的 URI!<webHttp> 允许在我们的 WebGetWebInvoke 属性中定义所有这些。

关于这个自动生成的 JavaScript 代理的更多信息可以在 WCF AJAX Web Service 文章 中找到(如果您好奇……您也可以稍后阅读)。

Web.config 文件中(Tweet.WCFService.RESTful 项目)进行更改……

Tweet.WCFService.RESTful Web.config with webHttp Screen-shot

是时候再次运行 TweetService.svc DoWork 方法了……

Tweet.WCFService.RESTful TweetService.svc with webHttp Screen-shot

Tweet.WCFService.RESTful TweetService.svc DoWork return NULL with webHttp Screen-shot

……然后 DoWork 正常执行。不用说,DoWork 方法的返回类型是 void,因此执行 DoWork 方法不会返回任何内容供我们显示。

UriTemplate 参数帮助服务器(在本例中是 Web Dev)确定如何处理传入的请求!它有助于推断哪个服务方法应该响应哪个特定的传入请求。

让我们将 DoWork 方法的 UriTemplate 参数从 /DoWork 更改为 /GetSomethingDone……

这将演示 UriTemplate 参数的重要性!因为当我们尝试使用 /DoWork URI 调用 DoWork 方法时,它会报告“Endpoint not found”(端点未找到)!因为我们现在已经更改了访问 DoWork 方法的 URI 以 /GetSomethingDone

TweetService.svc 中更改 UriTemplate 参数。

Tweet.WCFService.RESTful TweetService.svc DoWork with /GetSomethingDone UriTemplate Screen-shot

使用旧的 UriTemplate URI /DoWork 调用 DoWork 方法……

Tweet.WCFService.RESTful TweetService.svc DoWork with /GetSomethingDone UriTemplate invoking /DoWork Screen-shot

服务器无法确定如何处理此请求,因为我们将 UriTemplate 映射到了 /GetSomethingDone

现在让我们使用正确的 URI 调用 DoWork 方法。

Tweet.WCFService.RESTful TweetService.svc DoWork with /GetSomethingDone UriTemplate invoking /GetSomethingDone Screen-shot

看!DoWork 方法的 void 又回来了!!

现在我们已经很好地理解了 UriTemplate 的作用和重要性……让我们向公开真实的 TweetBL 业务方法(而不是 DoWork(默认方法))迈出一步,作为我们备受期待的 TweetService 的一部分!

但在继续前进之前,让我们稍作绕道,让运行 TweetService.svc 变得更容易——只需按 F5!

这肯定会让我们的生活轻松很多,并在下一节中讨论。

简单地运行 Tweet.WCFService.RESTful 项目!

与其右键单击:TweetService.svc - 并选择“open in browser”(在浏览器中打开),我们可以这样做……

Tweet.WCFService.RESTful 项目设置为启动项目。

Tweet.WCFService.RESTful TweetService.svc Set as Start up Project Screen-shot

选择 TweetService.svc 并按 F5

Tweet.WCFService.RESTful TweetService.svc Set as Start up Project Screen-shot

您将收到以下错误:

Tweet.WCFService.RESTful TweetService.svc WCF Test Client FAILED Project Screen-shot

好吧,尝试启动 WCF 测试客户端,但由于 RESTful 服务未生成 WSDL,因此 WCF 测试客户端无法自动生成 XML(WSDL)来帮助我们测试服务……我们现在来修复这个问题;这样,当我们尝试在选择 TweetService.svc 后运行 Tweet.WCFService.RESTful 时——WCF 测试客户端将不再被用于帮助我们测试服务!

让我们编辑 Tweet.WCFService.RESTful 项目的文件。

在开始编辑之前,我们需要卸载 Tweet.WCFService.RESTful 项目。

Tweet.WCFService.RESTful editing Project File UNLOAD Project Screen-shot

项目卸载后,右键单击项目并选择“Edit Tweet.WCFService.RESTful.csproj”。

Tweet.WCFService.RESTful editing Project File Edit csproj Screen-shot

按“Ctrl+F”搜索<WebProjectProperties>

Tweet.WCFService.RESTful editing Project File WebProjectProperties Screen-shot

Tweet.WCFService.RESTful 项目的 WebProjectProperties 添加以下元素!然后保存文件。

<WebProjectProperties>
  // Other Project Properties...
  
  <EnableWcfTestClientForSVCDefaultValue>
    false
  </EnableWcfTestClientForSVCDefaultValue>
  
  // Other Project Properties...
</WebProjectProperties>

Tweet.WCFService.RESTful editing Project File WebProjectProperties EnableWcfTestClientForSVCDefaultValue set to false Screen-shot

保存对 Tweet.WCFService.RESTful.csproj 的更改后,是时候重新加载项目了……

Tweet.WCFService.RESTful editing Project File Reload Project Screen-shot

点击“YES”!

Tweet.WCFService.RESTful editing Project File Reload Project Click YES Screen-shot

再次将 Tweet.WCFService.RESTful 项目设置为启动项目……

Tweet.WCFService.RESTful editing Project File Setting as Start-Up Screen-shot

选择 TweetService.svc 文件。

Tweet.WCFService.RESTful editing Project File Select TweetService.svc Screen-shot

TweetService.svc 的后台代码文件中——按 F5!

WCF 测试客户端没有弹出!我们的 TweetService.svc 已执行…… Tweet.WCFService.RESTful edited Project File in TweetService.svc Press F5 Screen-shot

现在,让我们继续公开我们的有效 TweetBL 业务功能,作为我们备受期待的 TweetServiceTweetService.svc)的一部分。这将在下一节中完成。

构建 WCF RESTful 服务项目(用于 TweetBL 项目的业务功能)

是时候构建我们真正的 RESTful 服务并删除 DoWork 方法了!让我们利用TweetBL 项目 - ManageTweet.cs:这个类包含我们需要管理 Tweet 的所有业务代码。我们将把所有这些方法公开为 RESTful Web Service。

Tweet.WCFService.RESTful TweetService.svc with TweetBL Business Methods Screen-shot

Tweet.WCFService.RESTful 项目的 TweetService.svc 中,我们已包含对 TweetBL 项目的 ManageTweet.cs 的引用,正如上面屏幕截图所示,我们所做的只是将收到的任何 TweetService.svc 方法的调用传递给 ManageTweet 类方法来执行实际工作。

简单来说,我们在服务类中所做的就是在调用业务类来完成实际工作。

运行 WCF RESTful 服务项目(现在包含我们的业务代码)

现在我们准备好了——来实际运行我们的 Tweet 服务!

它不会有太大区别……但是的,需要一些额外的步骤才能运行某些方法!这些方法没有实现 GET 动词(WebGet 属性)而是实现了 WebInvoke 属性。另外,不用担心需要 ID 参数的方法 GetTweetById,测试起来会很简单!下面指出的那些(在 TweetService.svc 中)

Tweet.WCFService.RESTful Project TweetService.svc WebInvoke Methods Screen-shot

相信我,这很有趣……

测试 GetTweets() 方法: 按照下面屏幕截图中的步骤操作

运行服务 - 选择 TweetService.svc 并按 F5……

Tweet.WCFService.RESTful Project TweetService.svc Running Service FAILS Screen-shot

我们收到以下错误!

Tweet.WCFService.RESTful Project TweetService.svc Running Service FAILED MESSAGE Screen-shot

完整的错误消息是:“合同‘TweetService’中的操作‘GetTweetByID’有一个名为‘tweetId’的路径变量,其类型不是‘string’。UriTemplate 路径段的变量必须是‘string’类型。”

这里没有戏剧性的事情!抱怨的是 GetTweetByID 方法,它需要一个 int tweetId 参数。WCF Rest 无法解析 UriTemplate 路径中的任何其他值,除了字符串

有问题的​​方法……嗯,一旦我们解决了 GetTweetByIdDeleteTweet 方法也会有问题!

最好现在就解决它们!

方法们

Tweet.WCFService.RESTful Project TweetService.svc GetTweetById Method Screen-shot

Tweet.WCFService.RESTful Project TweetService.svc DeleteTweet Method Screen-shot

我们所要做的就是将 GetTweetByID 方法的 int tweetId 参数DeleteTweet 方法的 int deleteTweetId 参数更改为string,并在我们的 GetTweetByID 方法和 DeleteTweet 方法中进行必要的数据转换,将 tweetIddeleteTweetId 参数从string 转换为 int,然后再将它们传递给相应的 TweetBL 方法。

进行建议的更改——

GetTweetByID 方法

Tweet.WCFService.RESTful Project TweetService.svc GetTweetById Modified Method Screen-shot

DeleteTweet 方法

Tweet.WCFService.RESTful Project TweetService.svc DeleteTweet Modified Method Screen-shot

终于,我们回到正轨了……

现在让我们第二次测试 TweetService.svc 方法!

测试 GetTweets() 方法: (注意* GetTweetByIDDeleteTweet 方法已修复!)按照下面屏幕截图中的步骤操作

运行服务 - 选择 TweetService.svc 并按 F5……

Tweet.WCFService.RESTful Project TweetService.svc Running Service Will Pass Screen-shot

输入方法名 GetTweets

Tweet.WCFService.RESTful Project TweetService.svc GetTweets Method Call Screen-shot

GetTweets 方法结果(未格式化)

Tweet.WCFService.RESTful Project TweetService.svc GetTweets Method unformatted result Screen-shot

注意到 k__BackingField 附加到了我们的每个 Tweet 属性……这是因为我们没有将我们的 Tweet 类(TweetBL 项目)标记为 DataContract 属性,并且没有将它的字段标记为 DataMember 属性。

TweetBL Project Tweet.cs DataMember Attribute Missing Screen-shot

快速回顾:数据契约定义了 Web 服务操作将发送和接收的数据的类型和格式。DataMember 属性应用于 DataContract 类的要序列化的字段。

我在我之前的一篇文章中详细介绍过 WCF 契约,相关部分可以在 这里 找到。

将属性应用于 Tweet.cs

TweetBL Project Tweet.cs DataMember Attribute Added Serialization Namespace missing Screen-shot

哎哟!那些红色的波浪线……啊……这只是表明您在 TweetBL 项目中没有对“Serialization”程序集的引用!

namespace TweetBL
{
    using System;
    using System.Runtime.Serialization;
	.... remaining code...	

让我们快速添加对“Serialization”程序集的引用

TweetBL Project Tweet.cs Serilaization reference-1 Screen-shot

TweetBL Project Tweet.cs Serilaization reference-2 Screen-shot

然后一切又恢复正常了……

TweetBL Project Tweet.cs Serilaization reference-3 Screen-shot

再次运行 TweetService.svc……我们得到以下结果: k__BackingField 不再附加。

Tweet.WCFService.RESTful Project TweetService.svc GetTweets Method formatted result Screen-shot

让我们运行 GetTweetByID() 方法。此方法用 WebGet 属性修饰,但它还需要一个类型为 string 的参数!要传递……太棒了……

Tweet.WCFService.RESTful Project TweetService.svc GetTweetById Method Screen-shot

运行 TweetService.svc 并调用 GetTweetByID 方法而不传递必需的 string 参数将产生以下“Endpoint not found”(端点未找到)结果

Tweet.WCFService.RESTful Project TweetService.svc GetTweetByID Method No Param 1 Screen-shot

我们得到上述结果是因为 WCF 尽力匹配请求的 URI,但未能找到匹配的方法。对于 GetTweetByID 方法,URI 指示需要一个 string[WebGet(UriTemplate = "/Tweet/{tweetId}")]

运行 TweetService.svc 并仅通过 /Tweet 调用 GetTweetByID 方法将产生以下“Method not allowed”(方法不允许)结果

Tweet.WCFService.RESTful Project TweetService.svc GetTweetByID Method No Param 2 Screen-shot

不用说,TweetService.svc 中定义的其他方法都没有 /Tweet 的 URI 并且用 WebGet 属性修饰!

UpdateTweet 方法确实有一个匹配的 URI,但它用WebInvoke 属性修饰,正如我们稍后将学到的,调用 WebInvoke 方法的方式有点不同。

默认情况下,我们的浏览器只发送 WebGet 请求!……所以它无法执行 URI 为 /Tweet 的方法(在本例中为 UpdateTweet 方法),因为它会以 GET 动词的 HTTP 请求发送 /Tweet,而 UpdateTweet 方法正在等待 PUT 动词的 HTTP 请求!

让我们在 URI 中传递必需的 string Id 参数,看看服务是如何工作的

0 传递给 GetTweetByID 方法

Tweet.WCFService.RESTful Project TweetService.svc GetTweetByID Method Param = 0 Screen-shot

显而易见,我们没有 ID 为 0 的记录,所以返回 null

我们只需要传递一个正确的推文 ID(请参阅下方)

Tweet.WCFService.RESTful Project TweetService.svc GetTweetById Method with Correct Param Screen-shot

所以,这是关于如何运行用 WebGet 属性修饰并且需要传递 string 参数的服务操作/方法的一个简单演示!

是时候看一下 TweetService.svc 类中用 WebInvoke 属性修饰的其他操作了……

Tweet.WCFService.RESTful Project TweetService.svc WebInvoke Methods Screen-shot

WebGetWebInvoke 属性之间的关键区别在于,它使用 POST 动词而不是 WebGet 使用的 GET 动词。

为什么使用 WebInvoke?嗯,WebInvoke 属性使用其他 HTTP 动词(如 POSTPUTDELETE)公开服务操作/方法。这些操作旨在修改资源;因此,使用 WebInvoke 属性来修改资源。注意:默认选项是 POST,但您可以通过设置 WebInvoke 属性的Method 属性来更改它。如下面所示

[OperationContract]
[WebInvoke(Method = "PUT")]
public void PutQuestion(int id, Question question)
{
    // Put question in database
}

另一个需要注意的有趣点是,所有 Web 浏览器都针对 GET 动词请求进行了优化。它们缓存 Get 请求的结果,并且每次刷新浏览器时,结果都会从浏览器缓存中检索,而不是访问 Web 服务器。

因此,出于明显的原因,现在执行createupdatedelete操作时,您不希望浏览器缓存这些操作的结果!所以,我们使用不同的动词,如 PutPost 等,来表示我们不希望缓存这些操作的结果,并且在PutPostDelete操作成功完成后,我们总是希望刷新数据。这是一个双赢!

现在,继续……如果我们尝试像调用 WebGet 属性修饰的操作那样运行 WebInvoke 修饰的操作,我们会得到以下结果

方法 CreateTweet - URI:/Tweets

Tweet.WCFService.RESTful Project TweetService.svc WebInvoke Method CreateTweet Screen-shot

调用结果

Tweet.WCFService.RESTful Project TweetService.svc WebInvoke Method CreateTweet run Screen-shot

我们收到“Method not allowed”(方法不允许)消息,因为我们为 CreateTweet 操作指定了 WebInvoke 属性。

我们现在提出的问题是……如何测试我们的 WebInvoke 方法 CreateTweet? 简单的答案是使用“Fiddler”

Fiddler:是一个实用工具,允许我们创建和监控机器上的 HTTP Get/Put/Post/Delete 请求!……正是我们需要的!

有一些问题的答案……嗯,这个问题不属于其中之一 :) 感谢 Fiddler。

Fiddler Search Screen-shot

事不宜迟,下载并安装 Fiddler……(我在 Windows 8 上)因此我选择了 Fiddler 4!请根据网站上的建议选择 2 或 4。

Fiddler Selected Screen-shot

运行 FIDDLER 很简单。找到 Fiddler 并运行它……

Fiddler Running Screen-shot

现在,让我们再次使用 Fiddler 运行方法 CreateTweet - URI:/Tweets!

所以,我们要向 TweetService 发送一个 POST 请求!

按照下面的屏幕截图:粘贴 TweetService 的地址,并将类型更改为 POST

Fiddler Connecting to our Service Screen-shot

添加对 CreateTweet 所需 URI 的调用:该方法的 UriTemplate/Tweets

Fiddler Connecting to our Service specifying the correct CreateTweet URI Screen-shot

现在,我们需要指定一个有效的请求头

这是因为我们希望明确告知我们要发送给服务器进行处理的数据格式!

请记住 CreateTweet 方法需要一个 TWEET 类型的参数!

CreateTweet Parameter

指定request Header: Content-Type: application/json,我们的数据将以 json 格式发送到服务器!

Request Header

现在,我们来到了最重要的部分!指定消息正文——即在此情况下要保存的数据!(不用说,格式是 json!正如我们在请求头中指定的!)

所以,我们将发送一个 json 对象到服务器以作为我们调用 CreateTweet 方法的一部分进行保存!

{
  "Id": 0,
  "PostedBy": "Rahul Pawar via Fiddler",
  "Text": "Saved tweet via Fiddler 4"
}

Request Body for CreateTweet

是时候点击Execute(执行)了。

Request Body for CreateTweet Execute

Request Body for CreateTweet Execute RESULT

Request Body for CreateTweet Execute Response Headers

200 的响应表明一切顺利!

快速调用 GetTweets 方法会返回新插入的 Tweet!

GetTweets after CreateTweet Execute

是时候测试我们的 UpdateTweet 方法了:UpdateTweet 用 Web Invoke 属性修饰,该属性接受 HTTP PUT 动词请求。

UpdateTweet Method

启动 Fiddler……

转到 Composer(作曲家)……输入 TweetService.svc 的地址……为此请求选择 PUT 作为 HTTP 动词……

UpdateTweet Method Fiddler Start-up

添加对 UpdateTweet 所需 URI 的调用:该方法的 UriTemplate/Tweet

UpdateTweet Method Fiddler UpdateTweet Method URI

指定request Header: Content-Type: application/json

现在,我们来到了最重要的部分!指定消息正文——即通过 UpdateTweet 方法要更新的数据!

让我们更新 ID 为 2 的 Tweet,更新为以下内容:

{
  "Id": 2,
  "PostedBy": "UPDATED via Fiddler",
  "Text": "UPDATED tweet via Fiddler"
}

UpdateTweet Method Fiddler UpdateTweet Method Request Body

是时候执行我们的 Update请求!

在 Inspectors(检查器)选项卡下,我们的 200 响应头表明一切都已顺利完成!记录已更新!

UpdateTweet Method Fiddler UpdateTweet Method Response Header

快速调用 GetTweets 方法会返回新更新的 Tweet!

GetTweets after UpdateTweet Execute

是时候测试我们的 DeleteTweet 方法了:DeleteTweet 用 Web Invoke 属性修饰,该属性接受 HTTP DELETE 动词请求。

DeleteTweet Method

启动 Fiddler……

转到 Composer(作曲家)……输入 TweetService.svc 的地址……为该请求选择 DELETE 作为 HTTP 动词……

DeleteTweet Method Fiddler Start-up

添加对 DeleteTweet 所需 URI 的调用:该方法的 UriTemplate/Tweet/{deleteTweetId}

我们将删除 ID 为 2 的 Tweet(在上一步中更新的那个)请注意——在 URI 中,我们只是在最后指定了 Tweet ID!……URI……/2……

DeleteTweet Method Fiddler DeleteTweet Method URI

注意*:根据HTTP 规范——对于 DELETEGET 动词,我们不需要发送请求正文!不用说,REST 遵循这个规范。

是时候点击Execute(执行)了!

结果:我们得到 200 的响应——ID 为 2 的 Tweet 已被删除!

DeleteTweet Method Fiddler Result

快速调用 GetTweets 方法会返回剩余的 Tweet(s)!

GetTweets after DeleteTweet Execute

注意上面显示的 GetTweets 结果中缺少 ID 为 2 的 Tweet,因为我们已成功删除它!

至此,我们已完成了对 TweetService.svc 的快速测试,并已确定它工作正常!

现在是时候创建我们 TweetService.svc 的客户端了。我们将在下一节中这样做。

创建和测试 WCF RESTFul Web Service 客户端

Fiddler 对于一些快速的单元测试很有用。现在是时候构建我们自己的 Web Service 客户端了。让我们开始添加一个名为 TweetClient 的新 Console Application 项目,它将成为消费我们 RESTFul Tweet Web Service 的客户端。

TweetClient Project - Screen-Shot

TweetClient Project Added - Screen-Shot

由于 RESTFul 服务未生成 WSDL,因此我们无法通过简单地引入服务引用来获得默认服务代理类等便利。

我们将不得不自己完成所有必需的序列化、反序列化、网络调用、创建数据传输对象等工作来消费我们的 RESTFul Tweet Web Service……听起来很糟糕,但请坚持住,因为在 .NET 中这样做非常简单!

让我们创建一个名为 Services 的文件夹,并引入一个名为 TweetService 的类,它将负责我们 Web 客户端的所有通信……

TweetClient Project - Services Folder and TweetService Client Screen-Shot

引入 GetTweets 方法

TweetClient Project - GetTweets missing transport object Screen-Shot

好的……我们还没有 Tweet 的定义!让我们先解决这个问题……

让我们创建一个名为 Transports 的文件夹,并引入一个名为 Tweet 的类,该类基本上是客户端的 Tweet 对象定义……

TweetClient Project - Transports Folder and Tweet Object Screen-Shot

我们客户端的 Tweet 对象的定义与我们在 TweetBL 项目中定义的不会有太大区别!

TweetClient Project - Transports Folder and Tweet Object Definition Screen-Shot

添加对 Transports 文件夹中 Tweet 对象的引用……一切都很好!

TweetClient Project -  GetTweets added transport object Screen-Shot

现在,回到 GetTweets 方法……

GetTweets 方法中,我们将使用 Web Client 并要求 Web 服务器以 JSON 格式向我们传递数据。

下面是 GetTweets 方法的定义——注意它有适当的文档说明

public IList<Tweet> GetTweets()
{
     // Making a call to our GetTweets Endpoint by employing a WebClient!
     var client = new WebClient();
     
     // Requesting JSON from the Web Server - because we have deserializer for JSON in place
     client.Headers.Add("Accept", "application/json");
     
     // Using WebClient we can download a file, a string etc.. we will download String
     // because we will be receiving the data from our TweetService.svc in XML format or JSON format
     // ...all we have to do than is create a deserializer to create a object from that 
     // received XML/JSON data! .. sweet
     
     // to download a string we need to give the web address of our service endpoint
     // below I have specified the local address and the correct endpoint to access the
     // required information
     var result = client.DownloadString("https://:47354/TweetService.svc/GetTweets");            
     
     // Now we will employ the JSON desiralizer that comes with .NET to de-serialize and 
     // create a Tweet object for us from the response received from TweetService.svc
     var serializer = new DataContractJsonSerializer(typeof(List<Tweet>));
     
     List<Tweet> resultObject;
     using (var stream = new MemoryStream(Encoding.ASCII.GetBytes(result)))
     {
         resultObject = (List<Tweet>)serializer.ReadObject(stream);
     }
     
     return resultObject;
}

GetTweets 方法的屏幕截图

TweetClient Project -  GetTweets Method : DataContractJsonSerializer missing-  Screen-Shot

哎呀——那条该死的红色波浪线!它抱怨 DataContractJsonSerializer……让我们添加引用并修复它!

添加对:System.Runtime.Serialization 的引用以访问 DataContractJsonSerializer

注意*:已在 TweetClient 项目中添加了引用。

TweetClient Project -  Add reference to  System.Runtime.Serialization.Json Take 1 Screen-Shot

TweetClient Project -  Add reference to  System.Runtime.Serialization.Json Take 2 Screen-Shot

TweetClient Project -  Add reference to  System.Runtime.Serialization.Json Take 3 Screen-Shot

问题已解决!

TweetClient Project -  Add reference to  System.Runtime.Serialization.Json Take 4 Screen-Shot

是时候运行我们的 GetTweets 方法了。

请按照下面提到的步骤操作

步骤 1:将 Tweet.WCFService.RESTful 设置为默认启动项目。

步骤 2:在 Tweet.WCFService.RESTful 中双击 TweetService.svc

步骤 3:转到**Debug**(菜单选项中的“调试”),然后选择**Start without Debugging**(启动而不调试)。

步骤 4:您的默认浏览器将显示以下页面!

Tweet.WCFService.RESTful-  Running without Debugging Screen-Shot

步骤 5:跳转到 TweetClient 项目。

步骤 6:选择 TweetClient 项目,右键单击并按照下面的屏幕截图操作。

TweetClient Project-  Running Program Class Take 1 Screen-Shot

注意*:我将把 Program 类留在 TweetClient 项目中供您自己探索!因为它不包含任何与文章相关的代码。它只有一个花哨的 GUI(您决定 :)) 来调用我们的 RESTFul Tweet 服务!

按照步骤 6 操作后,我们劳动成果的展示

TweetClient Project-  Running Program Class GUI Take 1 Screen-Shot

选择L(按 Enter)列出所有 Tweets - 它调用我们的 GetTweets 方法

TweetClient Project-  Running Program Class GUI Call to List all Tweets - Which wil fail Screen-Shot

轰……我们遇到了一个异常!异常在 TweetClient 项目的 GetTweets 方法中抛出。

TweetClient Project-  Running Program Class GUI Call to List all Tweets FAILS: Exception Reported- Which wil fail Screen-Shot

让我们仔细看看异常。

TweetClient 项目的 TweetService 类的第 39 行和第 45 行设置断点。

TweetClient Project-  TweetService.cs with set Breakpoints lines 39 and 45 Screen-Shot

再次运行 TweetClient 项目……以探索断点处应用程序的条件……

注意*:当 GUI 弹出时,请记住输入L然后按 Enter!

当执行到达第 39 行时按 F10,当它在第 45 行时,将光标指向第 39 行的变量 result……我们需要在 JSON 查看器中查看变量 result 中存储的内容……按照下面的步骤操作。

TweetClient Project-  TweetService.cs line 39 Screen-Shot

在那里,一旦我们选择了 JSON 查看器……问题就变得有点明显了!

TweetClient Project-  TweetService.cs line 39 JSON Visulaizer Screen-Shot

高亮的警告消息清楚地说明了问题……我们请求了 JSON 格式,但 Web 服务器没有按照我们的请求进行!

由于返回的结果不是 JSON 格式,我们的客户端无法将其反序列化。

现在要解决这个问题,我们需要在 Tweet.WCFService.RESTful 项目中进行更改……

我们需要让我们的 RESTFul TweetService.svc 更加灵活,以便它可以从其客户端获取关于结果返回格式的信息……

我们可以通过修改 Tweet.WCFService.RESTful 项目的 Web.config 文件来实现应用程序级别的更改……

更改 Web.config 文件!

添加 automaticFormatSelectionEnabled 将使我们的服务客户端能够指定返回数据的格式……默认情况下,Web 服务器返回 XML format,因此我们的 TweetClient 项目 GetTweets 方法抛出了异常,因为它请求了 JSON 格式并且基于服务器会遵守其请求的假设……嗯,现在它会了!!

Tweet.WCFService.RESTful Project - Web.config file modified Screen-Shot

现在,我们在这里,让我们再次按照上面提到的 6 个步骤来测试我们的 GetTweets 方法

是的,请记住删除我们添加的断点……相信我,这次一切都会顺利的 :)

遵循(6 个步骤)后,这次我们得到以下结果(选择L后)

TweetClient Project - GetTweets Method Result Screen-Shot

Voilà:所有记录中的推文都已返回……!我们的 GetTweets 方法终于成功了!

现在,继续处理其余方法。

测试 GetTweetByID 方法……

对于这个 GetTweetByID 方法,我们将请求并反序列化 XML 而不是 JSON。

GetTweetByID 方法

TweetClient Project - GetTweetById Method Screen-Shot

测试方法——现在,请再次按照上面提到的6 个步骤来测试我们的 GetTweetById 方法。

程序运行后,请按照以下步骤操作

选择L获取当前存储的所有推文列表。

TweetClient Project - GetTweetById Method Run Step 1 Screen-Shot

输入 1 来提取 ID 为 1 的推文……

哎……又出麻烦了……

TweetClient Project - GetTweetById Method Result Exception Screen-Shot

如果我们查看异常的详细信息

TweetClient Project - GetTweetById Method Result Exception detail Screen-Shot

为了修复这个问题……我们需要介绍我们在 TweetBL 项目 Tweet 类中定义的 XML Schema 定义。

所以,在 Tweet 客户端项目的Transports文件夹的 Tweet 类中,添加以下一行……

TweetClient Project - Transport Project Tweet Client XML Definition addition Screen-Shot

现在再次运行测试……最终结果……

TweetClient Project - GetTweetById Method Result Screen-Shot

是时候进入创建 Tweet 方法了。

不,不幸的是,使用 WebClient,您无法指定要用于服务操作的 HTTP 动词。Web Client 对所有请求都使用 GET HTTP 动词。

由于我们在创建/更新 Tweet 时需要更多控制,因此现在我们需要使用 HTTP Web Request 而不是 Web Client,因为它将为我们提供使用其他 HTTP 动词进行请求的能力。

CreateTweet 方法

TweetClient Project - CreateTweet Method 1 Screen-Shot

TweetClient Project - CreateTweet Method 2 Screen-Shot

是时候测试 CreateTweet 方法了

按照6 个步骤(上面提到)然后按照下面提到的步骤操作

输入 N - 用于输入 New Tweet(新推文)……

TweetClient Project - CreateTweet Method Test 1 Screen-Shot

TweetClient Project - CreateTweet Method Test 2 Screen-Shot

输入 L,这是结果

TweetClient Project - CreateTweet Method Test 3 Screen-Shot

是时候编写和测试 Update 方法了

CreateTweet 方法相比,Update 方法只有一个区别,那就是它使用的 HTTP 动词……

Update 方法需要使用 PUT HTTP 动词。

Update 方法

TweetClient Project - UpdateTweet Method Screen-Shot

测试 Update 方法——按照(上面提供的)6 个步骤以及下面指定的步骤……

检索我们使用 CreateTweet 方法保存的 Tweet……

TweetClient Project - UpdateTweet Method Test 1 Screen-Shot

选择 E 选项进行编辑

TweetClient Project - UpdateTweet Method Test 2 Screen-Shot

选择 L 列出所有 Tweets……

TweetClient Project - UpdateTweet Method Test 3 Screen-Shot

最终结果……更新的 Tweet!

TweetClient Project - UpdateTweet Method Test 4 Screen-Shot

现在,最后一个方法——DeleteTweet 方法!

对于 Delete,我们要发送一个不是 Tweet 对象,但包含 Tweet Id 属性的对象……

TweetClient 项目中添加一个新的 Transport 对象……它将包含我们想要用于 DeleteTweet 操作的对象定义的必需定义!

TweetClient Project - Transport Folder Delete Tweet 1 Screen-Shot

TweetClient Project - Transport Folder Delete Tweet 2 Screen-Shot

DeleteTweet 方法

TweetClient Project - Delete Tweet Method Screen-Shot

是时候测试 DeleteTweet 方法了

按照上面提到的6 个步骤,然后按照下面的步骤……

输入我们使用 CreateTweet 方法添加的 Tweet 的 ID……选择 D 选项删除它……

TweetClient Project - Delete Tweet Test 1 Screen-Shot

选择 Y(是)- 确认删除:还输入 L 列出所有 Tweets……

TweetClient Project - Delete Tweet Test 2 Screen-Shot

我们的劳动成果……ID 为 7 的 Tweet 已被删除……返回的 Tweets 不包含 ID 为 7 的 Tweet!

TweetClient Project - Delete Tweet Test 3 Screen-Shot

我们完成了!!!!

最终想法

这是一篇关于WCF Web Service的文章!另外,这是关于 WCF Ajax Web Service的文章链接!

这两篇文章都是我写的。两篇文章都演示了上述服务的简单示例,展示了 WCF 的强大功能和简单性。

现在该我告别了。欢迎随时提问、提供反馈和任何其他事宜,因为我和您在同一条船上。附注:这艘船叫做“燃烧与学习”。

历史

  • 版本 1 提交于 2015 年 4 月 19 日
© . All rights reserved.