访问WebService的方法有3大种:
1. 通过Http的Get或Post方法
2. 通过SOAP
3. 用.net的代理类
第一种只能访问本机的,后二种可以访问任何地方的。
使用最方便,编码量最少,且可配置性也较好的是第三种,所以应尽可能多的使用第三种,其代码就是实例化一个对象,然后调用其方法即可。
有时候(比如在开发阶段不知道要访问哪个服务)需要用前2种方式,因为第一种有只能访问本机的限制,所以不推荐使用,一般应用第二种,即SOAP方式,它也是WebService标准的交互协议,其实就是基于Http协议之上,对输入和输出参数的字符串格式的规定。
SOAP又分为1.1和1.2两种,它们的区别仅限于XML编码和TagName,调用过程没有区别,都是基于HttpPost,拿1.1为例:
1. 首先通过在浏览器里输入http://domain/ServiceName.asmx?op=FunName 查看其输入和输出的样例(里面有1.1和1.2两种)。
2. 用服务地址(如http://domain/ServiceName.asmx )实例化一个HttpWebRequest类,然后设置其方法名(SOAPAction), ContentType等属性
3. 发出调用请求(即把SOAP消息写入到请求流)。
4. 接收响应(是一个XmlDocument对象)。
代码如下:
public static XmlDocument CallWebServiceBySoap(string serviceUrl, string argString)
{
// For example: serviceUrl = "http://localhost:2258/ComplexService.asmx?"
// argString = "op=DoSomething&input=<a>1</a><b>2</b>"
// op is function name
try
{
//return QueryPostWebService(serviceUrl, Encoding.UTF8.GetBytes(argString));
char[] sepKey = "&".ToCharArray();
char[] sepValue = "=".ToCharArray();
string[] pas = argString.Split(sepKey);
StringBuilder sb = new StringBuilder();
string funName = null;
foreach (string pa in pas)
{
string[] ps = pa.Split(sepValue);
if (ps[0] == "op")
{
funName = ps[1];
}
else
{
sb.Append("<" + ps[0] + ">");
sb.Append(ps[1]);
sb.Append("</" + ps[0] + ">");
}
}
string soapFmt =
@"<?xml version=""1.0"" encoding=""utf-8""?>
<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:Body>
<{0} xmlns=""http://tempuri.org/"">
{1}
</{0}>
</soap:Body>
</soap:Envelope>";
string soap = string.Format(soapFmt, funName, sb.ToString());
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(serviceUrl);
req.Headers.Add("SOAPAction", string.Format("\"http://tempuri.org/{0}\"", funName));
req.ContentType = "text/xml;charset=\"utf-8\"";
req.Accept = "text/xml";
req.Method = "POST";
using (Stream stm = req.GetRequestStream())
{
using (StreamWriter stmw = new StreamWriter(stm))
{
stmw.Write(soap);
}
}
WebResponse response = req.GetResponse();
//Stream responseStream = response.GetResponseStream();
XmlDocument doc = ReadXmlResponse(response);
return doc;
}
catch
{
//EntLibLogger.LogCriticalException(
// string.Format("Web Service error: url = {0}, args = {1}"
// , serviceUrl, argString));
throw;
}
}
参数部分需要有一定的构成格式,我封装了一个较通用的单参数(简单类型(如int,string)的参数不必用此,直接拼字符串即可,此处是为复杂类型设计的)示例(可以作为进一步扩展的基础,用于我们未来的的访问Web服务的项目),多参数可以进一步将最后2个参数改进为Dictionary。
private T GetFromWebServiceBySoap<T>(string serviceUrl, string funName, string inputParaName, object input)
{
// Prepare Input
string inputStr = ObjectSerializer.Serialize(input);
XmlDocument docInput = new XmlDocument();
docInput.LoadXml(inputStr);
string inputXml = docInput.DocumentElement.InnerXml;
string argString = string.Format("op={0}&{1}={2}", funName, inputParaName, inputXml);
// Call & Get Result XmlDocument
XmlDocument docResult;
docResult = WebServiceAccess.CallWebServiceBySoap(serviceUrl, argString);
// DeSerialize to Result Object
Type resultType = typeof(T);
string objStr = docResult.DocumentElement.ChildNodes[0].ChildNodes[0].ChildNodes[0].OuterXml;
string tagName = docResult.DocumentElement.ChildNodes[0].ChildNodes[0].ChildNodes[0].Name;
objStr = objStr.Replace("<" + tagName, "<" + resultType.Name);
objStr = objStr.Replace("</" + tagName, "</" + resultType.Name);
docResult.LoadXml(objStr);
docResult.LoadXml(docResult.OuterXml.Replace(docResult.DocumentElement.NamespaceURI, ""));
docResult.DocumentElement.RemoveAllAttributes();
objStr = docResult.OuterXml;
T result
= ObjectSerializer.DeSerializerString2Object<T>(objStr);
// Return Result
return result;
}
工具类:
public static class ObjectSerializer
{
public static string Serialize(object objToXml)
{
if (objToXml == null)
throw new ArgumentNullException("objToXml");
XmlSerializer serializer;
XmlSerializerNamespaces xsn;
StringWriter writer;
serializer = new XmlSerializer(objToXml.GetType());
xsn = new XmlSerializerNamespaces();
xsn.Add(String.Empty, String.Empty);
writer = new StringWriter();
serializer.Serialize(writer, objToXml, xsn);
return writer.GetStringBuilder().ToString();
}
public static T DeSerializerString2Object<T>(string sXml)
{
if (sXml == null)
throw new ArgumentNullException("sXml");
XmlReader reader = XmlReader.Create(new StringReader(sXml));
XmlSerializer serializer = new XmlSerializer(typeof(T));
object obj = serializer.Deserialize(reader);
return (T)obj;
}
}
调用示例:
protected void Button2_Click(object sender, EventArgs e)
{
TestEntities.ComplexInput input = new TestEntities.ComplexInput();
input.a = 1;
input.b = 2;
string serviceUrl = "http://localhost:2258/ComplexService.asmx";
TestEntities.ComplexResult complexResult
= GetFromWebServiceBySoap<TestEntities.ComplexResult>(serviceUrl, "DoSomething", "input", input);
lblMsg.Text = "complexResult.x = " + complexResult.x.ToString();
}
其中输入和输出参数的类定义为:
public class ComplexInput
{
public int a;
public int b;
}
public class ComplexResult
{
public int x;
}
Web服务代码为:
public class ComplexService : System.Web.Services.WebService
{
[WebMethod]
public ComplexResult DoSomething(ComplexInput input)
{
ComplexResult complexResult = new ComplexResult();
complexResult.x = input.a + input.b;
return complexResult;
}
}