Webservices-2.C#创建web服务,及引用访问、代码访问
注:web服务简介Webservices-1.web服务定义简介
以下均以C#语言为例
一、创建web服务(简单介绍,主要讨论客户端引用)
打开VS创建网站项目,在网站项目中添加“WEB服务(ASMX)”,
此时VS便已经默认建立好一个web服务。
如需使用Session,请添加“[WebMethod(EnableSession=true)] ”,更多信息请实际编写代码时候查看智能提示,及msdn文档
此时可以将服务部署于web服务器上,以IIS为例,部署完毕即可正确访问。有时创建IIS网站时,请注意配置使用的.net版本库。
访问地址:http://172.168.0.40:8086/WebSer.asmx(个人PC示例,请勿随意copy)
二、服务解析概述
在访问地址后添加?WSDL既可以查看服务说明文档:http://172.168.0.40:8086/WebSer.asmx?WSDL
1 <?xml version="1.0" encoding="utf-8"?> 2 <wsdl:definitions xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:tns="ChineShine" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" targetNamespace="ChineShine" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> 3 <wsdl:types> 4 <s:schema elementFormDefault="qualified" targetNamespace="ChineShine"> 5 <s:element name="HelloWorld"> 6 <s:complexType> 7 <s:sequence> 8 <s:element minOccurs="0" maxOccurs="1" name="ss" type="s:string" /> 9 </s:sequence> 10 </s:complexType> 11 </s:element> 12 <s:element name="HelloWorldResponse"> 13 <s:complexType> 14 <s:sequence> 15 <s:element minOccurs="0" maxOccurs="1" name="HelloWorldResult" type="s:string" /> 16 </s:sequence> 17 </s:complexType> 18 </s:element> 19 <s:element name="NoReturnValue"> 20 <s:complexType> 21 <s:sequence> 22 <s:element minOccurs="0" maxOccurs="1" name="ss" type="s:string" /> 23 </s:sequence> 24 </s:complexType> 25 </s:element> 26 <s:element name="NoReturnValueResponse"> 27 <s:complexType /> 28 </s:element> 29 <s:element name="NoParaValue"> 30 <s:complexType /> 31 </s:element> 32 <s:element name="NoParaValueResponse"> 33 <s:complexType> 34 <s:sequence> 35 <s:element minOccurs="0" maxOccurs="1" name="NoParaValueResult" type="s:string" /> 36 </s:sequence> 37 </s:complexType> 38 </s:element> 39 </s:schema> 40 </wsdl:types> 41 <wsdl:message name="HelloWorldSoapIn"> 42 <wsdl:part name="parameters" element="tns:HelloWorld" /> 43 </wsdl:message> 44 <wsdl:message name="HelloWorldSoapOut"> 45 <wsdl:part name="parameters" element="tns:HelloWorldResponse" /> 46 </wsdl:message> 47 <wsdl:message name="NoReturnValueSoapIn"> 48 <wsdl:part name="parameters" element="tns:NoReturnValue" /> 49 </wsdl:message> 50 <wsdl:message name="NoReturnValueSoapOut"> 51 <wsdl:part name="parameters" element="tns:NoReturnValueResponse" /> 52 </wsdl:message> 53 <wsdl:message name="NoParaValueSoapIn"> 54 <wsdl:part name="parameters" element="tns:NoParaValue" /> 55 </wsdl:message> 56 <wsdl:message name="NoParaValueSoapOut"> 57 <wsdl:part name="parameters" element="tns:NoParaValueResponse" /> 58 </wsdl:message> 59 <wsdl:portType name="WebSerSoap"> 60 <wsdl:operation name="HelloWorld"> 61 <wsdl:input message="tns:HelloWorldSoapIn" /> 62 <wsdl:output message="tns:HelloWorldSoapOut" /> 63 </wsdl:operation> 64 <wsdl:operation name="NoReturnValue"> 65 <wsdl:input message="tns:NoReturnValueSoapIn" /> 66 <wsdl:output message="tns:NoReturnValueSoapOut" /> 67 </wsdl:operation> 68 <wsdl:operation name="NoParaValue"> 69 <wsdl:input message="tns:NoParaValueSoapIn" /> 70 <wsdl:output message="tns:NoParaValueSoapOut" /> 71 </wsdl:operation> 72 </wsdl:portType> 73 <wsdl:binding name="WebSerSoap" type="tns:WebSerSoap"> 74 <soap:binding transport="http://schemas.xmlsoap.org/soap/http" /> 75 <wsdl:operation name="HelloWorld"> 76 <soap:operation soapAction="ChineShine/HelloWorld" style="document" /> 77 <wsdl:input> 78 <soap:body use="literal" /> 79 </wsdl:input> 80 <wsdl:output> 81 <soap:body use="literal" /> 82 </wsdl:output> 83 </wsdl:operation> 84 <wsdl:operation name="NoReturnValue"> 85 <soap:operation soapAction="ChineShine/NoReturnValue" style="document" /> 86 <wsdl:input> 87 <soap:body use="literal" /> 88 </wsdl:input> 89 <wsdl:output> 90 <soap:body use="literal" /> 91 </wsdl:output> 92 </wsdl:operation> 93 <wsdl:operation name="NoParaValue"> 94 <soap:operation soapAction="ChineShine/NoParaValue" style="document" /> 95 <wsdl:input> 96 <soap:body use="literal" /> 97 </wsdl:input> 98 <wsdl:output> 99 <soap:body use="literal" /> 100 </wsdl:output> 101 </wsdl:operation> 102 </wsdl:binding> 103 <wsdl:binding name="WebSerSoap12" type="tns:WebSerSoap"> 104 <soap12:binding transport="http://schemas.xmlsoap.org/soap/http" /> 105 <wsdl:operation name="HelloWorld"> 106 <soap12:operation soapAction="ChineShine/HelloWorld" style="document" /> 107 <wsdl:input> 108 <soap12:body use="literal" /> 109 </wsdl:input> 110 <wsdl:output> 111 <soap12:body use="literal" /> 112 </wsdl:output> 113 </wsdl:operation> 114 <wsdl:operation name="NoReturnValue"> 115 <soap12:operation soapAction="ChineShine/NoReturnValue" style="document" /> 116 <wsdl:input> 117 <soap12:body use="literal" /> 118 </wsdl:input> 119 <wsdl:output> 120 <soap12:body use="literal" /> 121 </wsdl:output> 122 </wsdl:operation> 123 <wsdl:operation name="NoParaValue"> 124 <soap12:operation soapAction="ChineShine/NoParaValue" style="document" /> 125 <wsdl:input> 126 <soap12:body use="literal" /> 127 </wsdl:input> 128 <wsdl:output> 129 <soap12:body use="literal" /> 130 </wsdl:output> 131 </wsdl:operation> 132 </wsdl:binding> 133 <wsdl:service name="WebSer"> 134 <wsdl:port name="WebSerSoap" binding="tns:WebSerSoap"> 135 <soap:address location="http://172.168.0.40:8086/WebSer.asmx" /> 136 </wsdl:port> 137 <wsdl:port name="WebSerSoap12" binding="tns:WebSerSoap12"> 138 <soap12:address location="http://172.168.0.40:8086/WebSer.asmx" /> 139 </wsdl:port> 140 </wsdl:service> 141 </wsdl:definitions>
折叠后查看
注意:WSDL元素[1]基于XML语法描述了与服务进行交互的基本元素:
Type(消息类型):数据类型定义的容器,它使用某种类型系统(如XSD)。
Message(消息):通信数据的抽象类型化定义,它由一个或者多个part组成。
Part:消息参数
Operation(操作):对服务所支持的操作进行抽象描述,WSDL定义了四种操作: 1.单向(one-way):端点接受信息;2.请求-响应(request-response):端点接受消息,然后发送相关消息;3.要求-响应(solicit-response):端点发送消息,然后接受相关消息;4.通知(notification[2]):端点发送消息。
Port Type (端口类型):特定端口类型的具体协议和数据格式规范。
Binding:特定端口类型的具体协议和数据格式规范
Port:定义为绑定和网络地址组合的单个端点。
Service:相关端口的集合,包括其关联的接口、操作、消息等。
2.1 targerNamespasce
主要声明的是:本服务使用的命名空间 ,默认是:http://tempuri.org/ (打开一看,跑到bing去了,呵呵),可以自定义使用,如本文定义了:ChineShine
2.2 wsdl:types
主要是:服务接口里面的:方法名称,参数,返回值介绍
2.3 wsdl:Message、wsdl:portType (参看以上注意)
2.4 wsdl:Binding
可以使用的协议访问,如示例中提示使用的soap(即soap1.1),soap12(即soap1.2)
2.5 wsdl:service
主要是:各种方式服务的接口地址
综述:其实在调用别人web服务的时候,只要有web服务地址,即可能够使用,对方的服务,要详细正确使用还需服务开发者,提供详细调用文档。
三、客户端服务引用(这里才是重点啊)
客户端引用主要包含:项目中引用服务地址,普通引用(主要指VS中的“添加服务引用”)
名称 | 使用场景 | 优缺点 | |
普通引用 | 项目建立初期 | 初期建立,方便快捷,易于使用 | |
使用代理类 | 完善的项目,使用中的项目,
需求变更的项目,当然初期的也可以 |
需要自己手工编写代码,
对于成熟使用的项目扩展性好 |
|
代码引用 | post |
完善的项目,使用中的项目, 需求变更的项目,当然初期的也可以 |
需要自己手工编写代码, 对于成熟使用的项目扩展性好 |
get | |||
soap1.1 | |||
soap1.2 |
3.1 普通引用
在需要引用的VS项目中,引用→添加服务引用→添加服务地址“http://172.168.0.40:8086/WebSer.asmx”,
编写基本代码即可使用
TestServiceReference.WebSerSoapClient wc = new TestServiceReference.WebSerSoapClient();//初始化web服务客户端对象
string ss=wc.HelloWorld("你好");//调用web服务的,接口方法
说明:这种方法适用于VS操作,其他语言及IDE未测试。优点方便快捷,简单易于使用。
3.2 代码引用
这里以soap1.1 为例,post,get比较简单,soap1.2 与soap1.1类似,讲述soap1.1后会添加全部代码
打开其中一个接口,参看
注:前提条件,根据接口的wsdl,以及开发商提供的文档可以查看到:接口的地址(URL)、方法名(Method)、参数列表(Paras)、命名空间等信息(tns)
编写请求代码:
//创建一个HttpWebRequest
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL);
request.Method = "POST";//请求方式
request.ContentType = "text/xml; charset=utf-8";//网络文件的类型和网页的编码
request.Headers.Add("SOAPAction", "\"" + XmlNs + (XmlNs.EndsWith("/") ? "" : "/") + MethodName + "\"");//构建soap1.1 请求头文件
request.Credentials = CredentialCache.DefaultCredentials;//获取系统凭据
request.Timeout = 10000;//请求超时时间
byte[] data = EncodeParsToSoap(Pars, XmlNs, MethodName, soapVersion);//组织发送内容,并序列化成字节流,详细参看附注代码,
request.ContentLength = data.Length;//请求数据长度
using (Stream writer = request.GetRequestStream())//请求参数
{
writer.Write(data, 0, data.Length);
writer.Close();
}
XmlDocument doc = new XmlDocument(), doc2 = new XmlDocument();
doc = ReadXmlResponse(request.GetResponse());//接收返回消息 request.GetResponse() 附注代码已修改成使用异步编程方式
这是一次请求,就完成了。详细处理,请参看详细代码
附注:详细代码(复制到程序中,直接就可以使用哦!)
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.IO; 5 using System.Linq; 6 using System.Net; 7 using System.Text; 8 using System.Web; 9 using System.Xml; 10 using System.Xml.Serialization; 11 12 namespace TestWS 13 { 14 public class WebServicesCodeTool 15 { 16 private System.Collections.Hashtable _xmlNamespaces = new System.Collections.Hashtable();//缓存xmlNamespace,避免重复调用GetNamespace 17 18 /// <summary> 19 /// 需要WebService支持Post调用 20 /// </summary> 21 public System.Xml.XmlDocument QueryPostWebService(String URL, String MethodName, System.Collections.Hashtable Pars) 22 { 23 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL + "/" + MethodName); 24 request.Method = "POST"; 25 request.ContentType = "application/x-www-form-urlencoded"; 26 SetWebRequest(request); 27 byte[] data = EncodePars(Pars); 28 WriteRequestData(request, data); 29 return ReadXmlResponse(request.GetResponse());//这里没有修改成异步方式,建议自行修改 30 } 31 32 /// <summary> 33 /// 需要WebService支持Get调用 34 /// </summary> 35 public XmlDocument QueryGetWebService(String URL, String MethodName, Hashtable Pars) 36 { 37 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL + "/" + MethodName + "?" + ParsToString(Pars)); 38 request.Method = "GET"; 39 request.ContentType = "application/x-www-form-urlencoded"; 40 SetWebRequest(request); 41 return ReadXmlResponse(request.GetResponse()); 42 } 43 /// <summary> 44 /// 通用WebService调用(Soap),参数Pars为String类型的参数名、参数值、soap版本(如果支持1.2,使用1.2,默认填写1.1) 45 /// </summary> 46 /// <param name="URL"></param> 47 /// <param name="MethodName"></param> 48 /// <param name="Pars"></param> 49 /// <param name="soapVersion"></param> 50 /// <returns></returns> 51 public XmlDocument QuerySoapWebService(String URL, String MethodName, Hashtable Pars, string soapVersion) 52 { 53 if (_xmlNamespaces.ContainsKey(URL)) 54 { 55 return QuerySoapWebService(URL, MethodName, Pars, _xmlNamespaces[URL].ToString(), soapVersion); 56 } 57 else 58 { 59 return QuerySoapWebService(URL, MethodName, Pars, GetNamespace(URL), soapVersion); 60 } 61 } 62 XmlDocument doc = null; 63 private XmlDocument QuerySoapWebService(String URL, String MethodName, Hashtable Pars, string XmlNs, string soapVersion) 64 { 65 _xmlNamespaces[URL] = XmlNs;//加入缓存,提高效率 66 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL); 67 request.Method = "POST"; 68 69 if (soapVersion == "1.2") 70 { 71 request.ContentType = "application/soap+xml;charset=utf-8"; 72 } 73 else 74 { 75 request.ContentType = "text/xml; charset=utf-8"; 76 request.Headers.Add("SOAPAction", "\"" + XmlNs + (XmlNs.EndsWith("/") ? "" : "/") + MethodName + "\""); 77 } 78 SetWebRequest(request); 79 byte[] data = EncodeParsToSoap(Pars, XmlNs, MethodName, soapVersion); 80 WriteRequestData(request, data); 81 82 XmlDocument doc2 = new XmlDocument(); 83 IAsyncResult ar = request.BeginGetResponse(AsyncCallbackGetResponse, request);//异步方式 84 //XmlDocument doc = new XmlDocument(); 85 //doc = ReadXmlResponse(request.GetResponse());//原来同步方式 86 if (ar.IsCompleted && doc != null) 87 { 88 XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable); 89 String RetXml = ""; 90 if (soapVersion == "1.2") 91 { 92 mgr.AddNamespace("soap12", "http://www.w3.org/2003/05/soap-envelope"); 93 RetXml = doc.SelectSingleNode("//soap12:Body/*/*", mgr).InnerXml; 94 } 95 else 96 { 97 mgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/"); 98 RetXml = doc.SelectSingleNode("//soap:Body/*/*", mgr).InnerXml; 99 } 100 doc2.LoadXml("<root>" + RetXml + "</root>"); 101 AddDelaration(doc2); 102 103 } 104 return doc2; 105 } 106 107 private void AsyncCallbackGetResponse(IAsyncResult ar) 108 { 109 WebRequest request = ar.AsyncState as WebRequest; 110 var response = request.EndGetResponse(ar); 111 Stream stream = response.GetResponseStream(); 112 using (StreamReader reader = new StreamReader(stream)) 113 { 114 string content = reader.ReadToEnd(); 115 if (!string.IsNullOrEmpty(content)) 116 { 117 doc = new XmlDocument(); 118 doc.LoadXml(content); 119 } 120 } 121 } 122 123 /// <summary> 124 /// 第一次执行获取要访问的命名空间 125 /// </summary> 126 /// <param name="URL"></param> 127 /// <returns></returns> 128 private string GetNamespace(String URL) 129 { 130 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL + "?WSDL"); 131 SetWebRequest(request); 132 WebResponse response = request.GetResponse(); 133 XmlDocument doc = null; 134 using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) 135 { 136 doc = new XmlDocument(); 137 doc.LoadXml(sr.ReadToEnd()); 138 sr.Close(); 139 } 140 return doc != null ? doc.SelectSingleNode("//@targetNamespace").Value : "http://tempuri.org/"; 141 } 142 143 private byte[] EncodeParsToSoap(Hashtable Pars, String XmlNs, String MethodName, string soapVersion) 144 { 145 XmlDocument doc = new XmlDocument(); 146 XmlElement soapBody = null; 147 if (soapVersion == "1.2") 148 { 149 doc.LoadXml("<soap12:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap12=\"http://www.w3.org/2003/05/soap-envelope\"></soap12:Envelope>"); 150 AddDelaration(doc); 151 soapBody = doc.CreateElement("soap12", "Body", "http://www.w3.org/2003/05/soap-envelope"); 152 } 153 else 154 { 155 doc.LoadXml("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"></soap:Envelope>"); 156 AddDelaration(doc); 157 soapBody = doc.CreateElement("soap", "Body", "http://schemas.xmlsoap.org/soap/envelope/"); 158 } 159 XmlElement soapMethod = doc.CreateElement(MethodName); 160 soapMethod.SetAttribute("xmlns", XmlNs); 161 foreach (string k in Pars.Keys) 162 { 163 XmlElement soapPar = doc.CreateElement(k); 164 soapPar.InnerXml = ObjectToSoapXml(Pars[k]); 165 soapMethod.AppendChild(soapPar); 166 } 167 soapBody.AppendChild(soapMethod); 168 doc.DocumentElement.AppendChild(soapBody); 169 return Encoding.UTF8.GetBytes(doc.OuterXml); 170 } 171 172 private string ObjectToSoapXml(object o) 173 { 174 XmlSerializer mySerializer = new XmlSerializer(o.GetType()); 175 MemoryStream ms = new MemoryStream(); 176 mySerializer.Serialize(ms, o); 177 XmlDocument doc = new XmlDocument(); 178 doc.LoadXml(Encoding.UTF8.GetString(ms.ToArray())); 179 if (doc.DocumentElement != null) 180 { 181 return doc.DocumentElement.InnerXml; 182 } 183 else 184 { 185 return o.ToString(); 186 } 187 } 188 189 private void SetWebRequest(HttpWebRequest request) 190 { 191 request.Credentials = CredentialCache.DefaultCredentials; 192 request.Timeout = 10000; 193 } 194 195 private void WriteRequestData(HttpWebRequest request, byte[] data) 196 { 197 request.ContentLength = data.Length; 198 using (Stream writer = request.GetRequestStream()) 199 { 200 writer.Write(data, 0, data.Length); 201 writer.Close(); 202 } 203 } 204 205 private byte[] EncodePars(Hashtable Pars) 206 { 207 return Encoding.UTF8.GetBytes(ParsToString(Pars)); 208 } 209 210 private String ParsToString(Hashtable Pars) 211 { 212 StringBuilder sb = new StringBuilder(); 213 foreach (string k in Pars.Keys) 214 { 215 if (sb.Length > 0) 216 { 217 sb.Append("&"); 218 } 219 sb.Append(HttpUtility.UrlEncode(k) + "=" + HttpUtility.UrlEncode(Pars[k].ToString())); 220 } 221 return sb.ToString(); 222 } 223 224 private XmlDocument ReadXmlResponse(WebResponse response) 225 { 226 String retXml = ""; 227 using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) 228 { 229 retXml = sr.ReadToEnd(); 230 sr.Close(); 231 } 232 XmlDocument doc = new XmlDocument(); 233 if (!string.IsNullOrEmpty(retXml)) { doc.LoadXml(retXml); } 234 return doc; 235 } 236 237 private void AddDelaration(XmlDocument doc) 238 { 239 XmlDeclaration decl = doc.CreateXmlDeclaration("1.0", "utf-8", null); 240 doc.InsertBefore(decl, doc.DocumentElement); 241 } 242 243 } 244 }
项目中的调用:
WebServicesTool ws = new WebServicesTool();
Hashtable paras = new Hashtable();
paras.Add("ss", "你好");
XmlDocument docPost = ws.QueryPostWebService("http://172.168.0.40:8086/WebSer.asmx", "HelloWorld", paras);
XmlDocument docSoap = ws.QuerySoapWebService("http://172.168.0.40:8086/WebSer.asmx", "HelloWorld", paras, "1.2");
context.Response.Write(docPost.OuterXml);
context.Response.Write(docSoap.OuterXml);
3.3 使用wsdl代理类
①、查看webservice服务,访问Service Document,即这里的wsdl文件,
②、将查看的wsdl文件保存。
③、本机使用VS自带的“VS2013 开发人员命令提示”。点击打开
④、wsdl 文件路径,即可生成代理类,调用代理类即可访问不同程序编写的webservice服务
四、心得
4.1 使用代码方式,使得成熟稳定的项目,易于扩展。
4.2 不论何种语言,只要读懂wsdl及接口开发商提供文档即可,调用web接口。
4.3 一些关于soap1.2 的简介http://blog.csdn.net/xiaojianpitt/article/details/5258254
更多的soap介绍,可以查看:http://www.ibm.com/developerworks/cn/xml/x-sisoap/