十五天精通WCF——第十三天 用WCF來玩Rest

一線碼農發表於2015-07-23

  

        在我們玩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。

 

相關文章