MSDN的Windows Communication Foundation (WCF) Samples里AJAX部分同样也提供了丰富的例子供学习,第一个是JSONP的例子,这个例子基于JSONP提供WCF REST服务,
首先我们看看WCF服务端的实现,有几点需要mark一下:
1. 例子中的SVC使用WebScriptServiceHostFactory,
<%@ ServiceHost Factory=”System.ServiceModel.Activation.WebScriptServiceHostFactory”%>
WebScriptServiceHostFactory会自动添加一个WebScriptEndPoint到服务里,如果没有其他终结点等配置的需要,<system.ServiceModel>这个节其实可以直接从Web.config里直接移掉
2. 服务的方法通过WebGetAttribute属性来标记,这样可以确保服务响应Http Get请求,并且默认采用JSON格式
例子中的标记如下:
[WebGet(ResponseFormat = WebMessageFormat.Json],但实际上等价于[WebGet]
这个配合web.config里的
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<standardEndpoints>
<webScriptEndpoint>
<standardEndpoint name="" crossDomainScriptAccessEnabled="true"/>
</webScriptEndpoint>
</standardEndpoints>
</system.serviceModel>
当crossDomainScriptAccessEnabled
设置为true并且response format设置为JSON时,WCF将提供REST服务,客户端web page可以通过类似于URL
http://localhost:33695/CustomerService/GetCustomer?callback=Sys._json0来访问
而服务器端的返回值类似于:Sys._json0({"__type":"Customer:#Microsoft.Samples.Jsonp","Address":"1 Example Way","Name":"Bob"});
3. 此例服务端脚本的写法有别于Getting Started的例子,所有的脚本均在service.cs里实现,通过Service来进行标记:
%@ServiceHost Service=”Microsoft.Samples.Jsonp.CustomerService”%>
4. 服务契约标记了命名空间“JsonAjaxService”,这个将是客户端访问时使用的命名空间:
[ServiceContract(Namespace=”JsonAjaxService”)]
回过头来看看客户端的实现,也有几点想mark一下的:
1. 关于javascript defer,这个以前没有接触过,defer的目的在于让脚本等待所有的DOM元素加载完毕后再执行,具体用法如下:
<script type=”text/javascript” defer=”defer”>makeCall();</script>,此处的方法makeCall()会在DOM元素加载完毕后再执行,
这个可以帮助解决经常在代码执行如getElementById方法由于对象DOM还没有加载完毕而失败的问题,而且与onload相比,defer可以延缓脚本的加载,从而提高page的加载速度
关于defer的更多介绍,参看http://www.w3schools.com/tags/att_script_defer.asp,目前仅IE支持,这里有更详细的测试结果。
2. 我们看看具体的javascript脚本实现
function makeCall(){ var proxy = new JsonpAjaxService.CustomerService(); proxy.set_enableJsonp(true); proxy.GetCustomer(onSuccess, onFail, null); } function onSuccess(result){ document.getElementById(“name”).value = result.Name; document.getElementById(“address”).value = result.Address; } function onFail(result){ document.getElementById(“name”).value = “Error”; document.getElementById(“address”).value = “Error”; }
注意其中new的对象是JsonpAjaxService.CustomerService,分别是我们标记的命名空间和定义的类
此外,set_enableJsonp指定要支持JSONP.
3. 最后我们再看一点
<asp:ScriptMangager ID=“ScriptManager1” runat=“server”>
<Services>
<asp:ServiceReference Path=” http://localhost:33695/service.svc” />
</Services>
</asp>
此段代码提供了对WCF REST服务的访问引用
PostWCF服务
以上的例子是基于HTTP GET请求,基于HTTP POST请求的代码大同小异
首先,与以上的例子相比,客户端的访问代码不需要任何修改;
其次,服务器端的方法标记上[WebInvoke]就可以了
1 [ServiceContract(Namespace = "PostAjaxService")]
2 public interface ICalculator
3 { [WebInvoke]
4 double Add(double n1, double n2);
5 //Other operations omitted…
6 }
返回对象的WCF服务
只提一点:一切尽在代码中(OnSucess方法里清晰的表明了如何在客户端脚本里访问返回的对象属性值)。但没有直接确认过,返回的内容应该是JSON的格式
代码
1 [DataContract]
2 public class MathResult
3 {
4 [DataMember]
5 public double sum;
6 [DataMember]
7 public double difference;
8 [DataMember]
9 public double product;
10 [DataMember]
11 public double quotient;
12 }
13
14 function onSuccess(mathResult){
15 document.getElementById("sum").value = mathResult.sum;
16 document.getElementById("difference").value = mathResult.difference;
17 document.getElementById("product").value = mathResult.product;
18 document.getElementById("quotient").value = mathResult.quotient;
19 }
返回基于XML格式的WCF服务
首先分析的还是服务端脚本:
1. 最重要的下面这段,使用的是WebServiceHostFactory而不是WebScriptServiceHostFactory哟
1 %@ServiceHost language="c#" Debug="true" Service="Microsoft.Samples.XmlAjaxService.CalculatorService" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %
2. 相对应的,config里面是webHttpEndPoint而不是webScriptEndPoint
代码
<system.serviceModel>
<standardEndpoints>
<webHttpEndpoint>
<!-- Use this element to configure the endpoint -->
<standardEndpoint name="" />
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
3. 微软提供的Sample有一个对比,可以很清晰的看到对返回Json和XML的区别
1 [WebInvoke(ResponseFormat=WebMessageFormat.Json, BodyStyle=WebMessageBodyStyle.Wrapped)]
2 MathResult DoMathJson(double n1, double n2);
3
4 [WebInvoke(ResponseFormat=WebMessageFormat.Xml, BodyStyle=WebMessageBodyStyle.Wrapped)]
5 MathResult DoMathXml(double n1, double n2);
客户端的脚本变化比较大,通过XML请求来做
1 <script type="text/javascript">
2 function makeCall(operation){
3 var xmlHttp;
4 try{
5 xmlHttp = new XMLHttpRequest();
6 }catch(e){
7 try{
8 xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
9 }catch(e){
10 try{
11 xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
12 }catch(e){
13 alert("This sample only works in browsers with AJAX support");
14 return false;
15 }
16 }
17 }
18
19 //Create result handler
20 xmlHttp.onreadystatechange=function(){
21 if(xmlHttp.readyState == 4){
22 document.getElementById("result").value = xmlHttp.responseText;
23 }
24 }
25
26 var url = "service.svc/";
27 url = url + operation;
28
29 //Build the body of the JSON message
30 var body = '{"n1":';
31 body = body + document.getElementById("num1").value + ',"n2":';
32 body = body + document.getElementById("num2").value + '}';
33
34 //Send the HTTP request
35 xmlHttp.open('POST', url, true);
36 xmlHttp.setRequestHeader("Content-type", "application/json");
37 xmlHttp.send(body);
38 }
39 </script>
DataContractJsonSerializer
叉开谈一下这个类用来序列化当前的数据成JSON的格式和利用JSON格式的数据实例化类,没有过多需要说明的,一切都在代码里:
1 using System;
2 using System.IO;
3 using System.Runtime.Serializatin;
4 using System.Runtime.Serialization.Json;
5
6 namespace Microsoft.samples.JsonSerialization
7 {
8 class Sample{
9 static void Main(){
10 Person p = new Person();
11 p.name = "John";
12 p.age = 42;
13
14 MemoryStream stream1 = new MemoryStream();
15 //Serialize the Person object to a memory stream using DataContractJsonSerializer;
16 DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Person));
17 ser.WriteObject(stream1, p);
18
19 //Show the JSON outpu.
20 stream1.Position = 0;
21 StreamReader sr = new StreamReader(stream1);
22 Console.Write("JSON form of Person object: ");
23 Console.WriteLine(sr.ReadToEnd());
24
25 //Deserialize the JSON back into a new Person object.
26 stream1.Position = 0;
27 Person p2 = (Person)ser.ReadObject(stream1);
28
29 //Show the results.
30 Console.Write("Deserialized back, got name=");
31 Console.Write(p2.name);
32 Console.Write(",age=");
33 Console.WriteLine(p2.age);
34
35 Console.WriteLine("Press <ENTER> to terminate the program.");
36 Console.ReadLine();
37 }
38 }
39
40 [DataContract]
41 class Person{
42 [DataMember]
43 internal string name;
44
45 [DataMember]
46 internal int age;
47 }
48
49
50 }