2012-01-27 128 views
3

我想實現一個SOAP客戶端來處理WSDL文件在此位置描述的Web服務的加利福尼亞工資稅的電子報告:FSET Service。在這個WSDL文件中,有幾個模式的引用,其中包括一個在http://schemas.xmlsoap.org/ws/2004/08/addressing處的引用,它似乎在它甚至到達OnBeforeExecute事件之前停止我的程序。如何爲SOAP客戶端完成XML

爲了讓這個項目脫穎而出,我試圖訪問在WSDL文件中聲明的Ping函數。

我剛剛在Delphi中獲得了SOAP客戶端創建的一些經驗。我正在使用德爾福2010年。這是我做到這一點。我使用WSDL導入器在上述地址導入文件。它爲我創建了一個名爲fsetservice的單元。然後,我添加了一個表單到我的項目中,我添加了一個HTTPRIO組件。我將組件的WSDLLocation設置爲WSDL文件的本地副本,在窗體上放置幾個TMemos以捕獲請求和響應頭並添加代碼來執行此操作。然後,我設置了一個按鈕,並在其OnClick事件,我寫了這個代碼:達到

procedure TForm1.Button1Click(Sender: TObject); 
var sResponse: String; 
begin 
    sResponse := GetFsetServiceSoap.Ping; 
end; 

當我按一下按鈕,我在我的HTTPRIO OnBeforeExecute事件斷點前得到這個消息:

對於 最終接收者

頁眉http://schemas.xmlsoap.org/ws/2004/08/addressing:Action是必需的,但該消息

我知道我們應該只要求每個發帖一個問題,但不存在,有時你不知道夠隨便把一個好問題:

編輯:爲了節省時間給任何其他人提出同樣的問題,我把我在這些問題下找到的答案。

它看起來像HTTPRIO組件可能正在檢查從WSDL文件導入的XML是否完全針對WSDL中引用的模式。這看起來很酷,但它是真的嗎?

*答案:不正確,至少根據頁面底部的註釋http://www.tutorialspoint.com/wsdl/wsdl_definition.htm。根據筆記,模式沒有必要實際存在於該位置,它只需要唯一標識WSDL中使用的模式。*

在自動創建(和未修改)的GetFsetService函數中,我可以一路走到最後,錯誤發生在返回時,似乎沒有可能進入調用錯誤的實際進程。有沒有辦法做到這一點,我失蹤了?

答:我對此仍不確定,但似乎答案是否定的。無論如何,雖然從頭開始編寫這將會更乏味,但這是一個更好的解決方案,而不是等待WSDL嚮導出現奇蹟。

我有沒有想過說我需要實現爲我自動創建的FsetService接口?

答案:顯然不是。

我在Marco Cantu的書Mastering Delphi 2005中看到Borland(WebAppDbg.exe)提供了一個應用程序,允許您查看在特定端口上發送的HTTP。我嘗試過但沒有結果。這會有幫助嗎?如果是這樣,我應該使用什麼端口?

回答:使用Fiddler2工具。很好的發現。

我該如何克服這個錯誤?

回答:手動操作。

+0

爲什麼要將WSDLLocation屬性指向本地文件?嘗試將其設置爲https://fsettestversion.edd.ca.gov/fsetproxy/fsetservice.asmx?WSDL – 2012-01-27 21:17:33

+0

您是否使用內置的SOAP WSDL生成器來生成WSDL?顯示你打Ping的方式以及你的Ping通話設置。 – 2012-01-27 21:18:12

+0

@WarrenP他在他的消息中提到了Delphi 2010 ... – 2012-01-27 21:20:31

回答

4

首先,我將開始在處理肥皂和Web服務時將Fiddler2和SoapUI添加到您的工具庫中。

聽起來像信封頭是不完整的。在我與D2007和一個WCF Web服務的經驗,德爾福將無法正確生成的信封頭,所以只好截取呼叫並添加項目是這樣的:

procedure TMainForm.MyMessageEnvelopeComplete(Sender: TROSOAPMessage); 
begin 
    Sender.EnvelopeNode.AddAttribute('xmlns:a', 'http://www.w3.org/2005/08/addressing', False); 
    Sender.HeaderNode.Add('a:Action').Value := 'http://Testservice.Connect/IConnect/Ping'; 
    Sender.HeaderNode.Add('a:To').Value := 'http://testservice-pc:2021/WSConnect'; 
end; 

編輯:

