前言
web service也叫xml web service webservice是一種可以接收從internet或者intranet上的其它系統中傳遞過來的請求,輕量級的獨立的通訊技術。是:通過soap在web上提供的軟件服務,使用wsdl文件進行說明,并通過uddi進行注冊。
xml:(extensible markup language)擴展型可標記語言。面向短期的臨時數據處理、面向萬維網絡,是soap的基礎。
soap:(simple object access protocol)簡單對象存取協議。是xml web service 的通信協議。當用戶通過uddi找到你的wsdl描述文檔后,他通過可以soap調用你建立的web服務中的一個或多個操作。soap是xml文檔形式的調用方法的規范,它可以支持不同的底層接口,像http(s)或者smtp。
wsdl:(web services description language) wsdl 文件是一個 xml 文檔,用于說明一組 soap 消息以及如何交換這些消息。大多數情況下由軟件自動生成和使用。
uddi (universal description, discovery, and integration) 是一個主要針對web服務供應商和使用者的新項目。在用戶能夠調用web服務之前,必須確定這個服務內包含哪些商務方法,找到被調用的接口定義,還要在服務端來編制軟件,uddi是一種根據描述文檔來引導系統查找相應服務的機制。uddi利用soap消息機制(標準的xml/http)來發布,編輯,瀏覽以及查找注冊信息。它采用xml格式來封裝各種不同類型的數據,并且發送到注冊中心或者由注冊中心來返回需要的數據。
c#調用webservice接口
我們在日常開發中,經常遇到c#調用webservice的情況,通常來說如果webservice是用vs+c#來開發的,問題一般來說不大,直接web引用,然后調用就ok了。
流程如下:
下面就是進行調用,就這么簡單。
但如果webservice是用java或者其它語言或者其它工具生成的話,使用vs+c#來調用就經常遇到問題;就是使用上面的方法顯得很不好使,經常是使用soap ui調用沒有問題,但使用上面的方法卻調用報錯,經常是500的錯誤。當你聯系webservice提供商時通常會說soap ui都能調用得到,你們用代碼為啥子調用不到,問題出在你們的調用方法上。
在我們向其它公司提供webservice的時候,經常也會出現這樣的問題,以前我們一直都以為soap ui能夠調用,那么代碼也就一定能夠調用得通,但經過實踐,我們自己寫demo調用自己的webservice時才發現,并不是別人的調用代碼寫的有問題,因為我們自己也無法將自己寫的webservice調用得通,或者說沒有找到正確的方法調用得通。
這時我們就要思考是否是soap ui能夠調用得通的webservice就代碼一定調用沒有問題呢?或者說soap ui調用webservice和代碼調用webservice的原理區別到底在哪里呢?
總結一下:
(1)soap ui能夠調用成功,代碼不一定能夠調用成功,代碼調用成功并且得到返回結果的前提是webservice可以按標準返回結果,但soap ui是只要按信封返回就可以收到結果而不管結果是否標準;
(2)如果webservice的header有用戶名和密碼的校驗,使用soap ui可以調用成功并且得到返回結果,但使用上面web引用的方式卻不行。對于這種情況,有以下方法可以調用成功:
重復上面web引用的方式,另外引用microsoft.web.services3(這個dll可以在這里下載)。
手工修改reference.cs
以下是調用方法,重點在傳入用戶名和密碼,修改繼承類的重點也在于此;
引用完成,調用就會成功了,結果如下:
從上面可以看出web引用真的是簡單粗暴,基本不用寫幾句代碼就可以搞定絕大部分的webservice調用。
但是web引用卻有在現實開發中常遇到的缺點:
(1)需要開發環境可以訪問到的wsdl地址;
(2)如果webservice有變化需要更新web引用;
那有沒有其它方法呢?答案是有的。一種是直接封裝信封,使用webrequest,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
private void button2_click( object sender, eventargs e) { stringbuilder soap = new stringbuilder(); soap.append( "<soap:envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:zls=\"www.zlsoft.cn\">" ); soap.append( "<soap:header>" ); soap.append( "<wsse:security soap:mustunderstand=\"true\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">" ); soap.append( "<wsse:usernametoken wsu:id=\"usernametoken-4\">" ); soap.append( "<wsse:username>hjq</wsse:username>" ); //用戶名 soap.append( "<wsse:password type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#passwordtext\">123</wsse:password>" );//口令 soap.append( "<wsse:nonce encodingtype=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#base64binary\">gc6ddgkjxo0iarc5kpqu3w==</wsse:nonce>" ); soap.append( "<wsu:created>2017-11-01t05:11:22.805z</wsu:created>" ); soap.append( "</wsse:usernametoken>" ); soap.append( "</wsse:security>" ); soap.append( "</soap:header>" ); soap.append( "<soap:body>" ); soap.append( "<zls:getuserinfo>" ); soap.append( "<zls:appsys_id>trwetre</zls:appsys_id>" ); soap.append( "<zls:appsys_token>sdafdsf</zls:appsys_token>" ); soap.append( "<zls:sid>fdsafds</zls:sid>" ); soap.append( "</zls:getuserinfo>" ); soap.append( "</soap:body>" ); soap.append( "</soap:envelope>" ); string url = "http://127.0.0.1:6998/services/hipservice?wsdl" ; var result = getsoapresource(url, soap.tostring()); } public static string getsoapresource( string url, string datastr) { try { //request uri uri = new uri(url); webrequest webrequest = webrequest.create(uri); webrequest.contenttype = "application/soap+xml; charset=utf-8" ; webrequest.method = "post" ; using (stream requeststream = webrequest.getrequeststream()) { byte [] parambytes = encoding.utf8.getbytes(datastr.tostring()); requeststream.write(parambytes, 0, parambytes.length); } //response webresponse webresponse = webrequest.getresponse(); using (streamreader mystreamreader = new streamreader(webresponse.getresponsestream(), encoding.utf8)) { string result = "" ; return result = mystreamreader.readtoend(); } } catch (exception ex) { throw ex; } } |
但是上述方式還是存在問題,如果webservice需要校驗header里面的用戶名與密碼時,雖然信封中封裝了用戶名和密碼,但是一樣調用不成功,同樣的信封內容,使用soap ui卻能成功。可見代碼調用和soap ui調用還是有一定區別的。
另外一種方式是使用動態編譯:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
uri uri = new uri(txt_url.text); webrequest webrequest = webrequest.create(uri); webrequest.credentials = new networkcredential( "hjq" , "123" ); system.io.stream requeststream = webrequest.getresponse().getresponsestream(); // get a wsdl file describing a service servicedescription sd = servicedescription.read(requeststream); string sdname = sd.services[0].name; // add in tree view // initialize a service description servimport servicedescriptionimporter servimport = new servicedescriptionimporter(); servimport.addservicedescription(sd, string .empty, string .empty); servimport.protocolname = "soap" ; servimport.codegenerationoptions = codegenerationoptions.generateproperties; codenamespace namespace = new codenamespace(); codecompileunit codecompileunit = new codecompileunit(); codecompileunit.namespaces.add( namespace ); // set warnings servicedescriptionimportwarnings warnings = servimport.import( namespace , codecompileunit); if (warnings == 0) { stringwriter stringwriter = new stringwriter(system.globalization.cultureinfo.currentculture); microsoft.csharp.csharpcodeprovider prov = new microsoft.csharp.csharpcodeprovider(); prov.generatecodefromnamespace( namespace , stringwriter, new codegeneratoroptions()); // compile the assembly with the appropriate references //string[] assemblyreferences = new string[2] { "system.web.services.dll", "system.xml.dll" }; string [] assemblyreferences = new string [3] { "system.dll" , "system.dll" , "system.dll" }; compilerparameters param = new compilerparameters(assemblyreferences); param.generateexecutable = false ; param.generateinmemory = true ; param.treatwarningsaserrors = false ; param.warninglevel = 4; compilerresults results = new compilerresults( new tempfilecollection()); results = prov.compileassemblyfromdom(param, codecompileunit); assembly assembly = results.compiledassembly; type service = assembly.gettype(sdname); methodinfo[] methodinfo = service.getmethods(); foreach (methodinfo t in methodinfo) { if (t.name == "discover" ) break ; if (t.name == cbmethods.text) { //messagebox.show(t.tostring()); //invoke method object obj = activator.createinstance(service); object response = t.invoke(obj, new object [] { "1" , "2" , "3" }); messagebox.show( "result = " + response.tostring()); break ; } } } } catch (exception ex) { messagebox.show(ex.message); } |
從這種方式可以看出,首先是訪問wsdl的地址取回webservice的結構,然后采取動態編譯生成本地程序集的方式去調用webservice,和web引用自動生成reference.cs的原理類似;但是明顯這種方式也存在問題,如果webservice的header中需要校驗用戶名與密碼怎么處理呢?
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:http://www.cnblogs.com/goldenbridge/p/7781482.html