在我們玩wcf的時候,都會潛意識的覺得wcf就是通過soap協議交換消息的,并且可以在basic,tcp,msmq等等綁定中任意切換,
牛逼的一塌糊涂,但是呢,如果說哪一天wcf不再使用soap協議,而是采用json格式的字符串,是不是有一點顛覆你對wcf的認識的???
從傳統意義上說,wcf是非常重量級的,很明白的一個例子就是太多太多的配置,尤其是Behavior的配置,而且behavior對wcf來說又是重
中之重,它對wcf的擴展和性能又是最重要的,可恨的是wcf在binding,behavior,contract之中的配置又是非常非常的保守,可以說用
wcf來玩分布式,這些默認配置是完全做不到的,就比如說basicbinding的基類HttpBindingBase。

抱怨的話我也不說了,可能微軟也覺得這個問題是個不小的問題,然后就有了輕量級的 asp.net web api,你可以看到它和wcf比起來精
簡多了,也許讓我們這些碼農更加的專注于業務吧,既然wcf帶了這玩意,我也得必須約談一下。
## 一:UriTemplate
要說rest,還得先說UriTemplate,因為wcf用UriTemplate來做rest中的uri模板匹配,然后用WebInvoke這個OperationBehavior
插入到wcf的心臟中,說的玄乎一點,這個就有點像mvc中的路由匹配機制,下面我舉個例子:
1\. 用UriTemplate來告知可以監視的完整Url
從下面的圖中,可以看到三個元素:服務地址,模板,入參(這里面的”1“),這三個元素組合在一起,就構成了完整的remote url,
然后這個完整的url就是我模板(/User/{id})監視的對象。

2\. 通過UriTemplate來解析url中的參數。
既然可以構建url,那當然可以解析url啦,對吧,下面這張圖可以很清晰的告知你,當外來的url=http://127.0.1:1920/HomeService
/User/1過來的時候應該被哪個uriTemplate所接收。

