在上篇随笔中对于客户实例传递的xml实现中,手动定义了xml的数据格式,如果现在对产品实例进行传递,那么还要手动对产品实例进行xml进行数据格式化。现在有一套为数据传递定义的协议,那就是soap。其实html也是一种数据存储格式,但html更注重的是表现数据。
(一)Soap是什么?
Simple Object Access Protocol 简单对象访问协议。是一种轻量的,简单的,基于xml的协议。
在W3c中对它是这样描述的:
它是一种通信协议,用于应用程序之间的能信,它是一种用于发送消息的格式,被设计用来通过互联网进行通信,它基于xml,独立于平台,语言,它简单且可以扩展,它可以允许绕过防火墙。
可以所它认为是一种协议,同时它也是一种消息发送的格式。
(二)soap版本
Soap现在有两个版本,1.1和1.2版本。1.1版本是2000年5月发布的文档中描述的,它其中包含了大量互操作性问题及歧义,导致解释时出现偏差。21.2提供了一个更严密、更可靠的规范集合,它基于对协议和xml序列化进行绑定的一个抽象模型。(可以找相关协议规范阅读)
(三)soap组成
现在看一个soap包(soap是一种协议,也是一种用于发送消息的格式,所以可以叫它soap包)。现在通过WS来看看这个soap包是什么样子。
建立Web服务,发布的方法就一个方法:
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
在客户调用端:
首先生成代理,直接从web服务地址查找服务生成代理,然后调用:
using ws = FirstInstance;
[TestFixture]
public class SoapTest
{
[Test]
public void TestSimpleSoap()
{
ws.SelfService client = new ws.SelfService();
Console.WriteLine(client.HelloWorld());
}
}
测试的打印是正确的,现在进行抓包分析,对Http下的数据包截取有很多现成的工具,也可以自己写。
这是客户端请求时的包(http头省略):
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<HelloWorld xmlns="http://tempuri.org/"
xmlns:a="http://schemas.datacontract.org/2004/07/
UnicodeTest.FirstInstance"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"/>
</s:Body>
</s:Envelope>
这是服务端响应的包:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<HelloWorldResponse xmlns="http://tempuri.org/">
<HelloWorldResult>Hello World</HelloWorldResult>
</HelloWorldResponse>
</soap:Body>
</soap:Envelope>
这就是soap包。Soap包由封套Envelope组成,也叫信封,信封由一个soap头和包体组成,其中包体是必须的。
现在对客户类实例进行传输。
[WebMethod]
public Customer GetCustomer()
{
Customer customer = new Customer
{
Unid = 13,
CustomerName = "Songjiang",
CreateTime = DateTime.Now,
Telephone = new Call {
Mobile = "1111111",
FirmCall = "2222",
HomeCall = "3333" }
};
return customer;
}
客户端:
public void TestCustomerSoap()
{
ws.Customer customer = new ws.Customer();
ws.SelfService client = new ws.SelfService();
customer = client.GetCustomer();
Console.WriteLine(customer.CustomerName);
}
从WS返回的soap包是:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetCustomerResponse xmlns="http://tempuri.org/">
<GetCustomerResult>
<Unid>13</Unid>
<CustomerName>Songjiang</CustomerName>
<CreateTime>2010-03-31T11:40:52.3125+08:00</CreateTime>
<Telephone>
<HomeCall>3333</HomeCall>
<Mobile>1111111</Mobile>
<FirmCall>2222</FirmCall>
</Telephone>
</GetCustomerResult>
</GetCustomerResponse>
</soap:Body>
</soap:Envelope>
从中可以看到:
<GetCustomerResponse xmlns="http://tempuri.org/">
<GetCustomerResult>
<Unid>13</Unid>
<CustomerName>Songjiang</CustomerName>
<CreateTime>2010-03-31T11:40:52.3125+08:00</CreateTime>
<Telephone>
<HomeCall>3333</HomeCall>
<Mobile>1111111</Mobile>
<FirmCall>2222</FirmCall>
</Telephone>
</GetCustomerResult>
</GetCustomerResponse>
这部分与上篇中的对客户类实例的xml数据格式化是很相近的。只是在整个过程中,自己没有进行显示的xml格式化。
而由ws进行显示的xml序列化。
现在看看通过XmlSerializer序列化器进行对客户类的手动序列化
public void TestSerialize()
{
Customer customer = new Customer
{
Unid = 13,
CustomerName = "Songjiang",
CreateTime = DateTime.Now,
Telephone = new Call {
Mobile = "1111111",
FirmCall = "2222",
HomeCall = "3333" }
};
FileStream fs = new FileStream("xmltest.xml", FileMode.Create);
XmlSerializer formatter = new XmlSerializer(typeof(Customer));
formatter.Serialize(fs, customer);
fs.Close();
}
文档内容:
<?xml version="1.0"?>
<Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Unid>13</Unid>
<CustomerName>Songjiang</CustomerName>
<CreateTime>2010-03-31T11:55:32.375+08:00</CreateTime>
<Telephone>
<HomeCall>3333</HomeCall>
<Mobile>1111111</Mobile>
<FirmCall>2222</FirmCall>
</Telephone>
</Customer>
更多XmlSerializer的内容请见:
http://www.cnblogs.com/jams742003/archive/2010/03/03/1677288.html
这个文档的内容与上篇中的内容相近。然后再来看看soap序列化器 SoapFormatter
public void TestSoapSerialize()
{
Customer customer = new Customer
{
Unid = 13,
CustomerName = "Songjiang",
CreateTime = DateTime.Now,
Telephone = new Call {
Mobile = "1111111",
FirmCall = "2222",
HomeCall = "3333" }
};
FileStream fs = new FileStream("xmlSoap.xml", FileMode.Create);
SoapFormatter formatter = new SoapFormatter();
formatter.Serialize(fs, customer);
fs.Close();
}
内容为:
<SOAP-ENV:Envelope>
<SOAP-ENV:Body>
<a1:Customer id="ref-1">
<_x003C_Unid_x003E_k__BackingField>
13
</_x003C_Unid_x003E_k__BackingField>
<_x003C_CustomerName_x003E_k__BackingField id="ref-3">
Songjiang
</_x003C_CustomerName_x003E_k__BackingField>
<_x003C_CreateTime_x003E_k__BackingField>
2010-03-31T12:01:08.8750000+08:00
</_x003C_CreateTime_x003E_k__BackingField>
<_x003C_Telephone_x003E_k__BackingField href="#ref-4"/>
</a1:Customer>
<a1:Call>
<_x003C_HomeCall_x003E_k__BackingField id="ref-5">
3333
</_x003C_HomeCall_x003E_k__BackingField>
<_x003C_Mobile_x003E_k__BackingField id="ref-6">
1111111
</_x003C_Mobile_x003E_k__BackingField>
<_x003C_FirmCall_x003E_k__BackingField id="ref-7">
2222
</_x003C_FirmCall_x003E_k__BackingField>
</a1:Call>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
是一个完整的封套(为了排版好看我删除了一些名字空间样的字串,其实这样也不好看)。