欢迎来到.net学习网

欢迎联系站长一起更新本网站!QQ:879621940

您当前所在位置:首页 »  .NET本质论第一卷:公共语言运行库教程 » 正文

本教程章节列表

消息接收器区域-信使接收器(envoy sink)

创建时间:2013年03月18日 22:56  阅读次数:(4634)
分享到:
要讨论的最后一个消息接收器区域是信使接收器(envoy sink)。像客户端上下文接收器一样,信使接收器(envoy sink)在切换到上下文之前执行。客户端上下文接收器是由调用方上下文提供的。信使接收器在调用方的上下文中,充当服务器上下文接收器的使者(ambassador),用于检查调用方上下文的某些信息片断[例如,安全信息、区域(locale)以及事务标志],并且通过调用上下文属性将它们发送到服务器上下文接收器。这种通信方式能双向工作:服务器上下文接收器能传递上游信息到其信使接收器,作为响应消息的一部分,并且信使接收器能在最终返回该代理的控制权之前,调整调用方的执行状态。信使接收器由目标上下文中的上下文属性提供,这些属性必须实现IContributeEnvoySink接口

为了理解信使接收器的角色,我们再次列举线程优先级的示例。前面的实现总是将线程优先级设置成一个绝对级别,而没有顾及现存的优先级。如果我们想实现一个截获器,它能将线程级别提高一级,那应该怎么做呢?一种解决方式就是在服务器上下文接收器中处理:
IMessage SyncProceseMessage(IMessage m){
//缓存
Thread here=Thread.CurrentThread;
ThradPriority oldp=here.Priority;
ThreadPriority newp=old;
/促进
if(newp!=ThreadPriority.Highest)
here.Priority=newp+1;
//分发调用
Imessager=next.SyncProcessMessage(m);
//恢复
if(newp!=ThreadPriority.Highest)
 here.Priority=old;
return r;
}

遗憾的是,只有我们仍然运行在调用方的原始线程上,这种方式才奏效。对于任意的消息接收器,我们无法保证这一点。更进一步地说,我们需要构建一个这样的信使接收器,它能传播原来的优先级到我们的服务器端上下文接收器,并作为调用上下文的附加信息。并且,为了确保这个调用上下文总是被传播的,我们需要额外的数据以支持ILogicalThreadAffinative接口。下面就是我们需要的:
internal class EnovyData:IlogicalThreadAffinative{
internal ThreadPriority clientPriority;
internal EnvoyData(ThreadPriority p)
{clientPriority=p;}
}

在我们的信使接收器准备沿着接收器链向下转发消息之前,它只是简单地将优先级加到这个消息中:
public class PriorityEnvoySink:ImessageSink{
 public Imessage SyncProcessMessage(Imessage m){
  ImethodCallMessage call=(IMethodCallMessage)m;
  ThreadPriority p=Thread.CurrentThread.Priority;
  EnvoyData ed=new EnvoyData(p);
  call.LogicalCallContext.SetData(“clientpriority”,ed);
  return next.SyncProcessMessage(call);
}
//为了清晰起见,余下部分省略。
}

这里允许我们的下游服务器端上下文接收器在调用上下文之外,删除调用方的优先级,如下所示:
public class PriorityServerSink:ImessageSink{
public Imessage SyncProcessMessage(Imessage m){
//从调用上下文获取调用方的优先级
ImethodCallMessage call=(IMethodCallMessage)m;
LogicalcallContext cc=call.LogicalCallContext;
EnvoyData ed=(EnvoyData)cc.GetData(“clientpriority”);
cc.FreeNamedDataSlot(“clientpriority”);

//进行boost-dispatch-unboost!
Thread here=Thred.CurrentThread;
ThreadPriority old=here.Priority;
if(ed.clientPriority!=ThreadPriority.Highest)
 here.Priority=ed.clientPriority+1;
IMessage resp=next.SyncProcessMessage(call);
if(ed.clietnPriority!=ThreadPriority.Highest)
 here.Priority=old;
 return resp;
}
//为了清晰起见,余下部分省略
}

现在我们所需要的只是一个简单的上下文属性,用于插入这两个消息接收器:
public class BoostProperty:IcontextProperty,IcontributeEnvoySink,IcontributeServerContextSink{
public ImessageSink GetEnvoySink(MarshalByRefObject obj,ImessageSink n)
{return new PriorityEnvoySink(n);}
public ImessageSink GetServerContextSink(ImessageSink n){
return new PriorityServerSink(n);
}
public string Name{get{return “Boost”}}
public bool IsNewContextOK(Context ctx){return true;}
public void Freeze(Context ctx){}
}

插入到这个属性中的上下文特性绝对是一个样本,不过,存在一种例外的情形。由于newobj操作码在我们的信使接收器之前执行,因而对于我们的服务器端上下文接收器的SyncProcessMessage,它的首次调用将无法得到EnvoyData的好处。为了处理这个问题,我们的上下文特性需要在它的GetPropertiesForNewContext方法中,将调用上下文属性插入到构造调用(construction call)的消息中:
public void GetPropertiesForNewContext(IconstructionCallMessage ctor){
//增加我们的属性到新的上下文
ctor.ContextProperties.Add(new BoostProperty());
//在调用上下文中保存当前线程的优先级
ctor.LogicalCallContext.SetData(“clientpriority”,new EnvoyData(Thread.CurrentThread.Priority));
}

从本质上讲,上下文特性为构造函数调用扮演了信使接收器的角色。

我们走到哪儿了
CLR提供了一个丰富的架构,用于把方法调用视为消息交换。这个架构的关键是透明代理的实用部件,它是由CLR的远程库(remoting library)提供的。透明代理将在调用堆栈世界的边界活动,它允许开发人员把该世界视为消息过滤器的管道。CLR还提供了一个强大的上下文概念,它允许你透明地将截获集成到以类型为中心的编程模型中。
来源:.net学习网
说明:所有来源为 .net学习网的文章均为原创,如有转载,请在转载处标注本页地址,谢谢!
【编辑:Wyf】

打赏

取消

感谢您的支持,我会做的更好!

扫码支持
扫码打赏,您说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

最新评论

共有评论0条
  • 暂无任何评论,请留下您对本文章的看法,共同参入讨论!
发表评论:
留言人:
内  容:
请输入问题 71+63=? 的结果(结果是:134)
结  果: