转自http://www.cnblogs.com/splendidme/archive/2011/10/05/2199501.html
一直以来,我们都为动态调用WebService方法而烦恼。在.Net环境下,最常用的方法就是采用代理类来调用WebService,可以通过改变代理类的Url属性来实现动态调用,但当xmlns改变时就会出错,似乎要重新绑定Webservice并重新编译后才能再次运行。我无意中通过百度搜索找了一个采用GET/POST/SOAP方式动态调用WebService的简易灵活方法,只需传入WebService地址、需调用的方法及其参数,就可以随时动态调用了。经过测试调用成功,现分享给大家,代码如下:
using System;
using System.Web;
using System.Xml;
using
System.Collections;
using System.Net;
using System.Text;
using
System.IO;
using System.Xml.Serialization;
//By huangz 2008-3-19
/**//// <summary>
///
利用WebRequest/WebResponse进行WebService调用的类,By 同济黄正 http://hz932.ys168.com
2008-3-19
/// </summary>
public class
WebSvcCaller
{
//<webServices>
//
<protocols>
// <add
name="HttpGet"/>
// <add
name="HttpPost"/>
//
</protocols>
//</webServices>
private static Hashtable _xmlNamespaces = new
Hashtable();//缓存xmlNamespace,避免重复调用GetNamespace
/**//// <summary>
///
需要WebService支持Post调用
///
</summary>
public static XmlDocument
QueryPostWebService(String URL , String MethodName , Hashtable
Pars)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL + "/" +
MethodName);
request.Method =
"POST";
request.ContentType =
"application/x-www-form-urlencoded";
SetWebRequest(request);
byte[]
data = EncodePars(Pars);
WriteRequestData(request , data);
return
ReadXmlResponse(request.GetResponse());
}
/**//// <summary>
///
需要WebService支持Get调用
///
</summary>
public static XmlDocument
QueryGetWebService(String URL , String MethodName , Hashtable
Pars)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL + "/" +
MethodName + "?" +
ParsToString(Pars));
request.Method = "GET";
request.ContentType =
"application/x-www-form-urlencoded";
SetWebRequest(request);
return
ReadXmlResponse(request.GetResponse());
}
/**//// <summary>
///
通用WebService调用(Soap),参数Pars为String类型的参数名、参数值
///
</summary>
public static XmlDocument
QuerySoapWebService(String URL , String MethodName , Hashtable
Pars)
{
if
(_xmlNamespaces.ContainsKey(URL))
{
return
QuerySoapWebService(URL , MethodName , Pars ,
_xmlNamespaces[URL].ToString());
}
else
{
return
QuerySoapWebService(URL , MethodName , Pars
,GetNamespace(URL));
}
}
private static XmlDocument QuerySoapWebService(String URL
, String MethodName , Hashtable Pars , string XmlNs)
{ //By 同济黄正 http://hz932.ys168.com
2008-3-19
_xmlNamespaces[URL] =
XmlNs;//加入缓存,提高效率
HttpWebRequest
request =
(HttpWebRequest)HttpWebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "text/xml;
charset=utf-8";
request.Headers.Add("SOAPAction" , "\"" + XmlNs + (XmlNs.EndsWith("/") ? "" :
"/") + MethodName + "\"");
SetWebRequest(request);
byte[]
data = EncodeParsToSoap(Pars , XmlNs ,
MethodName);
WriteRequestData(request , data);
XmlDocument doc = new XmlDocument() , doc2 = new
XmlDocument();
doc =
ReadXmlResponse(request.GetResponse());
XmlNamespaceManager mgr = new
XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("soap" ,
"http://schemas.xmlsoap.org/soap/envelope/");
String RetXml = doc.SelectSingleNode("//soap:Body/*/*" ,
mgr).InnerXml;
doc2.LoadXml("<root>" + RetXml +
"</root>");
AddDelaration(doc2);
return
doc2;
}
private static string
GetNamespace(String URL)
{
HttpWebRequest request =
(HttpWebRequest)WebRequest.Create(URL +
"?WSDL");
SetWebRequest(request);
WebResponse response =
request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream() ,
Encoding.UTF8);
XmlDocument doc =
new XmlDocument();
doc.LoadXml(sr.ReadToEnd());
sr.Close();
return
doc.SelectSingleNode("//@targetNamespace").Value;
}
private static byte[] EncodeParsToSoap(Hashtable Pars ,
String XmlNs , String MethodName)
{
XmlDocument doc = new
XmlDocument();
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>");
AddDelaration(doc);
XmlElement
soapBody = doc.CreateElement("soap" , "Body" ,
"http://schemas.xmlsoap.org/soap/envelope/");
XmlElement soapMethod =
doc.CreateElement(MethodName);
soapMethod.SetAttribute("xmlns" ,
XmlNs);
foreach (string k in
Pars.Keys)
{
XmlElement soapPar =
doc.CreateElement(k);
soapPar.InnerXml =
ObjectToSoapXml(Pars[k]);
soapMethod.AppendChild(soapPar);
}
soapBody.AppendChild(soapMethod);
doc.DocumentElement.AppendChild(soapBody);
return Encoding.UTF8.GetBytes(doc.OuterXml);
}
private static string ObjectToSoapXml(object
o)
{
XmlSerializer mySerializer = new
XmlSerializer(o.GetType());
MemoryStream ms=new
MemoryStream();
mySerializer.Serialize(ms,o);
XmlDocument doc=new XmlDocument();
doc.LoadXml(Encoding.UTF8.GetString(ms.ToArray()));
if(doc.DocumentElement !=null)
{
return doc.DocumentElement.InnerXml
;
}
else
{
return
o.ToString();
}
}
private static void
SetWebRequest(HttpWebRequest request)
{
request.Credentials =
CredentialCache.DefaultCredentials;
request.Timeout = 10000;
}
private static void WriteRequestData(HttpWebRequest
request , byte[] data)
{
request.ContentLength =
data.Length;
Stream writer =
request.GetRequestStream();
writer.Write(data , 0 ,
data.Length);
writer.Close();
}
private static byte[] EncodePars(Hashtable
Pars)
{
return Encoding.UTF8.GetBytes(ParsToString(Pars));
}
private static String ParsToString(Hashtable
Pars)
{
StringBuilder sb = new
StringBuilder();
foreach (string k
in Pars.Keys)
{
if
(sb.Length >
0)
{
sb.Append("&");
}
sb.Append(HttpUtility.UrlEncode(k) + "=" +
HttpUtility.UrlEncode(Pars[k].ToString()));
}
return
sb.ToString();
}
private static XmlDocument ReadXmlResponse(WebResponse
response)
{
StreamReader sr = new StreamReader(response.GetResponseStream() ,
Encoding.UTF8);
String retXml =
sr.ReadToEnd();
sr.Close();
XmlDocument doc = new
XmlDocument();
doc.LoadXml(retXml);
return
doc;
}
private static void AddDelaration(XmlDocument
doc)
{
XmlDeclaration decl = doc.CreateXmlDeclaration("1.0" , "utf-8" ,
null);
doc.InsertBefore(decl ,
doc.DocumentElement);
}
}
这个类有三个公用的方法:QuerySoapWebService为通用的采用Soap方式调用WebService,QueryGetWebService采用GET方式调用,QueryPostWebService采用POST方式调用,后两个方法需要WebService服务器支持相应的调用方式。三个方法的参数和返回值相同:URL为Webservice的Url地址(以.asmx结尾的);MethodName为要调用的方法名称;Pars为参数表,它的Key为参数名称,Value为要传递的参数的值,Value可为任意对象,前提是这个对象可以被xml序列化。注意方法名称、参数名称、参数个数必须完全匹配才能正确调用。第一次以Soap方式调用时,因为需要查询WSDL获取xmlns,因此需要时间相对长些,第二次调用不用再读WSDL,直接从缓存读取。这三个方法的返回值均为XmlDocument对象,这个返回的对象可以进行各种灵活的操作。最常用的一个SelectSingleNode方法,可以让你一步定位到Xml的任何节点,再读取它的文本或属性。也可以直接调用Save保存到磁盘。采用Soap方式调用时,根结点名称固定为root。
这个类主要是利用了WebRequest/WebResponse来完成各种网络查询操作。为了精简明了,这个类中没有添加错误处理,需要在调用的地方设置异常捕获。
下面是一个调用实例:
protected void Page_Load(object
sender , EventArgs e)
{
try
{
Hashtable pars = new
Hashtable();
String Url =
"http://www.260dns.cn/Services/Weather.asmx";
pars["city"] =
"上海";
pars["wdate"]="2008-3-19";
XmlDocument doc = WebSvcCaller.QuerySoapWebService(Url , "GetWeather" ,
pars);
Response.Write(doc.OuterXml);
}
catch (Exception
ex)
{
Response.Write(ex.Message);
}
}