再戰 web service (C# Call JAVA)
2010 6/8 挫折... Orz
最近接到一個需求是要修改 web service 的程式,對方的 web service 看起來像是用JAVA寫的,由於在前公司有小小的接觸過,所以對這個需求真是一點也沒有再怕的啦!但也許就是因為太過自信,命運就會想好好的捉弄你一下,好讓你不要太囂張...
首先我在 Visual Studio 2008(以下簡稱VS2008) 開啟一個C#的專案,然後在方案總管的參考那邊按滑鼠右鍵,要加入"web參考"
阿勒~ 怎麼沒有 "web參考" 可以選...
而且選 "服務參考" 還給我跳出 "Web服務列舉型別元件未安裝,請重新安裝Vistual Studio"
就這樣我重新安裝了兩次 VS2008 兩次都一樣... 然後半天就不見了...
後來Google找到解法如下
全文轉貼來至:在VS.Net2008中不能添加Web引用或Service引用?
2010/2/5
在VS.Net2008中不能添加Web引用或Service引用?
真是他X的怪,一直出現錯誤訊息:
"The ccomponents required to enumerate web references are not installed on this computer. please re-install the Visual Studio"
“Web服務列舉型別元件未安裝,請重新安裝Vistual Studio”
我真搞了半天,重裝兩次Visual Studio 2008,還是有問題,
Goolgle搜一下,還真有解,
運行[Vs.net install path]/devenv.exe /resetskippkgs
如果以上命令無效,很可能是你安裝了Source Analysis Tool for C#. 移除此工具就行了。
> _< … 感動,總算解了!
就這樣,一行指令解決掉這個麻煩的問題...
接下來,"服務參考" 可以用了,所以我就開啟服務參考把WSDL網址加進去,想要開始寫程式。
本以為這樣一切就解決了,但是事情還是沒有這麼簡單,於是又跑進去茫茫的Google大海開始找資料,但是在海裡面游了好幾圈,怎麼弄都覺得怪怪的。
除了不熟以外,這次呼叫的web service 還要用 UsernameToken 驗證,所以整個就是一直盲目的想找解法,直到救世主我同事的出現,才讓我突破瓶頸!
首先~ web service 的加入方法不是直接加進去。
選加入服務參考後出現如下畫面
然後選畫面左下角的"進階"
然後選畫面左下角的"加入 Web 參考"
輸入WSDL的URL
點畫面右邊的 "加入參考" 就完成了~ 微軟是很 Nice 的~
接下來就是處理 UsernameToken 驗證的時候了
首先要先安裝 Web Services Enhancements (WSE) 3.0 for Microsoft .NET
然後參考下面文章(文章很長所以只擷取重點)
擷取至:利用 Web Services Enhancements 進行 WS-Security 驗證及數位簽章
全文備份
建立使用 WS-Security 的用戶端
為了要瞭解在用戶端如何配合 WSE 來利用 WS-Security,我建立了一個 Windows Form 應用程式,它會在我按下一個按鈕時呼叫我的 Web 服務。如同我在前面 Web 服務類別中所做的,我加入了一個對 Microsoft.Web.Services.dll 的參照,並且包含有在伺服器端程式碼中相同的 using 陳述式。
在用戶端的部份,WSE 提供了 Microsoft.Web.Services.WebServicesClientProtocol 類別,它是繼承自 System.Web.Services.Protocols.SoapHttpClientProtocol 類別。當您在 Visual Studio .NET 中選擇「加入 Web 參考」選項,或是利用 WSDL.exe 公用程式依據 WSDL 建立用戶端程式碼時會使用到 SoapHttpClientProtocol。您可以利用 Visual Studio .NET 中的「加入 Web 參考」選項,或是使用 WSDL.exe 公用程式產生用戶端程式碼的 Proxy 類別,然後修改所產生的 Proxy 類別,把繼承的關係從 SoapHttpClientProtocol 改成 WebServicesClientProtocol。現在 Proxy 類別就會有一個 RequestSoapContext 及 ResponseSoapContext 屬性,您可以用來取用您傳送或接收的 WS-Security 的標題。如果您使用的是「加入 Web 參考」選項,您可以在 Web References 目錄下找到所產生 Proxy 類別的程式碼。對於 C# 的專案而言,您可以在名稱為 WSDL 所在主機的主機名稱的目錄下找到一個叫做 Reference.cs 的檔案。對於 MicrosoftR Visual BasicR .NET 專案,這個檔案會叫做 Reference.vb。我將類別的宣告從public class Service1 :
System.Web.Services.Protocols.SoapHttpClientProtocol {
改成public class Service1 :
Microsoft.Web.Services.WebServicesClientProtocol {
如果您使用 Visual Studio .NET「加入 Web 參考」選項,則在修改其放置所產生程式碼的檔案時,要特別小心。如果您選擇「更新 Web 參考」選項,這時 Visual Studio .NET 會重新產生程式碼,並且覆寫您的變更。
為了要產生要求用的 UsernameToken,我的用戶端程式碼看起來會像下面的樣子。localhost.Hello proxy = new localhost.Hello();
proxy.Url = endpointInput.Text;
UsernameToken TextToken
= new UsernameToken(usernameInput.Text,
passwordInput.Text,
PasswordOption.SendHashed);
proxy.RequestSoapContext.Security.Tokens.Add(TextToken);
string result;
try
{
result = proxy.PersonalHello();
}
catch (Exception ex)
{
result = ex.Message;
}
MessageBox.Show(result);
這段程式碼和呼叫一般 Web service 的程式碼之間的差別只在於我建立了 UsernameToken 物件,並將它加入到要求的 Tokens 集合中。UsernameToken 物件的建構函式中需要三個參數:使用者名稱、密碼以及 PasswordOption。在這個例子中我是要傳送雜湊過的密碼。在這段程式中所產生的一個精簡版 SOAP 要求如下所示。您可以注意到要求中有一個 Security 標題,其中有一個 UsernameToken 子元素,包含有使用者名稱、雜湊的密碼和一個可以用來識別這個特定的要求的隨機 Nonce,以及產生的時間。完整的訊息可以參考在本章最後的參考資料一節。<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Header>
...
<wsse:Security
soap:mustUnderstand="1"
xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext">
<wsse:UsernameToken
xmlns:wsu="http://schemas.xmlsoap.org/ws/2002/07/utility"
wsu:Id="SecurityToken-58564463-5bdc-4a6b-a7fb-94a0d7357a20">
<wsse:Username>Joe</wsse:Username>
<wsse:Password Type="wsse:PasswordDigest">
gpBDXjx79eutcXdtlULIlcrSiRs=
</wsse:Password>
<wsse:Nonce>
h52sI9pKV0BVRPUolQC7Cg==
</wsse:Nonce>
<wsu:Created>2002-11-04T19:16:50Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
</soap:Header>
<soap:Body>
<PersonalHello xmlns="http://tempuri.org/" />
</soap:Body>
</soap:Envelope>
這段訊息現在可以傳送給 Web 服務,而 WSE SOAP 延伸會驗證要求的一般格式,檢查密碼雜湊和從密碼提供者取得的密碼是否吻合,如果一切正常的話,就要對我們的 Web 方法進行呼叫。我們的 Web 方法會接收到傳入的要求以及填入的 SoapContext,在 Security 標題中找到 UsernameToken,然後依據指定的名稱建立回應字串。傳回的回應是一般的 WebMethod 回應,而我們的用戶端應用程式會顯示傳回的字串。我們已經成功的執行了第一個 WS-Security 應用程式!
因為我裝的是 WSE3.0 所以要先將 Microsoft.Web.Services3.dll 給加入參考。
然後上面文章提到的public class Service1 :
System.Web.Services.Protocols.SoapHttpClientProtocol {
我改成public class Service1 :
Microsoft.Web.Services3.WebServicesClientProtocol {
存檔以後就OK了~
然後另外值得注意的一點是,傳送帳號密碼的選項。
我是這樣用的,不然對方會跳 "WSDoAllReceiver: security processing failed" 給我UsernameToken TextToken
= new UsernameToken(usernameInput.Text,
passwordInput.Text,
PasswordOption.SendNone);
修改完以後就可以順利抓到對方回傳的訊息囉~
2 回應:
嘿…小小黃真乖!
有說到做到喔~
總算讓我等到新文章發表了
繼續努力!和平、奮鬥、救台灣!!!
^______________________^
您才是真正的高手,
這個問題困擾我三個月,
連 Microsoft MVP 也無解,
見到您無私分享,致上最高的敬意!
張貼留言