[WCF 学习笔记] 8. 数据传输
2009-01-17 15:05
465 查看
WCF 服务方法通过接收消息、处理消息、回复消息来完成调用。所有的数据都被序列化,并转换成消息后再行传输,接收方执行相反的动作获得数据对象。
消息描述
最简单就是消息描述就是方法参数,所有的基本类型可以直接被序列化。我们还可以使用 MessageParameterAttribute 为参数定义消息名称。
[ServiceContract]
public interface IContract
{
[OperationContract]
double Add(double a, double b);
[OperationContract]
void Test([MessageParameter(Name="myString")]string s);
}
对于自定义类型,我们可以使用 DataContractAttribute 或 MessageContractAttribute 来定义,这些在前面的章节已经提过,此处不再做进一步说明。
WCF 服务方法支持 ref / out 关键字,也就是说底层引擎会重新为添加了关键字的对象赋予返回值。我们使用 "Message Logging" 和 "Service Trace Viewer" 查看一下 Reply Message。
Server.cs
[ServiceContract]
public interface IContract
{
[OperationContract]
double Add(double a, ref double b);
}
public class MyService : IContract
{
public double Add(double a, ref double b)
{
b += 2;
return a + b;
}
}
client.cs
using (ContractClient client = new ContractClient(new BasicHttpBinding(),
new EndpointAddress("http://localhost:8080/myservice")))
{
double b = 2;
double c = client.Add(1, ref b);
Console.WriteLine("c={0};b={1}", c, b);
}
Reply Message
<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://...">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://...">http://tempuri.org/IContract/AddResponse</Action>
</s:Header>
<s:Body>
<AddResponse xmlns="http://tempuri.org/">
<AddResult>5</AddResult>
<b>4</b>
</AddResponse>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
在 Reply Message 中除了返回值 "AddResult" 外,还有 "b"。:-)
需要注意的是,即便我们使用引用类型的参数,由于 WCF 采取序列化传送,因此它是一种 "值传递",而不是我们习惯的 "引用传递"。看看下面的例子,注意方法参数和数据结果的不同。
Server.cs
[DataContract]
public class Data
{
[DataMember]
public int I;
}
[ServiceContract]
public interface IContract
{
[OperationContract]
void Add(Data d);
[OperationContract]
void Add2(ref Data d);
}
public class MyService : IContract
{
public void Add(Data d)
{
d.I += 10;
}
public void Add2(ref Data d)
{
d.I += 10;
}
}
Client.cs
using (ContractClient client = new ContractClient(new BasicHttpBinding(),
new EndpointAddress("http://localhost:8080/myservice")))
{
Data d = new Data();
d.I = 1;
client.Add(d);
Console.WriteLine("d.I={0}", d.I);
Data d2 = new Data();
d2.I = 1;
client.Add2(ref d2);
Console.WriteLine("d2.I={0}", d2.I);
}
输出:
d.I=1
d2.I=11
序列化引擎
缺
省情况下,WCF 使用 DataContractSerializer 引擎对相关参数进行序列化,这也是 WCF 推荐的方式。另外一个选择是
XmlSerializer,也就是 ASP.NET Web Service 所使用的序列化引擎。XmlSerializer 仅支持
DataContractSerializer 所支持的部分类型,但它允许你使用 XmlAttributeAttribute
等特性对序列化生成的 XML 进行更多的控制。
DataContractSerializer 支持的类型:
支持所有的基本类型,还包括 XmlElement 和 DateTime 这样的常用类型。
支持使用 DataContractAttribute 标记的类型。
支持使用 SerializableAttribute 标记或者实现 ISerializable 接口的类型。
实现 IXmlSerializable 接口的类型。
大多数集合(含泛型)类型,包括常用的 Array、List、IList 等。
通
过向服务添加 XmlSerializerFormatAttribute 标记,就可以手动切换到 XmlSerializer
引擎。此时使用自定义类型,无须使用
SerializableAttribute、ISerializable、DataContractAttribute 等特性或接口。
public class Data
{
public int I = 1234;
public string X = "Hello, World!";
}
[ServiceContract, XmlSerializerFormat]
public interface IContract
{
[OperationContract]
void Test(Data d);
}
public class MyService : IContract
{
public void Test(Data d)
{
Console.WriteLine("i={0}; x={1}", d.I, d.X);
}
}
public class WcfTest
{
public static void Test()
{
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
ServiceHost host = new ServiceHost(typeof(MyService));
host.AddServiceEndpoint(typeof(IContract), new BasicHttpBinding(),
"http://localhost:8080/myservice");
host.Open();
});
ChannelFactory<IContract> factory = new ChannelFactory<IContract>(new BasicHttpBinding(),
"http://localhost:8080/myservice");
IContract client = factory.CreateChannel();
Data d = new Data();
d.I = 123456;
d.X = "China";
client.Test(d);
}
}
我们为自定义类型添加控制标记,看看 Request Message 的变化。
public class Data
{
[System.Xml.Serialization.XmlAttribute]
public int I = 1234;
[System.Xml.Serialization.XmlElement]
public string X = "Hello, World!";
}
Request Message
<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://.../">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://...">http://tempuri.org/IContract/Test</Action>
</s:Header>
<s:Body xmlns:xsi="http://..." xmlns:xsd="http://...">
<Test xmlns="http://tempuri.org/">
<d I="123456">
<X>China</X>
</d>
</Test>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
需要注意一个区别,我们 DataContractSerializer 和 DataContractAttribute 的时候,只有标记了 DataMemberAttribute 的成员被序列化,而 XmlSerializer 是序列化全部 "可视" 成员。
有关 WCF 序列化的更多细节,以后再写相关的研究专题。本文只是作为初次学习的一个简要记录。
消息描述
最简单就是消息描述就是方法参数,所有的基本类型可以直接被序列化。我们还可以使用 MessageParameterAttribute 为参数定义消息名称。
[ServiceContract]
public interface IContract
{
[OperationContract]
double Add(double a, double b);
[OperationContract]
void Test([MessageParameter(Name="myString")]string s);
}
对于自定义类型,我们可以使用 DataContractAttribute 或 MessageContractAttribute 来定义,这些在前面的章节已经提过,此处不再做进一步说明。
WCF 服务方法支持 ref / out 关键字,也就是说底层引擎会重新为添加了关键字的对象赋予返回值。我们使用 "Message Logging" 和 "Service Trace Viewer" 查看一下 Reply Message。
Server.cs
[ServiceContract]
public interface IContract
{
[OperationContract]
double Add(double a, ref double b);
}
public class MyService : IContract
{
public double Add(double a, ref double b)
{
b += 2;
return a + b;
}
}
client.cs
using (ContractClient client = new ContractClient(new BasicHttpBinding(),
new EndpointAddress("http://localhost:8080/myservice")))
{
double b = 2;
double c = client.Add(1, ref b);
Console.WriteLine("c={0};b={1}", c, b);
}
Reply Message
<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://...">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://...">http://tempuri.org/IContract/AddResponse</Action>
</s:Header>
<s:Body>
<AddResponse xmlns="http://tempuri.org/">
<AddResult>5</AddResult>
<b>4</b>
</AddResponse>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
在 Reply Message 中除了返回值 "AddResult" 外,还有 "b"。:-)
需要注意的是,即便我们使用引用类型的参数,由于 WCF 采取序列化传送,因此它是一种 "值传递",而不是我们习惯的 "引用传递"。看看下面的例子,注意方法参数和数据结果的不同。
Server.cs
[DataContract]
public class Data
{
[DataMember]
public int I;
}
[ServiceContract]
public interface IContract
{
[OperationContract]
void Add(Data d);
[OperationContract]
void Add2(ref Data d);
}
public class MyService : IContract
{
public void Add(Data d)
{
d.I += 10;
}
public void Add2(ref Data d)
{
d.I += 10;
}
}
Client.cs
using (ContractClient client = new ContractClient(new BasicHttpBinding(),
new EndpointAddress("http://localhost:8080/myservice")))
{
Data d = new Data();
d.I = 1;
client.Add(d);
Console.WriteLine("d.I={0}", d.I);
Data d2 = new Data();
d2.I = 1;
client.Add2(ref d2);
Console.WriteLine("d2.I={0}", d2.I);
}
输出:
d.I=1
d2.I=11
序列化引擎
缺
省情况下,WCF 使用 DataContractSerializer 引擎对相关参数进行序列化,这也是 WCF 推荐的方式。另外一个选择是
XmlSerializer,也就是 ASP.NET Web Service 所使用的序列化引擎。XmlSerializer 仅支持
DataContractSerializer 所支持的部分类型,但它允许你使用 XmlAttributeAttribute
等特性对序列化生成的 XML 进行更多的控制。
DataContractSerializer 支持的类型:
支持所有的基本类型,还包括 XmlElement 和 DateTime 这样的常用类型。
支持使用 DataContractAttribute 标记的类型。
支持使用 SerializableAttribute 标记或者实现 ISerializable 接口的类型。
实现 IXmlSerializable 接口的类型。
大多数集合(含泛型)类型,包括常用的 Array、List、IList 等。
通
过向服务添加 XmlSerializerFormatAttribute 标记,就可以手动切换到 XmlSerializer
引擎。此时使用自定义类型,无须使用
SerializableAttribute、ISerializable、DataContractAttribute 等特性或接口。
public class Data
{
public int I = 1234;
public string X = "Hello, World!";
}
[ServiceContract, XmlSerializerFormat]
public interface IContract
{
[OperationContract]
void Test(Data d);
}
public class MyService : IContract
{
public void Test(Data d)
{
Console.WriteLine("i={0}; x={1}", d.I, d.X);
}
}
public class WcfTest
{
public static void Test()
{
AppDomain.CreateDomain("Server").DoCallBack(delegate
{
ServiceHost host = new ServiceHost(typeof(MyService));
host.AddServiceEndpoint(typeof(IContract), new BasicHttpBinding(),
"http://localhost:8080/myservice");
host.Open();
});
ChannelFactory<IContract> factory = new ChannelFactory<IContract>(new BasicHttpBinding(),
"http://localhost:8080/myservice");
IContract client = factory.CreateChannel();
Data d = new Data();
d.I = 123456;
d.X = "China";
client.Test(d);
}
}
我们为自定义类型添加控制标记,看看 Request Message 的变化。
public class Data
{
[System.Xml.Serialization.XmlAttribute]
public int I = 1234;
[System.Xml.Serialization.XmlElement]
public string X = "Hello, World!";
}
Request Message
<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://.../">
<s:Header>
<Action s:mustUnderstand="1" xmlns="http://...">http://tempuri.org/IContract/Test</Action>
</s:Header>
<s:Body xmlns:xsi="http://..." xmlns:xsd="http://...">
<Test xmlns="http://tempuri.org/">
<d I="123456">
<X>China</X>
</d>
</Test>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>
需要注意一个区别,我们 DataContractSerializer 和 DataContractAttribute 的时候,只有标记了 DataMemberAttribute 的成员被序列化,而 XmlSerializer 是序列化全部 "可视" 成员。
有关 WCF 序列化的更多细节,以后再写相关的研究专题。本文只是作为初次学习的一个简要记录。
相关文章推荐
- WCF学习笔记(六)自定义绑定和C/S之间传输流的绑定
- WCF学习笔记:传递DataTable 报错是因为WCF不支持DataTable数据类型,DataContractSerializer 支持的类型
- 5.7_Android Training 学习笔记_ 使用 Volley 执行网络数据传输
- ALSA声卡10_从零编写之数据传输_学习笔记
- ffmpeg--学习笔记(二)-将电脑的摄像头数据传输到服务器上去
- Silverlight学习笔记二:Silverlight从WCF那里获取数据,WCF为Silverlight提供数据
- ALSA声卡10_从零编写之数据传输_学习笔记
- TCP/IP网络编程 学习笔记_14 --多种I/O函数(数据传输扩展)
- 网络编程学习笔记-网络中数据传输过程的分析
- JSON数据传输学习笔记
- WCF RIA service 学习笔记三 数据验证
- WF实例学习笔记:(2)通过Workflow 调用 WCF Data Services 获取数据
- ZigBee组网学习笔记(五)--无线数据传输
- TCP/IP网络编程 学习笔记_14 --多种I/O函数(数据传输扩展)
- 以XML格式传输数据 (2)--Ajax学习笔记
- [TCP IP详解:学习笔记]数据传输
- Struts2 的学习笔记(三) Struts2 数据传输
- USB学习笔记连载(二十一):CY7C68013A进行数据传输(一)
- USB学习笔记连载(二十一):CY7C68013A进行数据传输(一)
- 数据的网络传输学习笔记