在流模式下利用消息头传输带外信息
2010-04-19 12:52
344 查看
WCF为传输层实现数据流在客户和服务之间进行传输提供了很好的支持,不过在使用这种方式时,我们必须遵循相应的约定。WCF服务在启动时会首先检查操作契约是否符合这种规范。因为通常模式下我们不能简单地在客户中使用特定的流,如我们在传输文件时,我们目的是要得到文件对象,而不是流对象。因为我们使用了不同类型的文件(如:*.doc,*.exe等),那么在另一端我们应该能够重现这种类型,不过由于使用流传输带来很好的性能,于是我们想在文件传输中使用这种流模式。那么就得附加相应的文件信息给异端,以便重现文件。这时我们就可以使用SOAP消息头来附加这些信息了。
1流模式的操作契约约定:
首先我们先来了解一下使用流模式的基本的操作契约要求。要使用流模式,我们在操作契约中只能是以单个的输入输出流作为参数,也就是说方法的参数和返回参数,要么是Stream对象或派生类对象,要么void,形如以下的方法签名可认可:
void SendStream(Stream inStream);
Stream ReceiveStream();
Stream SendAndReceiveStream(Stream inStream);
void SendAndReceiveStream(Stream inStream,out Stream outStream);
void ReceiveStream(out Stream outStream)
从上面的签名我们可以看出如果我们要在服务和客户之间传递一个文件流,在方法中是无法传递一个参数来达到的,所以这儿为了传递文件名和路径,我们选择使用消息头附加这些信息的方式来实现,这儿定义操作契约为:
2 WCF消息头相关的类和方法
OperationContext类代表操作上下文,它提供的IncomingMessageHeaders和OutgoingMessageHeaders属性来操作输入输出消息头:
public sealed class OperationContext :
IExtensibleObject<OperationContext>{
}
MessageHeader<T>代表SOAP 标头的内容,用泛型类来增强类型的安全。
}
MessageHeaders代表消息头的消息集合,这儿我们只用到GetHeader<T>()泛型方法
public sealed class MessageHeaders : IEnumerable<MessageHeaderInfo>, IEnumerable{
public T GetHeader<T>(int index);
}
OperationContextScope类是在当前上下文不适用时,可以切换为新的上下文。其构造函数可以将当前的上下文替换为新的上下文,而调用完成之后使用Dispose()方法恢复原来的上下文。
public sealed class OperationContextScope : IDisposable{
// Methods
public OperationContextScope(IContextChannel channel);
public OperationContextScope(OperationContext context);
public void Dispose();
……
}
3首先我们来实现附加消息头的逻辑
这里为了统一我们实现了一个数据契约【StreamContext】来包含要附加的带外信息。这个数据契约包括三个属性:FileName(文件名),FilePath(目标路径),FileLength(文件长度,可选)。还有一个静态的代表当前上下文的定制属性Current。为了简便起见我们实现了自定义消息头的封装。
客户调用
小结
使用消息头的方式在向服务传递带外信息不失为一种好的技术,这种方式一般用在不宜出现在服务契约中的数据或信息。不过如果服务契约能很好地满足我们数据的传递,建议在操作契约中设定参数的形式来传递,毕竟这样可以我们的程序具有良好的阅读性。
点击下载范例Code
1流模式的操作契约约定:
首先我们先来了解一下使用流模式的基本的操作契约要求。要使用流模式,我们在操作契约中只能是以单个的输入输出流作为参数,也就是说方法的参数和返回参数,要么是Stream对象或派生类对象,要么void,形如以下的方法签名可认可:
void SendStream(Stream inStream);
Stream ReceiveStream();
Stream SendAndReceiveStream(Stream inStream);
void SendAndReceiveStream(Stream inStream,out Stream outStream);
void ReceiveStream(out Stream outStream)
从上面的签名我们可以看出如果我们要在服务和客户之间传递一个文件流,在方法中是无法传递一个参数来达到的,所以这儿为了传递文件名和路径,我们选择使用消息头附加这些信息的方式来实现,这儿定义操作契约为:
[ServiceContract ] public interface ISendStreamService { //利用流的传输模式来实现,消息头附加信息 [OperationContract] void SendStream(Stream stream); }
2 WCF消息头相关的类和方法
OperationContext类代表操作上下文,它提供的IncomingMessageHeaders和OutgoingMessageHeaders属性来操作输入输出消息头:
public sealed class OperationContext :
IExtensibleObject<OperationContext>{
public MessageHeaders OutgoingMessageHeaders { get; }
public MessageHeaders IncomingMessageHeaders { get; }
……
}
MessageHeader<T>代表SOAP 标头的内容,用泛型类来增强类型的安全。
public class MessageHeader<T>{
public MessageHeader();
public MessageHeader(T content);
public MessageHeader(T content, bool mustUnderstand, string actor, bool relay);
//得到与类型无关的原始消息头
public MessageHeader GetUntypedHeader(string name, string ns);
}
MessageHeaders代表消息头的消息集合,这儿我们只用到GetHeader<T>()泛型方法
public sealed class MessageHeaders : IEnumerable<MessageHeaderInfo>, IEnumerable{
public T GetHeader<T>(int index);
public T GetHeader<T>(int index, XmlObjectSerializer serializer);
public T GetHeader<T>(string name, string ns);
public T GetHeader<T>(string name, string ns, params string[] actors);
public T GetHeader<T>(string name, string ns, XmlObjectSerializer serializer);
……
}
OperationContextScope类是在当前上下文不适用时,可以切换为新的上下文。其构造函数可以将当前的上下文替换为新的上下文,而调用完成之后使用Dispose()方法恢复原来的上下文。
public sealed class OperationContextScope : IDisposable{
// Methods
public OperationContextScope(IContextChannel channel);
public OperationContextScope(OperationContext context);
public void Dispose();
……
}
3首先我们来实现附加消息头的逻辑
这里为了统一我们实现了一个数据契约【StreamContext】来包含要附加的带外信息。这个数据契约包括三个属性:FileName(文件名),FilePath(目标路径),FileLength(文件长度,可选)。还有一个静态的代表当前上下文的定制属性Current。为了简便起见我们实现了自定义消息头的封装。
客户调用
string file=FileUpload1.PostedFile.FileName; inStream = new FileStream(file, FileMode.Open, FileAccess.Read); file = file.Substring(file.LastIndexOf("\\") + 1); string path = Server.MapPath(Request.Path); path = path.Substring(0, path.LastIndexOf("\\")); StreamContext context = new StreamContext(file, path, 0); client = new SendStreamClient("setEndpoint"); //在当前线程上建立一个与client相应的线程 using (OperationContextScope scope = new OperationContextScope(client.InnerChannel)) {//建立新的上下文 //设置消息头附加信息 StreamContext.Current = context; client.Open(); client.BeginSendStream(inStream, new AsyncCallback(Callback), file); }
小结
使用消息头的方式在向服务传递带外信息不失为一种好的技术,这种方式一般用在不宜出现在服务契约中的数据或信息。不过如果服务契约能很好地满足我们数据的传递,建议在操作契约中设定参数的形式来传递,毕竟这样可以我们的程序具有良好的阅读性。
点击下载范例Code
相关文章推荐
- APRS,一种利用业余无线电波段传输GPS信息的组网模式
- C#对象间的协作和信息交换(六)利用事件(Event)广播消息
- 关于利用SIM908 工程模式中的cellid lac 参数值进行基站定位(Sim900和sim908不一样,sim908没有直接读取基站定位信息的指令)
- 利用PHP命令行模式采集股票趋势信息
- 利用UDP进行信息传输
- 利用fiddler 截获微信传输数据 (方便抓取公众号信息)
- 理解JMS规范中消息的传输模式和消息持久化
- 利用redis实现消息队列之queue模式
- 服务器 用户模式 实现信息传输(实现QQ功能)
- 基于消息队列的信息传输机制
- 有关工作组模式以及 Microsoft 消息队列中域模式信息
- 理解JMS规范中消息的传输模式和消息持久化
- 探索AJAX中的消息传输模式(一)
- 利用 WAS V6.1 开发安全可靠的 Web Services,第 2 部分:实现可靠的消息传输
- 利用Socket.Send发送信息、Socket.SendFile传输文件
- 探索AJAX中的消息传输模式(一)
- 探索AJAX中的消息传输模式(二)
- 利用IP组播技术传输视频信息
- MFC中消息机制之实现多窗体信息的传输
- 利用redis实现消息队列之topic模式