正是因為UriTemplate具有這樣的url構建和解析能力,所以wcf就把UriTemplate作為WebInvoke和WebGet這兩個屬性的參數來動態
解析外來的url,然后根據這個url分配到具體的服務方法上,下面我們具體看一看。
## 二:WebGet,WebInvoke的使用
剛才也說了,WebGet和WebInvoke正是用了UriTemplate,才具有了路由轉向的功能,還有就是默認返回的是xml,這里就用json
值作為服務返回的格式
~~~
1 [ServiceContract]
2 public interface IHomeService
3 {
4 [OperationContract]
5 [WebGet(UriTemplate = "Get/{id}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
6 Student Get(string id);
7
8 [OperationContract]
9 [WebInvoke(Method = "POST", UriTemplate = "Add", RequestFormat = WebMessageFormat.Json,
10 ResponseFormat = WebMessageFormat.Json)]
11 string Add(Student stu);
12 }
~~~
對了,Rest推薦使用Http協議中的Get,Post,Delete,Put來作為CURD的狀態機制,然后就是你如果看懂了UriTemplate,那你現在應
該知道這個Template在監視什么類型的url。做完了上面的coding,下面我們需要在webconfig中通過behavior來指定啟動“web編程模型”,
就比如下面這樣。
~~~
1 <?xml version="1.0" encoding="utf-8"?>
2 <configuration>
3
4 <system.diagnostics>
5 <sources>
6 <source name="System.ServiceModel" switchValue="ActivityTracing">
7 <listeners>
8 <add name="mylisteners" type="System.Diagnostics.XmlWriterTraceListener" initializeData="E:\1.txt" />
9 </listeners>
10 </source>
11 <source name="System.ServiceModel.MessageLogging" switchValue="ActivityTracing">
12 <listeners>
13 <add name="messagelogging" type="System.Diagnostics.XmlWriterTraceListener" initializeData="E:\2.txt"/>
14 </listeners>
15 </source>
16 </sources>
17 <trace autoflush="true"/>
18 </system.diagnostics>
19
20 <system.serviceModel>
21
22 <diagnostics>
23 <messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtTransportLevel="true" />
24 </diagnostics>
25
26 <behaviors>
27 <serviceBehaviors>
28 <behavior>
29 <serviceMetadata httpGetEnabled="true" />
30 <serviceDebug includeExceptionDetailInFaults="true" />
31 </behavior>
32 </serviceBehaviors>
33 <endpointBehaviors>
34 <behavior name="webbehavior">
35 <webHttp />
36 </behavior>
37 </endpointBehaviors>
38 </behaviors>
39
40 <services>
41 <service name="MyService.HomeService">
42 <endpoint address="HomeService" binding="webHttpBinding" behaviorConfiguration="webbehavior"
43 contract="MyService.IHomeService">
44 <identity>
45 <dns value="localhost" />
46 </identity>
47 </endpoint>
48 <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
49 <host>
50 <baseAddresses>
51 <add baseAddress="http://127.0.0.1:1920" />
52 </baseAddresses>
53 </host>
54 </service>
55 </services>
56
57 </system.serviceModel>
58
59 </configuration>
~~~
其實呢?也就是代碼中的WebHttpBehavior類

好了,我現在服務地址也出來了:http://127.0.0.1:1920 ,然后服務方法的template也指定了。只要http.sys監控到了template
匹配的url,服務方法就會被執行,比如我現在在瀏覽器里面輸入:http://127.0.0.1:1920/HomeService/Get/1 ?來測試下Get操作。

可以看到,get方法成功了,也正確的匹配了我的服務方法Get。
~~~
1 public class HomeService : IHomeService
2 {
3 public Student Get(string id)
4 {
5 return new Student() { ID = Convert.ToInt32(id), Name = "hxc", SNS = "001" };
6 }
7
8 public string Add(Student stu)
9 {
10 return "hello";
11 }
12 }
~~~
然后我們看看Add方法,我在HttpWebRequest中模擬測試如下。

~~~
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Run();
6 }
7
8
9 /// <summary>
10 /// 報告系統錯誤
11 /// </summary>
12 /// <param name="ex"></param>
13 /// <returns></returns>
14 public static void Run()
15 {
16 HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://127.0.0.1:1920/HomeService/Add");
17 Encoding encoding = Encoding.UTF8;
18
19 string param = new JavaScriptSerializer().Serialize(new { ID = "10", Name = "hxc", SNS = "001" });
20 byte[] bs = Encoding.ASCII.GetBytes(param);
21
22 string responseData = String.Empty;
23 req.Method = "POST";
24 req.ContentType = "application/json";
25 req.ContentLength = bs.Length;
26 using (Stream reqStream = req.GetRequestStream())
27 {
28 reqStream.Write(bs, 0, bs.Length);
29 reqStream.Close();
30 }
31 using (HttpWebResponse response = (HttpWebResponse)req.GetResponse())
32 {
33 using (StreamReader reader = new StreamReader(response.GetResponseStream(), encoding))
34 {
35 responseData = reader.ReadToEnd().ToString();
36 }
37 }
38 }
39 }
~~~
View Code

好了,大概就說這么多了,如果說你不嫌麻煩,你可以用WCF Rest,還有就是不要忘了很多的默認配置,如果你覺得太繁瑣,
可以用用asp.net web api。

- 第一天 三種Binding讓你KO80%的業務
- 第二天 告別煩惱的config配置
- 第三天 client如何知道server提供的功能清單
- 第四天 你一定要明白的通信單元Message
- 第五天 你需要了解的三個小技巧
- 第六天 你必須要了解的3種通信模式
- 第七天 Close和Abort到底該怎么用才對得起觀眾
- 第八天 對“綁定”的最后一點理解
- 第九天 高級玩法之自定義Behavior
- 第十天 學會用SvcConfigEditor來簡化配置
- 第十一天 如何對wcf進行全程監控
- 第十二天 說說wcf中的那幾種序列化
- 第十三天 用WCF來玩Rest
- 第十四天 一起聊聊FaultException
- 終結篇 那些你需要注意的坑