如果你想要用手建立肥皂信封和郵政命令,我已經使用以下代碼完成了它:

procedure TMainForm.Button5Click(Sender: TObject); 
    procedure HandleError(const errorCode: integer); 
    var 
    errorMessage: AnsiString; 
    begin 
    SetLength(errorMessage, 256); 
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_FROM_HMODULE, 
        Pointer(GetModuleHandle('wininet.dll')), 
        errorCode, 0, PChar(errorMessage), Length(errorMessage), nil); 
    SetLength(errorMessage, StrLen(PChar(errorMessage))); 
    raise Exception.Create(errorMessage); 
    end; 

    function BuildHeader: TStringStream; 
    begin 
    result := TStringStream.Create(''); 
    try 
     result.WriteString('Content-Type: application/soap+xml;charset=UTF-8;action="http://Thermo.Connect/IHCSConnect/Ping"' + sLineBreak); 
    except 
     result.Free; 
     raise; 
    end; 
    end; 

    function BuildBody: TStringStream; 
    begin 
    result := TStringStream.Create(''); 
    with result do 
     try 
     WriteString('<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">' + sLineBreak); 
     WriteString('<s:Header>' + sLineBreak); 
     WriteString('<a:Action>http://Thermo.Connect/IHCSConnect/Ping</a:Action>' + sLineBreak); 
     WriteString('<a:To>http://thermo-pc:2021/WSHCSConnect</a:To>' + sLineBreak); 
     WriteString('</s:Header>' + sLineBreak); 
     WriteString('<s:Body>' + sLineBreak); 
     WriteString('<Ping xmlns="http://Thermo.Connect">' + sLineBreak); 
     WriteString('</Ping>' + sLineBreak); 
     WriteString('</s:Body>' + sLineBreak); 
     WriteString('</s:Envelope>' + sLineBreak); 
     except; 
     result.Free; 
     raise; 
     end; 
    end; 

var 
    InetRoot: HINTERNET; 
    InetConnect: HINTERNET; 
    Request: HINTERNET; 
begin 
    InetRoot := InternetOpen('GabeCode', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); 
    try 
    InetConnect := InternetConnect(InetRoot, 'thermo-pc:2021', 0, '', 
            '', INTERNET_SERVICE_HTTP, 0, Cardinal(Self)); 
    try 
     Request := HttpOpenRequest(InetConnect, 'POST', 'WSHCSConnect', 'HTTP/1.1', nil, nil, 
            INTERNET_FLAG_KEEP_CONNECTION or INTERNET_FLAG_NO_CACHE_WRITE, 
            0); 
     try 
     // build add header items to the post request 
     with BuildHeader do 
     try 
      HttpAddRequestHeaders(Request, PChar(DataString), Length(DataString), HTTP_ADDREQ_FLAG_ADD); 
     finally 
      Free; 
     end; 

     // build the body of data being posted and send the post 
     with BuildBody do 
     try 
      if not HttpSendRequest(Request, nil, 0, PChar(DataString), Length(DataString)) then 
      HandleError(GetLastError); 
     finally 
      Free; 
     end; 

     finally 
     InternetCloseHandle(Request); 
     end; 
    finally 
     InternetCloseHandle(InetConnect); 
    end; 
    finally 
    InternetCloseHandle(InetRoot); 
    end; 
end; 
+0

這看起來很有幫助,但我認爲MyMessageEnvelopeComplete是一個事件。它似乎不是HTTPRIO的事件。在HTTPRIO的一些子組件中,有一些事件我被忽略了。也許HTTPWebNode.OnBeforePost會有所幫助。我已經下載了SOAPUI,並且正在學習Fiddler2。感謝指針。 – jrodenhi 2012-01-28 00:03:09

+0

我的道歉,在上面的例子中,我使用了Rem Objects ... rem對象控件可以根據需要在表單上放置不同的組件。上面的組件是TROSOAPMessage。 – GDF 2012-01-28 08:28:01

+0

不需要道歉。 RemObjects似乎是一個很好的工具集,但我可能需要在沒有它的情況下完成這項工作。我發現了一篇關於手工構建SOAP客戶端的文章。這是一個有趣的前景。希望這不是職業。不利的一面是,我將不得不學習WSDL嚮導和HTTPRIO的許多東西,但有利的是,如果我能在這條道路上取得成功,我可能會了解更多關於許多事情的知識。 – jrodenhi 2012-01-28 19:49:40