一直以来,我都为动态调用WebService方法而烦恼。在.Net环境下,最常用的方法就是采用代理类来调用WebService,可以通过改 变代理类的Url属性来实现动态调用,但当xmlns改变时就会出错,似乎要重新绑定Webservice并重新编译后才能再次运行。我还试过网上的一种 动态编译并动态调用WebService的方式,这种方法效率低,而且需要有较高的权限,否则编译失败。我曾在Sql Server 2005的CLR存储过程中用此方法调用WebService时,浪费了大半天时间,无论怎么试它就是不能成功编译。于是我便不断思考其他的方法,今天晚 上终于写了一个类用于动态调用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);
}
}
转载:http://blog.csdn.net/hz932/archive/2008/03/20/2198601.aspx