Soap包中可以存放数据的地方可以是soap头也可以是soap body部分。其中body部分是必须的,是重要的数据存放位置。Soap头中也可以放一些数据,例如Web服务中的安全中用户检测。例如:
如果添加soap头,那么先要有一个从SoapHeader派生的类:
public class SelfHeader : SoapHeader
{
public string UserName { get; set; }
}
然后在web服务中先定义一个公共成员:
public SelfHeader _soapHeader;
然后在需要添加soap头的方法上添加soap头标签:
[WebMethod]
[SoapHeader("_soapHeader")]
public string HelloWorld()
{
if (_soapHeader.UserName != "zhao")
return "用户禁止访问!";
return "Hello World";
}
在客户端进行访问服务时,须设置header属性:
public void TestSimpleSoap()
{
ws.SelfService client = new ws.SelfService();
ws.SelfHeader _header = new ws.SelfHeader();
_header.UserName = "zzz";
client.SelfHeaderValue = _header;
Console.WriteLine(client.HelloWorld());
}
现在看一下现在的soap包的情况:
请求:
<?xml version="1.0" encoding="utf-8"?>
<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:Header>
<SelfHeader xmlns="http://192.168.1.105/">
<UserName>zzz</UserName>
</SelfHeader>
</soap:Header>
<soap:Body>
<HelloWorld xmlns="http://192.168.1.105/" />
</soap:Body>
</soap:Envelope>
现在添加了header部分。
在.net web服务中为soap添加附件。这里为什么说.net web服务呢?
这里说明一下web服务的概念:web service是基于xml和http的一种服务,它的通信协议主要基于SOAP(这是缩写应该全大写,但大家明白就行),通过WSDL来描述服务,通过UDDI来发布服务。
Web服务不是只有.net才有,.net中提供的web服务相关的定义,发布,发现等,及生成代理,应用。这些只是.net对web服务的一种帮助,或说.net提供了一套web服务的工具,用于创建,发布和应用。
Soap包中可以存放数据的位置可以是头,更重要且必须的是包体部分。那么对于附件,可以以格式化的数据存放于包体部分。
现在以包体部分来存储一个文本文件,目的很明确,那么文本文件内容以怎样的格式存放于包体呢?
第一种:文本文件中的内容以字串格式存在
[WebMethod]
public void SaveText(string strContent,string strFileName)
{
StreamWriter writer=File.CreateText("k:\\"+strFileName+".txt");
writer.WriteLine(strContent);
writer.Close();
}
这个方法将字串保存为utf-8的文本文件
客户端:
[Test]
public void TestSaveText()
{
StreamReader sr = new StreamReader
(@"k:\client.txt",Encoding.Default);
string strTemp = sr.ReadToEnd();
sr.Close();
ws.SelfService client = new ws.SelfService();
client.SaveText(strTemp, "server");
}
从gb2312文本中读取内容,然后存在包体中向服务传递。可以看下现在的包的内容:
<?xml version="1.0" encoding="utf-8"?>
<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>
<SaveText xmlns="http://192.168.1.105/">
<strContent>杩欐槸娴嬭瘯锛乤bc</strContent>
<strFileName>server</strFileName>
</SaveText>
</soap:Body>
</soap:Envelope>
其中乱码部分就是内容(乱码其实并不乱),可以所这部分拷贝到一个utf-8编码下的记事本中,然后另存为gb2312格式,可以看到认识的汉字了。
内容就是:这是测试!abc
第二种,二进制文件例如图片以base64编码存放
其实这个文件可以直接以二进制格式来传递,但如果要保存这个包,那么须对持久化的数据进行双向的格式化,使它的数据格式不会在转化时丢失或增加,在消息1中:
http://www.cnblogs.com/jams742003/archive/2010/03/30/1700605.html
给出了通过base64和支持8位字符编码的28591页的字符集ISO8859-1
(一)以base64来存放二进制图片
服务端:
[WebMethod]
public void SaveImages(string strBase64Content)
{
//ISO串
byte[] bb = Convert.FromBase64String(strBase64Content);//iso字节
Encoding encoding = Encoding.GetEncoding(28591);
string strReturn = encoding.GetString(bb);
FileStream fs = File.Create(@"k:\soapPic.gif");
fs.Write(bb, 0, bb.Length);
fs.Close();
}
客户端:
[Test]
public void TestSaveImage()
{
//1 iso串
Encoding _encoding = Encoding.GetEncoding(28591);
StreamReader sr = new StreamReader(@"k:\x1.gif", _encoding);
string strTemp = sr.ReadToEnd();
sr.Close();
//2 base64串
byte[] bb = _encoding.GetBytes(strTemp);
string strBase64 = Convert.ToBase64String(bb);
ws.SelfService client = new ws.SelfService();
client.SaveImages(strBase64);
}
看一下现在的soap包:
<?xml version="1.0" encoding="utf-8"?>
<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>
<SaveImages xmlns="http://192.168.1.105/">
<strBase64Content>DggAOw==</strBase64Content>
</SaveImages>
</soap:Body>
</soap:Envelope>
其中的粗体部分就是图片的内容,我省略了大部分,只留个小段。
(二)以二进制来传递但不保存文本
在进行base64的转换过程中要有性能损失,多一步就多消耗。因为现在不用对图片进行文本保存,那么这种持久不必要考虑,只要把图片存储下来就可以了。那么现在以二进制传递来存储图片。
服务端:
[WebMethod]
public void SaveBinaryImages(byte[] bb)
{
FileStream fs = File.Create(@"k:\soapPicBinary.gif");
fs.Write(bb, 0, bb.Length);
fs.Close();
}
客户端:
[Test]
public void TestSaveBinaryImage()
{
FileStream fs = new FileStream(@"k:\x1.gif",FileMode.Open);
byte[] bb=new byte[fs.Length];
fs.Read(bb,0,bb.Length);
fs.Close();
ws.SelfService client = new ws.SelfService();
client.SaveBinaryImages(bb);
}
现在的soap包情况:
<?xml version="1.0" encoding="utf-8"?>
<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>
<SaveBinaryImages xmlns="http://192.168.1.105/">
<bb>DggAOw==</bb>
</SaveBinaryImages>
</soap:Body>
</soap:Envelope>
这个包我也省略了一部分。从上面两个包分析,原来,在.net web服务里,对包体中的附件的二进制附件传递是以base64编码来进行的,所以soap中包体中的附件的转换带来的是性能上的损失。
在进行soap消息传递过程中,经常要把各种附件一起发送,而这些附件通过是二进制格式。在soap规范中有对附件的描述,那就是使用MIME类型以URI模式引用MIME部件。对于web服务的工具来说,并不是所有的工具都提供了对soap附件的支持,例如.net web服务。但微软推出了基于DIME的附件解决方案,并通过WSE(web服务增强)来支持web服务的MTOM消息优化传输,当然在WCF中更是支持MTOM。MTOM 是一种机制,用来以原始字节形式传输包含 SOAP 消息的较大二进制附件,从而使所传输的消息较小。
Base64编码以3个字节编码规则为4个字节,多出三分之一的容量,对于base64编码请见:
http://www.cnblogs.com/jams742003/archive/2010/03/26/1696876.html
soap消息包,信念xml格式的soap体消息,以及信封中未定义的但与消息有关的任意数据格式的其它实体。soap消息包通过MIME的Multipart/related媒体类型构建,每个部件都嵌入MIME边界(bundary,在Content-Type报头中定义)。每个MIME部件都有报头信息如:
Content-Type:表示数据的类型
Content Transfer-encoding:表示编码
Content-ID:表示引用内容的标识符
对于MIME消息的根部件要包含soap封套,且Content-type要设置为text/xml
下边是一个带有MIME格式附件的soap包:
Content-Type:text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-ID:<SOAP-ENV:Envelop>
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope>
<soapenv:Header>
</soapenv:Header>
<soapenv:Body>
</soapenv:Body>
</soapenv:Envelope>
--==_Part_20081204084150203==
Content-Type:text/plain
Content-Transfer-Encoding:binary
Content-ID:<attachment0.txt>
aaaaaaaaaaaaaaaaaaaaaaaaaaa
--==_Part_20081204084150203==
Content-Type:image/jpeg
Content-Transfer-Encoding:binary
Content-ID:<attachment1.jpg>
......JFIF.....d.d.....C...
--==_Part_20081204084150203==--
以上就是一个完整的mime附件的soap包。