简单演示 WCF AJAX Web 服务






4.83/5 (7投票s)
快速了解简单的 WCF AJAX Web 服务!
目录
- 引言
- WCF AJAX 服务 - 简介
- 查看我们定义简单业务功能的项目 TweetBL
- 创建 WCF AJAX 服务项目(用于 TweetBL 项目的业务功能)
- 运行默认的 WCF AJAX 服务项目
- 构建 WCF AJAX 服务项目(用于 TweetBL 项目的业务功能)
- 运行 WCF AJAX 服务项目(现在包含我们的业务代码)
- WCF AJAX Web Service 从 JSON 切换到 XML
- 创建 WCF AJAX Web Service 客户端
- 使用我们的服务客户端测试 WCF AJAX Web Service
- 最终想法
简介
在本文中,我们将探讨如何创建一个 WCF AJAX Web Service!
我建议快速阅读这篇文章,以温习 WCF 的基本细节。
在本文中,我将重点介绍与 WCF AJAX 服务相关的主题,而不会深入探讨 WCF 的基本细节,例如解释操作契约。上面链接的文章解释了这些主题。
我们将使用一个名为 TweetBL
的简单业务层项目来开始本文。在本文的过程中,我们将把 TweetBL
的业务功能公开为 WCF AJAX Web Service。
在本文中,我们将专注于开发一个 WCF AJAX Web Service,我已尽力使其尽可能简单。
遵循 KISS 原则:“保持简单明了。”
那么,让我们开始吧...
WCF AJAX 服务 - 简介
“异步 JavaScript 和 XML” 是一种 Web 开发技术,支持创建具有丰富客户端表示的交互式网站。AJAX 促进从服务器异步检索数据——这意味着 AJAX 在不中断客户端当前视图的情况下调用新的数据请求!
AJAX 使我们能够动态获取服务器端内容,并使其看起来像客户端动态内容……用户不会受到任何中断!而 AJAX 在幕后完成这种动态服务器端内容的获取。一旦从服务器获取数据完成,客户端的当前视图就会用检索到的数据进行更新。
最后,AJAX 的主要目的是提高 Web 应用程序的速度、可用性和性能。
一个业务示例可以是网页上的评分功能。当用户对某物进行评分时——例如,他们的评分是 5,它会被存储到数据库中,而无需刷新或重新加载网页。用户只需选择 5 颗星,然后继续在网页上处理他们的业务,而 AJAX 在后台努力工作以取悦其主人,完成所需的工作。
最后,AJAX 采用以下列出的技术(但不限于此)和机制,使开发人员的生活更轻松
- JavaScript
- XML
- 向服务器发出异步请求
“WCF AJAX Web 服务”
Windows Communication Framework (WCF) 和漫威宇宙一样有趣!不开玩笑。
WCF 是一个支持客户端和服务器之间基于消息通信的框架。
WCF 的可配置性极高……我们将利用 WCF 的这一特性,采用 EnableWebScript
行为配置选项!
EnableWebScript
行为提供 XML 和/或 JSON 序列化,而不是使用传统的 SOAP 信封!它还会为每个定义的 AJAX 服务创建一个默认的 JavaScript 代理(此默认的 JavaScript 代理包含用于在客户端和服务器之间发送和接收数据的客户端代码,以及有关交换数据所需传输对象的信息)……并且这个生成的 JavaScript 代理可以被任何 Web 客户端使用。
另一个重要因素是 WCF AJAX 服务是 Web API Web Service 的一个示例。这是因为 WCF AJAX 服务使用 HTTP 标准发送和接收数据,而不依赖于传统 WCF SOAP over HTTP 服务使用的 WSDL。我们将使用多个 HTTP 动词(如 Get
/Post
/Delete
)与服务器通信。
所有这些都只需调整 WCF 配置!
最后,AJAX 客户端是运行 JavaScript 代码并使用 HTTP 请求访问这些 WCF 服务的网页。
我们将开发一个 WCF AJAX Web Service,它将由运行 JavaScript 的客户端网页通过 HTTP 请求来消费。
是时候卷起袖子,开始行动了!
看看我们定义简单业务功能的项目 TweetBL
我们将把 TweetBL 项目的业务功能公开为 Web 服务!
我们将作为 Web 服务公开的项目是一个名为 TweetBL
的简单类库项目。TweetBL
项目代表了已被确定为可通过 Web 作为 WCF AJAX Web 服务提供的业务代码。
TweetBL
项目具有以下将作为服务公开的业务功能(方法)。业务功能方法包括
- 更新推文
- 保存/插入一条推文
- 删除一条推文
- 按 ID 检索推文以及
- 检索所有推文
TweetBL 项目
Tweet.cs 只是数据类,用于标识我们要获取/更新/插入和删除的所有数据成员,以管理推文。可以将其视为模型(数据模型)。
ManageTweet.cs 是包含业务方法的类,这些方法对推文数据执行所有必要的处理以进行管理和维护。注意:由于我们没有使用实际的数据库来保持事情的相对简单性,因此也存在一些内部管理代码。
创建 WCF AJAX 服务项目(用于 TweetBL 项目的业务功能)
既然我们已经快速浏览了 TweetBL
项目,是时候跳入实际代码了……让我们从添加一个名为 Tweet.WCFService.AJAX
的新项目开始,这将是我们的 WCF AJAX 服务项目。
只选择“空”选项,不选其他任何内容。
以上步骤为我们创建了一个空的 ASP.NET Web 应用程序!
现在,我们将向 Tweet.WCFService.AJAX
项目添加一个 WCF AJAX 服务。转到(在 Tweet.WCFService.AJAX
项目上)添加新项,并按照下面的屏幕截图操作
我们添加 AJAX 服务后,项目进行了一些更改。
.NET 中的一些引用和库已添加到我们的项目中。我们将介绍一些有趣的部分!
我们的 Web.config 文件也已修改!让我们来看看它……
一个行为已被添加到我们的 Web.config 文件(如上图所示),以启用我们项目的 Web 脚本。已添加一个 <endpointBehavior>
,它将启用对 Web 服务请求调用的监听。<enableWebScript />
行为将操作契约映射到特定的 URI。<enableWebScript />
还会为我们的服务创建一个 JavaScript 代理文件,我们稍后将查看。<enableWebScript />
还为我们提供了几种序列化数据的方式。我们可以在 JSON 或 XML 之间选择序列化数据。这里需要注意的重要一点是,所有这些都属于 Web API 的一部分。
请注意使用的绑定“webHttpBinding
”。这允许我们的 Web 服务客户端使用 HTTP get
和 post
动词与我们的服务进行通信。请注意,只有使用 Operation Contract
属性装饰的方法才作为服务公开。
除了上述更改,我们还为 TweetService.svc 类提供了一个模板文件。
这里与 SOAP over HTTP Web Services 不同,我们没有 interface
类。Service Contract
和 Operation Contract
属性直接定义在类上。另外,请注意 AspNetCompatibilityRequirements
属性:此属性指示此服务与 ASP.Net 管道集成。既然我们已经创建了一个项目并快速了解了默认提供给我们的内容,那么让我们开始构建真实的东西!
运行默认的 WCF AJAX 服务项目
因此,在我们的 WCF 项目 Tweet.WCFService.AJAX
中,让我们通过运行创建项目后得到的默认代码来开始。这可以通过右键单击 TweetService.svc 并选择“在浏览器中查看”来完成!
太棒了!自动生成的 HTML 页面。这是一个 Web API 服务,因此没有生成 WSDL!
当然,我们已经走到这一步了,测试我们在 TweetService.svc 类中看到的默认 DoWork
方法也无妨。要做到这一点,我们只需为 DoWork
方法添加一个新属性。这个新属性是屏幕截图中显示的 WebGet
。
自然,您会想知道 WebGet
属性有什么作用?基本上,WebGet
属性使用 GET
动词公开(用它装饰的)操作!现在,我们的 DoWork
服务可以直接通过 Web 浏览器访问,方法是在地址栏中输入服务的 URI(在我们的例子中是 TweetService.svc),然后是方法/操作名称(在我们的例子中是 DoWork
)。这就是我们接下来要做的事情。
添加这个新属性后,再次右键单击 TweetService.svc 并选择“在浏览器中查看”。在路径末尾输入方法 DoWork
……然后按回车键。
我们的劳动成果……
{"d":null}
是我们调用 DoWork
服务操作后返回的响应。这是 JSON 格式。
调用 AJAX 服务就是这么简单!我们以服务文件名(本例中为 TweetService.svc)开头,后面跟着方法名(本例中为 DoWork
)。请记住,我们用 WebGet
属性装饰了 DoWork
,这使得该操作可以通过 HTTP get
请求访问。
DoWork
返回结果的格式与为我们的 WCF 服务生成的默认 JavaScript Proxy
类有关。<enableWebScript />
有助于生成此默认代理。返回结果是带有一个“d
”参数的对象。这样做也是为了与上述代理一起工作。
如果您希望查看此默认生成的代理,您只需在服务文件名 TweetService.svc 后添加一个 js,如下面的屏幕截图所示
关于默认代理的一些有趣之处——除了代理文件开头明显的构造函数和样板代码之外——在文件的底部,我们发现以下有趣的部分
突出显示的是访问我们的 AJAX web service 的确切 URL……
突出显示的是我们默认 DoWork
方法的函数定义……
因此,在我们的网页中包含此脚本将使我们能够连接到我们的服务并使用 JavaScript 调用我们的 DoWork
方法!
最后一个有趣的部分是调用我们的方法 DoWork
的函数定义。
所以,上面的截图表明对 DoWork
方法的调用需要 3 个参数。
onSuccess
:这是一个处理程序,在 AJAX 服务调用成功完成后执行。Web 方法调用传递的任何数据都将传递给此onSuccess
函数。onFailed
:这是一个处理程序,如果 AJAX 服务调用因某种原因失败,它将执行。任何返回的错误数据都将传递给此onFailed
函数。userContext
:这允许传递用户相关数据。
现在我们已经创建了一个 WCF AJAX Web Service 项目,并花了很多时间运行和理解它……现在是时候在我们的 WCF AJAX Service 项目 Tweet.WCFService.AJAX
中引入一些相关的业务代码了。这将在下一节中完成。
构建 WCF AJAX 服务项目(用于 TweetBL 项目的业务功能)
是时候构建我们的真实 AJAX 服务并删除 DoWork
方法了!让我们深入了解 TweetBL 项目 - ManageTweet.cs:这个类包含管理推文所需的所有业务代码。我们将把所有这些方法作为 AJAX Web 服务公开。
在 Tweet.WCFService.AJAX
项目的 TweetService.svc 中,我们已包含了对 TweetBL
项目的 ManageTweet.cs 的引用,并且如上图所示,我们所做的只是将收到的对任何 TweetService.svc 方法的调用传递给 ManageTweet
类方法来完成实际工作。
简单来说,我们所做的只是在我们的 service
类中调用业务类来完成实际工作。
运行 WCF AJAX 服务项目(现在包含我们的业务代码)
现在我们准备好运行我们的推文服务了!它不会有什么不同……但是,是的,我们需要遵循一些额外的步骤来运行一些不实现 GET
动词(WebGet
属性)但实现 WebInvoke
属性的方法。如下面(在 TweetService.svc 中)指出
相信我,这很有趣……
测试 GetTweets() 方法:按照下面屏幕截图中的突出显示步骤操作:运行服务
输入方法名 GetTweets
GetTweets
方法结果(未格式化)
请注意,我们的每个 Tweet
属性后面都附加了 k__BackingField
……这是因为我们没有用 DataContract
属性标记我们的 Tweet
类(TweetBL
项目),也没有用 DataMember
属性标记其字段。
快速回顾:数据契约定义了将由 Web 服务操作发送和接收的数据的类型和格式。数据成员属性应用于 DataContract
类的字段,这些字段将被序列化。
我之前的一篇文章中对 WCF 契约进行了相当多的描述,相关部分可以在这里找到。
将属性应用于 Tweet.cs
噢!红色的波浪线……啊……这只是表示您的 TweetBL
项目中没有引用“Serialization
”程序集!
namespace TweetBL
{
using System;
using System.Runtime.Serialization;
.... remaining code...
让我们快速添加对“Serialization
”程序集的引用
世界再次变得美好起来……
再次运行 TweetService.svc... 我们得到以下结果:k__BackingField
不再附加。
让我们运行 GetTweetById()
方法。此方法用 WebGet
属性修饰,但它也期望传入一个 int 类型的参数……太棒了……
运行 TweetService.svc 并调用 GetTweetById
方法而不传递 int
参数将得到以下 NULL
结果
我们得到了 null
,因为 WCF 尽力匹配所需的参数(在本例中为 int
),当匹配失败时,它为所需的参数分配了默认值。因此,在本例中,对于 int
,WCF 为其分配了值 0
。显而易见,我们没有 id = 0
的记录,因此返回 null
。
我们所需要做的就是传递所需的参数(见下文)
注意:get
URI 中的参数名称应与方法上声明的参数名称匹配!
所以,这是一个简单的演示,展示了如何运行一个用 WebGet
属性装饰的服务操作/方法!
是时候看看 TweetService.svc 类中用 WebInvoke
属性修饰的其他操作了……
WebGet
和 WebInvoke
属性之间的主要区别在于,它使用 POST
动词而不是 WebGet
使用的 GET
动词。
为什么要使用 WebInvoke
?嗯,WebInvoke
属性使用其他 HTTP 动词(如 POST
、PUT
和 DELETE
)公开服务操作/方法。这些操作旨在 修改
资源;因此,WebInvoke
属性用于修改资源。注意:默认选项是 POST
,但您可以通过设置 WebInvoke
属性的 Method 属性来更改它。如下所示
[OperationContract]
[WebInvoke(Method = "PUT")]
public void PutQuestion(int id, Question question)
{
// Put question in database
}
注意* 在本文中,我们将坚持使用默认的 POST
。
另一个需要记住的有趣事情是,所有网络浏览器都经过优化,以满足 GET
动词请求。它们会缓存 Get
请求的结果,并且每次浏览器刷新时,结果都会从浏览器缓存中重新获取,而不是向 Web 服务器发出请求。
因此,出于显而易见的原因,当您执行 创建
、更新
或 删除
操作时,您不希望浏览器缓存这些操作的结果!所以,我们使用不同的动词,如 Put
、Post
等,来表明我们不希望缓存这些操作的结果,并且一旦 Put
、Post
操作成功完成,我们总是希望刷新数据。这是双赢!
现在,继续……如果我们尝试运行用 WebInvoke
装饰的操作,就像我们调用用 WebGet
属性装饰的操作一样,我们会得到以下结果
我们收到了“不允许的方法”消息,因为我们为 CreateTweet
操作指定了 WebInvoke
属性。
我们现在要问的问题是……我们如何测试我们的 WebInvoke 方法 CreateTweet?简单的答案是使用“POSTMAN”。
POSTMAN:是一个 Google Chrome 插件,允许我们创建 HTTP Get
/Put
/Post
/Delete
请求!这正是我们所需要的!
有些问题的答案是需要寻找的……嗯,这个问题不属于其中。 :) 感谢 Google。
废话不多说,把它添加到浏览器中……
运行 POSTMAN 同样简单,在 Chrome 中打开一个新标签页,点击应用网格,然后你就可以找到它了。
输入我们本地 CreateTweet
操作的 URL。
请记住它是一个 WebInvoke
方法,所以将选项更改为 POST
。
点击“Header”按钮!我们想表明我们将向服务器发送 JSON 格式的数据
让我们输入 Header 和 Value……这样我们的请求对服务器来说就一清二楚了!
切换到 RAW 模式并选择 JSON..
是时候行动了!我们将发送一个特定格式的请求……在这种情况下,它将是一个 Tweet
对象——包含它的所有 3 个属性。
回忆一下 3 个 Tweet
属性! - Tweet.cs(在 TweetBL
项目中)
是时候点击 发送 了。
哎哟,真疼……
我们收到了一个错误——WCF 传递给我们一些选项,我们可以使用它们来获取服务器上发生问题的更多详细信息!例如:在上面的屏幕截图中,我们被建议打开 includeExceptionDetailInFaults
,所以让我们这样做……
在我们的 Tweet.WCFService.AJAX
项目中,让我们更新 Web.config 文件,将 includeExceptionDetailInFaults
选项设置为 true
。这是一个调试选项,只应在开发期间使用,确保在服务即将部署时将其关闭(设置为 false
)。
// Let us add the following service behaviour to our Web.Config file
<serviceBehaviors>
<behavior name="reportIssues">
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
reportIssues
是我们给行为起的名字。includeExceptionDetailInFaults
已设置为 true
,表示我们希望将服务器上发生的异常详细信息传递给客户端。注意* includeExceptionDetailInFaults
设置在 serviceDebug
元素下。
现在,我们需要将此新行为与我们的服务关联起来。
// Associating the new behaviour with our service
<service name="Tweet.WCFService.AJAX.TweetService"
behaviorConfiguration="reportIssues" >
<endpoint
address=""
behaviorConfiguration =
"Tweet.WCFService.AJAX.TweetServiceAspNetAjaxBehavior"
binding="webHttpBinding"
contract="Tweet.WCFService.AJAX.TweetService" />
</service>
这是进行上述更改后 Web.config 文件的屏幕截图。
Web.config 已更新。让我们再次运行服务。
现在,我们得到了上面突出显示的信息!
服务器正在抱怨对象引用未设置为对象的实例……
我必须承认这并没有太大帮助,但我们必须利用现有的资源……而且由于我之前遇到过这个问题,我可以告诉你问题是什么!
CreateTweet
操作的屏幕截图(注意:参数名称)
我们的 JSON 请求消息的屏幕截图(注意:我们的 Tweet
对象的名称)
瞧,是参数名称不匹配的问题!让我们更正 json 请求中的对象名称,然后重试……
操作调用成功了!操作返回 null
,因为它的返回类型是 void
。
运行 GetTweets
方法以确认新记录已成功插入,结果如下面突出显示。
我希望这足够简单易懂。欢迎您使用 POSTMAN
测试所有其他服务操作。
我将把剩余的服务操作留给您自行尝试。下面是我对 UpdateTweet
和 DeleteTweet
操作进行单元测试的屏幕截图。
UpdateTweet
操作(请记住传入要更新的 Tweet
的 Id
)
UpdateTweet
操作后的 GetTweets
方法调用
DeleteTweet 操作(注意:我们的请求 JSON 对象)
DeleteTweet
操作后的 GetTweets
方法调用:Id = 5
的推文未返回!因为它已被删除。
WCF AJAX Web Service 从 JSON 切换到 XML
WCF AJAX Web Services 的默认设置是期望以 JSON 格式发送和接收数据。主要原因是 WCF AJAX Web Services 旨在与 JavaScript 配合使用,而 JavaScript 更喜欢并非常适合 JSON。我们可以通过以下步骤将其更改为 XML
// Tweet.WCFService.AJAX Project
// TweetService.svc
//
// Changing the GetTweets Operation to return XML rather than JSON
// Default is JSON.
//
// Modifying ResponseFormat to XML for WebGet Attribute.
[OperationContract]
[WebGet(ResponseFormat=WebMessageFormat.Xml)]
public IList<Tweet> GetTweets()
{
return _businessLayerTweetService.GetTweets();
}
重新运行 GetTweets
操作:
结果是 XML 格式!
创建 WCF AJAX Web Service 客户端
Postman 对于快速单元测试来说很好用。现在是时候构建我们自己的 Web 服务客户端了。让我们快速回顾一下为我们的服务生成的 JavaScript 库。我们现在拥有所有已定义的 Tweet 操作。
此外,要查看调试功能……您可以访问以下 URL。此文件基本上将在我们处理测试客户端(Web 服务客户端)时帮助我们在 Visual Studio 中进行代码补全。
现在,让我们继续为我们的服务编写一个合适的客户端。WCF AJAX Web Service 实际上是为了与基于 HTML-JavaScript 的客户端很好地配合而开发的。开发基于 HTML-JavaScript 的客户端要容易得多,因为我们不必担心序列化和反序列化等许多其他因素。所有这些都默认由我们完成。如果出于某种原因我们选择编写自己的独立客户端(我们可以选择任何客户端技术),那么我们将负责创建请求和响应对象,自己序列化和反序列化请求-响应对象,以及许多其他此类要求都将由我们来满足!这是因为 WCF AJAX Web Service 没有生成 WSDL。为了简单起见,我们将为我们的 Tweet
服务开发一个简单的基于 HTML-JavaScript 的客户端!我们将在客户端网页中使用默认生成的 JavaScript 代理类。我们需要添加一个 Web Form,转到 Tweet.WCFService.AJAX
项目中添加新项并选择 Web Form。
TweetClient.aspx 已添加到项目中!
我们将向 TweetClient.aspx 添加一个 ScriptManager
:这个 ScriptManager
将负责下载为我们的 TweetService
生成的默认 JavaScript Proxy
类!为此,我们需要向 ScriptManager
提供一个 服务引用(将在 Service
标签内声明)。该引用将要求我们向其传递一个指向我们的 Tweet
服务的 Path
。
// Tweet.WCFService.AJAX Project
// TweetClient.aspx
//
// ~: the tilde refers to the current application
<body>
<form id="form1" runat="server">
<asp:ScriptManager runat="server">
<Services>
<asp:ServiceReference Path="~/TweetService.svc" />
</Services>
</asp:ScriptManager>
<div>
</div>
</form>
</body>
TweetClient.aspx:
所以,现在 Script Manager 将包含为 Tweet
服务生成的 JavaScript 代理文件,它还将包含这个网页(TweetClient.aspx)在内部使用 TweetService Proxy
类所需的其他一些库。
就是这样……我们可以开始编写 JavaScript 来调用我们的 TweetService
方法了。
我们将在 TweetClient.aspx 的 Script
标签中执行以下操作
- 创建一条推文
- 更新一条推文
- 删除一条推文
- 检索所有推文
TweetClient.aspx Script
标签的屏幕截图
是时候测试我们的网页了。我们将在下一节中进行此操作。
使用我们的服务客户端测试 WCF AJAX Web Service
嗯,我们终于快完成了!按照下面的屏幕截图运行测试
输入 TweetClient.aspx...
我们的劳动成果!首先显示 CreateTweet
的成功警报消息!
现在是最终的 GetTweets
结果!
最后一条推文(Id = 5
)是我们通过 TweetClient.aspx Script
标签添加的记录!
有趣的一点
快速检查页面将发现,我们并没有添加一些其他的 Script
标签到我们的 HTML 页面中!
ScriptManager
为我们添加了它们。
例如:Web Resource 和 Script Resource 是由 ScriptManager
添加的。这些资源负责 WCF AJAX Web Services 的序列化和反序列化活动以及它们在后台执行的许多其他活动!
重要提示* 对 Create/Update/Delete 和 get 的调用不会按同步顺序执行……它们中的任何一个都可以在之前或之后调用。它们是异步执行的!
我知道 - 我说的是显而易见的!AJAX 响亮的名字! :)
快速查看 TweetClient.aspx 中的 DeleteTweet
方法:我已经注释掉了 Create
和 Update Tweet
的代码,因为我只想专注于 Delete
和 Get
。
运行 DeleteTweet
的测试
幸运的是,对我来说,DeleteTweet
在调用 GetTweets
之前被调用了!Id = 2
的推文已成功删除。
快速查看 TweetClient.aspx 中的 UpdateTweet
方法:我已经注释掉了 Create
和 Delete Tweet
的代码,因为我只想专注于 Update
和 Get
。
运行 UpdateTweet
的测试
幸运的是,这次对我来说,UpdateTweet
是在调用 GetTweets
之后被调用的!Id = 1
的推文已成功更新,但检索到的数据并未反映更改!这就是 AJAX。
刷新页面将反映更改:注意* 它也将再次执行 UpdateTweet
调用!但这对于我们来说是无害的。通常在生产代码中,我们有验证机制来阻止第二次更新。
我已将 Update
和 Delete Tweet
代码在 TweetClient.aspx 中注释掉了。
……我们完成了!
最终想法
这是一篇关于 WCF Web Service 的文章!由我撰写。它是一个简单的演示,展示了 WCF 的强大和简洁。
我该下线了。欢迎提出问题,提供反馈以及介于两者之间的所有内容,因为我们都在同一条船上。附注:这条船叫做“边烧边学”。
历史
- 2015年3月14日:提交版本 1