看WCF Web API的第一印象
每隔幾天,就會(huì)打開(kāi)http://aspnet.codeplex.com去看看有什么動(dòng)態(tài),前兩天無(wú)意間打開(kāi)后發(fā)現(xiàn)了一個(gè)新東西,WCF Web API,本來(lái)我對(duì)WWW(WCF,WF,WPF)沒(méi)有啥好印象,雖然在各大招聘網(wǎng)站上好像需求量倒不小,但是我發(fā)現(xiàn)這個(gè)Web API貌似是有關(guān)REST的內(nèi)容,于是就多看了兩眼,發(fā)現(xiàn)果不其然。
不幸的是,現(xiàn)在Web API還是preview版本,文檔少的可憐,只有源代碼和一個(gè)幾乎沒(méi)有什么用的Sample,上網(wǎng)搜索也沒(méi)有結(jié)果。前兩天看到一句話(huà),大概意思是:前兩年大家都在考慮要不要REST,現(xiàn)在已經(jīng)開(kāi)始考慮如何REST了。
盡管如些,但是在.NET平臺(tái)上,REST好像還只是一種概念,研究的人都很少,更不要說(shuō)投入生產(chǎn)了。關(guān)于WCF,剛問(wèn)世時(shí)我倒是學(xué)習(xí)過(guò)一段時(shí)間,也做了幾個(gè)例子,但是引用WCF服務(wù)的那種方式我一直不喜歡,在客戶(hù)端中生成一堆代碼,然后再使用那個(gè)蹩腳的***Client來(lái)調(diào)用服務(wù),這就讓我產(chǎn)生一個(gè)疑問(wèn):在兩個(gè)客戶(hù)端中調(diào)用同一個(gè)服務(wù),難道需要生兩個(gè)Client不成?再則,既然是服務(wù),那就應(yīng)該是一個(gè)“開(kāi)放”的東西,雖然WSDL名聲顯赫,然則過(guò)于龐大繁復(fù),如果你想用瀏覽器來(lái)調(diào)用WCF的服務(wù),從現(xiàn)實(shí)上來(lái)說(shuō)似乎不太可能,如果從瀏覽器不能調(diào)用一個(gè)Web服務(wù)(當(dāng)然是GET),那這個(gè)Web服務(wù)似乎就不太純粹;最后,HTTP是一個(gè)完善的協(xié)議 ,對(duì)于操作數(shù)據(jù)尤為如此,無(wú)論多么復(fù)雜的需求,最終對(duì)于數(shù)據(jù)而言無(wú)外乎增刪改查耳,HTTP都具有了,作為一個(gè)真正開(kāi)放、通用的服務(wù)來(lái)說(shuō),使用HTTP的基本方法,幾乎沒(méi)有不能完成的任務(wù)。于是對(duì)于操作"用戶(hù)"數(shù)據(jù)而言,使用GET、POST、PUT、DELETE足已,實(shí)在沒(méi)有必要再自定義一些諸如GetUser,CreateUser之類(lèi)的RPC方法,為啥一定得要人花一番工夫才能知道添加一個(gè)用戶(hù)到底是用Create還是Add呢?從某種意義來(lái)說(shuō),每一個(gè)網(wǎng)站實(shí)際上都是一個(gè)Web服務(wù),不是嗎?基于HTTP,提供數(shù)據(jù),只要你輸入對(duì)URL,它永遠(yuǎn)都會(huì)將你想要的結(jié)果呈現(xiàn)在你的眼前,如果這樣一個(gè)服務(wù),你要使用類(lèi)似WCF的框架去提供,使用這個(gè)Web服務(wù)的人會(huì)如何評(píng)價(jià)呢?他永遠(yuǎn)不知道在你的“服務(wù)”后面是加一個(gè)View還是Get抑或是Display...
然而,做技術(shù)的人往往喜歡把一個(gè)簡(jiǎn)單的問(wèn)題想的無(wú)限大,然后再整出一個(gè)周身毛病的解決方案,等引誘人家去上當(dāng),到最終滿(mǎn)頭包時(shí),才回歸到問(wèn)題本質(zhì),推出一個(gè)兼顧的方案,如果這還說(shuō)的不透徹,那么試想,你現(xiàn)在需要剪刀,然而很快專(zhuān)家們就設(shè)計(jì)出了瑞士軍刀,因?yàn)樗麄兿氲侥阋院蠛芸赡苓€會(huì)需要用...,到最后,你發(fā)現(xiàn)你使用幾乎天天用剪刀,那些掏耳勺,鑷子,起瓶器之類(lèi)的幾乎不用,最后,手里還是拿了把張小泉。記得以前看過(guò)一句話(huà):請(qǐng)把牛B還給牛,我想說(shuō)的是,請(qǐng)把HTTP還給HTTP,無(wú)論是在前端還是在服務(wù)端。
這兩天映入眼簾的東西較多,有IronJS,MongoDB,還有就是正在說(shuō)的這個(gè)WCF Web API了,其實(shí)這段時(shí)間我正在做一個(gè)類(lèi)似的框架,是在ASP.NET MVC上開(kāi)發(fā)一個(gè)輕量級(jí)的REST框架(說(shuō)框架好像有點(diǎn)抬舉自已了),基本思路是使用MVC的Action作為數(shù)據(jù)服務(wù),使用M$的Syndication來(lái)做數(shù)據(jù)傳遞格式,使用WebRequest以及WebResponse來(lái)手工向服務(wù)發(fā)起請(qǐng)求以及回傳響應(yīng),目前支持Atom和JSON格式的內(nèi)容,核心部分已經(jīng)完工了,本來(lái)打算投入使用后寫(xiě)幾篇說(shuō)明和各位兄弟探討,但是現(xiàn)在又發(fā)現(xiàn)了WCF Web API,這讓我很糾結(jié),不知道該是繼續(xù)呢還是先研究下Web API。昨天把那本《MongoDB權(quán)威指南》算是粗讀了一遍,今天晚上閑來(lái)無(wú)事,又把那個(gè)WCF Web API的源碼包打開(kāi)看了看,了解下這個(gè)所謂的Web API到底是怎么回事,內(nèi)容不多,但是由于下周有個(gè)項(xiàng)目有新需求要增加,而從下下周開(kāi)始要休假一段時(shí)間,因此有必須把今天看的東西記錄下來(lái),以免再過(guò)20來(lái)天,又不知丟到哪里去了。
要了解一個(gè)ASP.NET應(yīng)用的原理,還是得看Global、HttpHandler、HttpModel,在Web API的示例(ContactManager_Advanced)中,沒(méi)有發(fā)現(xiàn)顯示使用HttpHandler和HttpModel,那就只能看Global了:
- protected void Application_Start(object sender, EventArgs e)
- {
- // use MEF for providing instances
- var catalog = new AssemblyCatalog(typeof(Global).Assembly);
- var container = new CompositionContainer(catalog);
- var config = HttpHostConfiguration.Create().
- AddFormatters(
- new ContactPngFormatter(),
- new ContactFeedFormatter("http://localhost:9000/Contact"),
- new VCardFormatter(),
- new CalendarFormatter()).
- SetResourceFactory(new MefResourceFactory(container)).
- AddMessageHandlers(typeof (LoggingChannel), typeof (UriFormatExtensionMessageChannel));
- SetMappings();
- RouteTable.Routes.MapServiceRoute<ContactResource>("Contact", config);
- RouteTable.Routes.MapServiceRoute<ContactsResource>("Contacts", config);
- }
有意義的顯然是這段了,
catalog變量是指MEF用于導(dǎo)入的目錄,container是組合容器,有了這兩個(gè)對(duì)象實(shí)例后,就開(kāi)始創(chuàng)建一個(gè)HttpHostConfiguration的實(shí)例,使用一些自定義的Formatter,Formatter是啥用通呢?如果你了解AtomEntry,那就知道,AtomEntry里面實(shí)際是一種格式,它定義了一些固定的內(nèi)容(屬性),比如:Id,Title,Summary,Link之類(lèi)的,對(duì)于一個(gè)User實(shí)體來(lái)說(shuō),UserName如何表示呢,當(dāng)能只能去擴(kuò)展這個(gè)AtomEntry了,而這個(gè)Formatter就是擴(kuò)展這個(gè)AtomEntry的。SetResourceFactory,這個(gè)方法的作用是定義一個(gè)資源工廠(chǎng),啥是資源?在REST中,把用戶(hù)需要請(qǐng)求操作的服務(wù)即稱(chēng)為資源,http://localhost/User,這是一個(gè)Url,沒(méi)錯(cuò),但是這個(gè)Url就代表User服務(wù),它就是個(gè)資源,每一個(gè)Url就代表一個(gè)資源,但是http://localhost/User?id=think8848和http://localhost/User是同一個(gè)資源,這其中的道理不難理解,但是設(shè)計(jì)可訪(fǎng)問(wèn)的資源也是一個(gè)比較復(fù)雜的話(huà)題,這里不做詳細(xì)說(shuō)明了,有興趣的朋友可以參考《RESTful Web Service》一書(shū)。
那么在這段代碼中,到底是如何設(shè)置資源,又是如何使用資源的呢?這里使用M$的MEF,MEF是一個(gè)比較復(fù)雜的框架,簡(jiǎn)單的說(shuō)吧,它有點(diǎn)類(lèi)似于依賴(lài)注入,M$對(duì)于它定義如下:“Managed Extensibility Framework 或 MEF 是一個(gè)用于創(chuàng)建可擴(kuò)展的輕型應(yīng)用程序的庫(kù)。 應(yīng)用程序開(kāi)發(fā)人員可利用該庫(kù)發(fā)現(xiàn)并使用擴(kuò)展,而無(wú)需進(jìn)行配置。 擴(kuò)展開(kāi)發(fā)人員還可以利用該庫(kù)輕松地封裝代碼,避免生成脆弱的硬依賴(lài)項(xiàng)。 通過(guò) MEF,不僅可以在應(yīng)用程序內(nèi)重用擴(kuò)展,還可以在應(yīng)用程序之間重用擴(kuò)展。”。也就是說(shuō),使用MEF,可以獲取某些符合條件(通過(guò)特性Attribute檢索的)的接口實(shí)例。在這里設(shè)置一個(gè)ResourceFactory,當(dāng)調(diào)用到達(dá)時(shí),就會(huì)在這個(gè)ResourceFactory中去找服務(wù)的實(shí)例,在我們自已的程序中,可以使用其他方法達(dá)到資源工廠(chǎng)的功能,比如Ioc框架。AddMessageHandlers這個(gè)名字看起來(lái)比較直觀,以我現(xiàn)在的觀察,之前我們使用HttpRequest好像都變成了HttpRequestMessage了,于是我們姑且把這個(gè)Message看成是Request,這樣,就可以很清楚的看到,AddRequestHandler就是在添加請(qǐng)求的處理程序。初步猜測(cè),在這個(gè)處理程序中,應(yīng)該能做諸如權(quán)限控制之類(lèi)的工作。
最后兩句,關(guān)鍵詞是MapServiceRoute,這其實(shí)是一個(gè)擴(kuò)展方法,就定義在WCF Web API中,方法是為泛型參數(shù)類(lèi)型的服務(wù)注冊(cè)一個(gè)UrlRouting的規(guī)則,至此,事情就回到了MVC的范疇之類(lèi)了。
對(duì)于WCF Web API,調(diào)試了源代碼,感覺(jué)比MVC框架要復(fù)雜的多,今天發(fā)現(xiàn)的東西實(shí)在很多,還得以后慢慢消化了。
原文鏈接:http://www.cnblogs.com/think8848/archive/2011/07/23/2115127.html
【編輯推薦】