本主题概述了将基本 ASP.NET AJAX 服务迁移到已启用 AJAX 的等效 Windows Communication Foundation (WCF) 服务的过程。 它演示了如何为 ASP.NET AJAX 服务创建在功能上等效的 WCF 版本。 随后可以并行使用这两项服务,也可以用 WCF 服务替换 ASP.NET AJAX 服务。
将现有的 ASP.NET AJAX 服务迁移到 WCF AJAX 服务具有下列优点:
只需最少的额外配置,即可将 AJAX 服务公开为 SOAP 服务。
可以获得 WCF 功能(例如跟踪等)所带来的好处。
下面的过程假定你正在使用 Visual Studio 2012。
从本主题概述的过程中得到的代码将在过程后面的示例中提供。
若要详细了解如何通过已启用 AJAX 的终结点公开 WCF 服务,请参阅如何:使用配置来添加 ASP.NET AJAX 终结点主题。
创建并测试 ASP.NET Web 服务应用程序
打开 Visual Studio 2012。
从“文件”菜单中选择“新建”,然后依次选择“项目”、“Web”和“ASP.NET Web 服务应用程序”。
给该项目命名,然后单击“确定”
ASPHello
。在 Service1.asmx.cs 文件中,取消对包含
System.Web.Script.Services.ScriptService]
的行的注释,以便为此服务启用 AJAX。从“构建”菜单中,选择“构建解决方案”。
从“调试”菜单中选择“开始执行(不调试)”。
在生成的网页上,选择
HelloWorld
操作。在
HelloWorld
测试页上单击“调用”按钮。 您应收到以下 XML 响应。<?xml version="1.0" encoding="utf-8" ?> <string xmlns="http://tempuri.org/">Hello World</string>
此响应可确认您现在已拥有一项能正常运行的 ASP.NET AJAX 服务。具体而言,该服务现在已在 Service1.asmx/HelloWorld 处公开了一个响应 HTTP POST 请求并返回 XML 的终结点。
现在可以转换此服务以使用 WCF AJAX 服务了。
创建等效的 WCF AJAX 服务应用程序
右键单击“ASPHello”项目,然后依次选择“添加”、“新建项”和“启用了 AJAX 的 WCF 服务”。
为服务
WCFHello
命名,然后单击“添加”。打开 WCFHello.svc.cs 文件。
在 Service1.asmx.cs 中,复制
HelloWorld
操作的以下实现。public string HelloWorld() { return "Hello World"; }
将复制的
HelloWorld
操作的实现粘贴到 WCFHello.svc.cs 文件中,并替换下面的代码。public void DoWork() { // Add your operation implementation here return; }
将 ServiceContractAttribute 的
Namespace
属性指定为WCFHello
。[ServiceContract(Namespace="WCFHello")] [AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Required)] public class WCFHello { … }
将 WebInvokeAttribute 添加到
HelloWorld
操作,并将 ResponseFormat 属性设置为返回 Xml。 请注意,如果未设置此属性,则默认返回类型为 Json。[OperationContract] [WebInvoke(ResponseFormat=WebMessageFormat.Xml)] public string HelloWorld() { return "Hello World"; }
从“构建”菜单中,选择“构建解决方案”。
打开 WCFHello.svc 文件,然后从“调试”菜单中选择“开始执行(不调试)”。
现在,该服务会在
WCFHello.svc/HelloWorld
处公开一个响应 HTTP POST 请求的终结点。 HTTP POST 请求不能从浏览器进行测试,但终结点会返回以下 XML。<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">Hello World</string>
在功能上,
WCFHello.svc/HelloWorld
和Service1.aspx/HelloWorld
终结点现在是等效的。
示例
从本主题概述的过程中得到的代码将在下面的示例中提供。
//This is the ASP.NET code in the Service1.asmx.cs file.
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Linq;
using System.Web.Script.Services;
namespace ASPHello
{
/// <summary>
/// Summary description for Service1.
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
}
//This is the WCF code in the WCFHello.svc.cs file.
using System;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
namespace ASPHello
{
[ServiceContract(Namespace = "WCFHello")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class WCFHello
{
// Add [WebInvoke] attribute to use HTTP GET.
[OperationContract]
[WebInvoke(ResponseFormat=WebMessageFormat.Xml)]
public string HelloWorld()
{
return "Hello World";
}
// Add more operations here and mark them with [OperationContract].
}
}
XmlDocument 不支持 DataContractJsonSerializer 类型,因为此类型不能被 XmlSerializer 序列化。 可以改用 XDocument 类型或序列化 DocumentElement。
如果要升级 ASMX Web 服务并将其并行迁移到 WCF 服务,请避免将两种类型映射到客户端上的同一名称。 如果 WebMethodAttribute 和 ServiceContractAttribute 中使用了同一类型,则这将导致序列化程序中出现异常:
如果首先添加 WCF 服务,则对 ASMX Web 服务调用方法将导致 ConvertValue(Object, Type, String) 中出现异常,因为代理中顺序的 WCF 样式定义优先。
如果首先添加 ASMX Web 服务,则对 WCF 服务调用方法将导致 DataContractJsonSerializer 中出现异常,因为代理中顺序的 Web 服务样式定义优先。
DataContractJsonSerializer 和 ASP.NET AJAX JavaScriptSerializer 在行为上存在很大差异。 例如,DataContractJsonSerializer 将字典表示为键/值对的数组,而 ASP.NET AJAX JavaScriptSerializer 则将字典表示为实际的 JSON 对象。 因此,下面是用 ASP.NET AJAX 表示的字典。
Dictionary<string, int> d = new Dictionary<string, int>();
d.Add("one", 1);
d.Add("two", 2);
在下面的列表中:此字典用 JSON 对象表示:
DataContractJsonSerializer 将其表示为 [{"Key":"one","Value":1},{"Key":"two","Value":2}]
ASP.NET AJAX JavaScriptSerializer 将其表示为 {"one":1,"two":2}
DataContractJsonSerializer 可以处理其中的键类型不是字符串的词典,而 JavaScriptSerializer 则无法处理,在这一方面前者的功能更为强大。 但后者与 JSON 的兼容性更好。
下表汇总了这些序列化程序之间的重大差异。
差异类别 | DataContractJsonSerializer | ASP.NET AJAX JavaScriptSerializer |
---|---|---|
将空缓冲区(新 byte[0])反序列化为 Object(或 Uri,或某些其他类)。 | SerializationException | Null |
Value 的序列化 | {} (or {"__type":"#System"}) | Null |
[Serializable] 类型的私有成员的序列化。 | 已序列化 | 未序列化 |
ISerializable 类型的公共属性的序列化。 | 未序列化 | 已序列化 |
JSON 的“扩展” | 遵循 JSON 规范,该规范要求为对象成员名称加上引号 ({"a":"hello"})。 | 支持不带引号的对象成员名称 ({a:"hello"})。 |
DateTime 协调世界时 (UTC) | 不支持格式“\/Date(123456789U)\/”或“\/Date\(\d+(U|(\+\-[\d{4}]))?\)\\/)”。 | 支持 DateTime 值采用“\/Date(123456789U)\/”和“\/Date\(\d+(U|(\+\-[\d{4}]))?\)\\/)”格式。 |
词典的表示形式 | KeyValuePair<K,V> 的数组,处理不是字符串的键类型。 | 作为实际的 JSON 对象 - 但仅处理是字符串的键类型。 |
转义符 | 始终应带有转义正斜杠 (/);切勿使用非转义的无效 JSON 字符,例如“\n”。 | 对于 DateTime 值,带有转义正斜杠 (/)。 |