整合分布式應(yīng)用程序經(jīng)常是一件非常困難并且錯綜復(fù)雜的任務(wù),即使是最富有經(jīng)驗的開發(fā)者也可能會覺得頭疼。當(dāng)應(yīng)用程序在不同的操作系統(tǒng)以及涉及不同的程序平臺時,這個集成問題變得尤其復(fù)雜。雖然說,web服務(wù)承諾可以減輕程序員完成集成任務(wù)的困難程度,但是也可能給程序員們帶來一些意想不到的麻煩。在這里我們將把一個asp.net應(yīng)用程序和一個php web服務(wù)連結(jié)起來,以學(xué)習(xí)一些整合分布式應(yīng)用程序的方法,以及必要的應(yīng)對措施,包括運行什么以及不用去做什么。
這個web服務(wù)在一個apache服務(wù)器上運行,并且使用php開發(fā)。它從各種微軟新聞組檢索新聞?wù)约八鼈兊年P(guān)聯(lián)的文本。即使由這個服務(wù)提供的數(shù)據(jù)可以直接使用內(nèi)部的。net對象存取,但是這個服務(wù)還是將使用并提供一個連接到非。net平臺上的不錯的演示。我們這里要討論的實例基于。net beta 2版。
創(chuàng)建一個web服務(wù)代理
visual studio.net提供了一個出色的機制用于自動地生成可用于存取遠(yuǎn)程web服務(wù)的代理對像。因此,要首先嘗試使用這些函數(shù)來導(dǎo)入由php服務(wù)提供的web服務(wù)描述語言(web services description language,wsdl)文件。 還可以使用.net sdk的wsdl.exe命令行公用程序。不幸的是,在使用vs.net向?qū)?dǎo)入wsdl之后,并不能成功地創(chuàng)建一個代理。所以我必須把導(dǎo)入原始的wsdl文件后由vs.net生成的文件轉(zhuǎn)換為wsdl:
◆把模式域名空間從http://www.w3.org/1999/xmlschema改成http://www.w3.org/2001/xmlschema 然后清除所有的當(dāng)wsdl導(dǎo)入過程中由vs.net添加的”q”域名空間。
◆刪除 xmlns:tm=http://microsoft.com/wsdl/mime/textmatching/和xmlns: mime="http://schemas.xmlsoap.org/wsdl/mime/" 名字空間,因為這個應(yīng)用程序中不需要包含這些。
◆刪除類型元素,因為原始的 wsdl文檔 并沒有包含web服務(wù)的模式信息的指定的元素區(qū)段。
◆改變輸入輸出元素消息屬性值為包含tns域名空間前綴的形式:
| 以下為引用的內(nèi)容: <porttype name="nntpsoapporttype"> <input message="tns:getheaders" /> <o(jì)utput message="tns:getheadersresponse" /> </operation> <o(jì)peration name="getarticle" parameterorder="newsgroup article"> <input message="tns:getarticle" /> <o(jì)utput message="tns:getarticleresponse" /> </operation> </porttype> |
在進行了下面的這些微小的改變,vs.net向?qū)軌蜃x取wsdl并且自動地生成一個代理。在編譯了這個代理之后,它被包含在一個asp.net頁面中。然而,當(dāng)這個asp.net頁面被執(zhí)行:“ message does not have a correct soap root xml tag.”,這個錯誤被當(dāng)作一個soap錯誤從web服務(wù)中返回。
為了精確地評估這個錯誤,代理調(diào)用被一個名為proxy trace的公用程序使用,以便代理生成soap包裝。這可以通過把下列代碼添加進asp.net頁面來實現(xiàn):
msnews.proxy = new system.net.webproxy( http://localhost:8080);
在察看了由.net代理生成的soap包裝之后,我有點奇怪為什么會返回這個錯誤,因為實際上一個相對的soap包裝被生成并被發(fā)送到web服務(wù)。即使在嘗試了好幾個轉(zhuǎn)化成代理代碼之后這個錯誤依然持續(xù)。代碼段列表2顯示了從php web服務(wù)返回的完整的soap錯誤包裝。
在使用vs.net中創(chuàng)建的代理對象的好幾個把asp.net頁面與php web服務(wù)連結(jié)的不成功的嘗試之后,我決定從頭開始創(chuàng)建soap包裝以便執(zhí)行更有效的程序調(diào)試。{起先,它看起來好像由.net代理生成的模式域名空間可能是問題的關(guān)鍵,因為.net使用2001模式規(guī)范而php服務(wù)使用的是1999版本的規(guī)范。
然而,我把自定義的soap包裝改為用1999版本代替2001版本,錯誤依然存在。在嘗試了好幾個其他的小的改變之后,我決定把soap包裝使用的域名空間前綴和正文元素從soap (由.net代理生成)改為soap - env,因為我看見在soap錯誤信息中返回了soap - env前綴。(見代碼2)這表面上看上去微不足道的改變竟解決了問題!當(dāng)處理任何請求的時候,php服務(wù)顯然需要soap - env前綴,而拒絕不包含soap - env前綴的要求。
創(chuàng)建一個自定義代理
既然已經(jīng)了解了為什么web服務(wù)返回一個soap錯誤,我們就可以創(chuàng)建一個自定義代理來生成網(wǎng)服務(wù)期待的soap包裝。雖然創(chuàng)建一個自定義soap包裝肯定比使用一個由vs.net或者wsdl.exe公用程序生成的soap包裝要花更多的時間,但是這樣做可以完全控制包裝的內(nèi)容。為了開始創(chuàng)建自定義代理,我創(chuàng)建一個名為msnewsserviceproxy的包含兩個字段的新類:
| 以下為引用的內(nèi)容: public class msnewsserviceproxy { string _soapaction; } |
uri字段保存了web服務(wù)的位置,而_soapaction字段保存了將要使用soap包裝發(fā)送的soapaction數(shù)據(jù)頭的名稱。在msnewsserviceproxy類之內(nèi),添加createsoapenvelope (),sendsoapenvelope ()和filterresult ()這三個方法。這些方法生成soap包裝請求,把它發(fā)送到web服務(wù),然后過濾返回的soap包裝。讓我們逐一的看看每個方法。注意代碼在soap包裝的根元素上添加一個soap - env域名空間前綴。web服務(wù)顯然需要這個特定的前綴,而拒絕任何不包含這個前綴的信息。因為vs.net生成的代理發(fā)送一個soap域名空間前綴(而不是soap - env),所以它的消息被拒絕。web服務(wù)不應(yīng)該需要一個特定的域名空間前綴而為此拒絕不帶此前綴的消息,但是域名空間問題也是你必須注意要想使工作更好的完成,要執(zhí)行一些看上去不{0>可思議的事情。
在soap包裝被創(chuàng)建之后,sendsoapenvelope ()方法(見代碼段4)使用了幾個system.net和system.io域名空間中的類來把這個包裝發(fā)送到web服務(wù)中。代碼首先通過把_uri變量傳送到對象構(gòu)造器來創(chuàng)建一個httpwebrequest對象。其次,與這個請求相關(guān)聯(lián)的相應(yīng)的method,contenttype和header都將被發(fā)送。
然后一個streamwriter對象和httpwebrequest對象的請求流相關(guān)聯(lián),soap包裝就被使用streamwriter的write ()方法寫到流中。
從web服務(wù)返回的soap包裝被httpwebresponse對象的sendsoapenvelope ()方法獲得。
httpwebresponse response = (httpwebresponse)request.getresponse();
如果應(yīng)答不是空值,它將被載入一個xmltextreader,xmltextreader被用來填充xmldocument對象。然后從這個方法中返回xmldocument對象。
filtersoapenvelope ()方法分析soap應(yīng)答包裝并把從web服務(wù)中返回的數(shù)據(jù)裝入自定義代理的“消費者”使用的xmldocument對象:
| 以下為引用的內(nèi)容: private xmldocument xmldocument doc) { xmldocument filterdoc =new xmldocument(); xmlnode result = doc.selectsinglenode("http://results"); xmlnode resultimport = filterdoc.importnode(result,true); filterdoc.appendchild(resultimport); return filterdoc; } |
雖然過濾器可以使用好幾種方法執(zhí)行,但是filtersoapenvelope ()方法依靠xpath語句可以在應(yīng)答soap包裝中得到結(jié)果元素。
微軟新聞組php web服務(wù)展示了允許取得新聞組新聞?wù)膬煞N方法:getheaders ()和getmessage ()。 你可以看到如何在自定義代理類中使用這兩種方法(見代碼段5)。 注意每個方法中的代碼傳遞web服務(wù)方法名被調(diào)用到createsoapenvelope ()方法和任何使用這個方法關(guān)聯(lián)的參數(shù)。 在soap包裝被發(fā)送以及應(yīng)答被接受之后,filtersoapenvelope ()方法被調(diào)用來把返回的數(shù)據(jù)加載到一個xmldocument對象中,同樣,這個對象也是代理“消費者”使用的。
,歡迎訪問網(wǎng)頁設(shè)計愛好者web開發(fā)。新聞熱點
疑難解答
圖片精選