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