分享
 
 
 

Attribute在.NET编程的应用(六)

王朝c#·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

Attribute在.NET编程的应用(六)

(承上节) .NET Framework拦截机制的设计中,在客户端和对象之间,存在着多种消息接收器,这些消息接收器组成一个链表,客户端的调用对象的过程以及调用返回实行拦截,你可以定制自己的消息接收器,把它们插入了到链表中,来完成你对一个调用的前处理和后处理。那么调用拦截是如何构架或者说如何实现的呢?

在.NET中有两种调用,一种是跨应用域(App Domain),一种是跨上下文环境(Context),两种调用均通过中间的代理(proxy),代理被分为两个部分:透明代理和实际代理。透明代理暴露同对象一样的公共入口点,当客户调用透明代理的时候,透明代理把堆栈中的帧转换为消息(上一节提到的实现IMessage接口的对象),消息中包含了方法名称和参数等属性集,然后把消息传递给实际代理,接下去分两种情况:在跨应用域的情况下,实际代理使用一个格式化器对消息进行序列化,然后放入远程通道中;在跨上下文环境的情况下,实际代理不必知道格式化器、通道和Context拦截器,它只需要在向前传递消息之前对调用实行拦截,然后它把消息传递给一个消息接收器(实现IMessageSink的对象),每一个接收器都知道自己的下一个接收器,当它们对消息进行处理之后(前处理),都将消息传递给下一个接收器,一直到链表的最后一个接收器,最后一个接收器被称为堆栈创建器,它把消息还原为堆栈帧,然后调用对象,当调用方法结果返回的时候,堆栈创建器把结果转换为消息,传回给调用它的消息接收器,于是消息沿着原来的链表往回传,每个链表上的消息接收器在回传消息之前都对消息进行后处理。一直到链表的第一个接收器,第一个接收器把消息传回给实际代理,实际代理把消息传递给透明代理,后者把消息放回到客户端的堆栈中。从上面的描述我们看到穿越Context的消息不需要格式化,CLR使用一个内部的通道,叫做CrossContextChannel,这个对象也是一种消息接收器。

有几种消息接收器的类型,一个调用拦截可以在服务器端进行也可以在客户端进行,服务器端接收器拦截所有对服务器上下文环境中对象的调用,同时作一些前处理和后处理。客户端的接收器拦截所有外出客户端上下文环境的调用,同时也做一些前处理和后处理。服务器负责服务器端接收器的安装,拦截对服务器端上下文环境访问的接收器称为服务器上下文环境接收器,那些拦截调用实际对象的接收器是对象接收器。通过客户安装的客户端接收器称为客户端上下文环境接受器,通过对象安装的客户端接收器则称为特使(Envoy)接收器,特使接收器仅拦截那些和它相关的对象。客户端的最后一个接收器和服务器端的第一个接收器是CrossContextChannel类型的实例。不同类型的接收器组成不同的段,每个段的端点都装上称为终结器的接收器,终结器起着把本段的消息传给下一个段的作用。在服务器上下文环境段的最后一个终结器是ServerContextTerminatorSink。如果你在终结器调用NextSink,它将返回一个null,它们的行为就像是死端头,但是在它们内部保存有下一个接收器对象的私有字段。

我们大致介绍了.NET Framework的对象调用拦截的实现机制,目的是让大家对这种机制有一个认识,现在是实现我们代码的时候了,通过代码的实现,你可以看到消息如何被处理的过程。首先是为我们的程序定义一个接收器CallTraceSink:

//TraceContext.cs

using System;

using System.Runtime.Remoting.Contexts;

using System.Runtime.Remoting.Messaging;

using System.Runtime.Remoting.Activation;

namespace NiwalkerDemo

{

public class CallTraceSink : IMessageSink //实现IMessageSink

{

private IMessageSink nextSink; //保存下一个接收器

//在构造器中初始化下一个接收器

public CallTraceSink(IMessageSink next)

{

nextSink=next;

}

//必须实现的IMessageSink接口属性

public IMessageSink NextSink

{

get

{

return nextSink;

}

}

//实现IMessageSink的接口方法,当消息传递的时候,该方法被调用

public IMessage SyncProcessMessage(IMessage msg)

{

//拦截消息,做前处理

Preprocess(msg);

//传递消息给下一个接收器

IMessage retMsg=nextSink.SyncProcessMessage(msg);

//调用返回时进行拦截,并进行后处理

Postprocess(msg,retMsg);

return retMsg;

}

//IMessageSink接口方法,用于异步处理,我们不实现异步处理,所以简单返回null,

//不管是同步还是异步,这个方法都需要定义

public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)

{

return null;

}

//我们的前处理方法,用于检查库存,出于简化的目的,我们把检查库存和发送邮件都写在一起了,

//在实际的实现中,可能也需要把Inventory对象绑定到一个上下文环境,

//另外,可以将发送邮件设计为另外一个接收器,然后通过NextSink进行安装

private void Preprocess(IMessage msg)

{

//检查是否是方法调用,我们只拦截Order的Submit方法。

IMethodCallMessage call=msg as IMethodCallMessage;

if(call==null)

return;

if(call.MethodName=="Submit")

{

string product=call.GetArg(0).ToString(); //获取Submit方法的第一个参数

int qty=(int)call.GetArg(1); //获取Submit方法的第二个参数

//调用Inventory检查库存存量

if(new Inventory().Checkout(product,qty))

Console.WriteLine("Order availible");

else

{

Console.WriteLine("Order unvailible");

SendEmail();

}

}

}

//后处理方法,用于记录订单提交信息,同样可以将记录作为一个接收器

//我们在这里处理,仅仅是为了演示

private void Postprocess(IMessage msg,IMessage retMsg)

{

IMethodCallMessage call=msg as IMethodCallMessage;

if(call==null)

return;

Console.WriteLine("Log order information");

}

private void SendEmail()

{

Console.WriteLine("Send email to manager");

}

}

...

接下来我们定义上下文环境的属性,上下文环境属性必须根据你要创建的接收器类型来实现相应的接口,比如:如果创建的是服务器上下文环境接收器,那么必须实现IContributeServerContextSink接口。

...

public class CallTraceProperty : IContextProperty, IContributeObjectSink

{

public CallTraceProperty()

{

}

//IContributeObjectSink的接口方法,实例化消息接收器

public IMessageSink GetObjectSink(MarshalByRefObject obj, IMessageSink next)

{

return new CallTraceSink(next);

}

//IContextProperty接口方法,如果该方法返回ture,在新的上下文环境中激活对象

public bool IsNewContextOK(Context newCtx)

{

return true;

}

//IContextProperty接口方法,提供高级使用

public void Freeze(Context newCtx)

{

}

//IContextProperty接口属性

public string Name

{

get { return "OrderTrace";}

}

}

...

最后是ContextAttribute ...

[AttributeUsage(AttributeTargets.Class)]

public class CallTraceAttribute : ContextAttribute

{

public CallTraceAttribute():base("CallTrace")

{

}

//重载ContextAttribute方法,创建一个上下文环境属性

public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)

{

ctorMsg.ContextProperties.Add(new CallTraceProperty());

}

}

}

为了看清楚调用Order对象的Submit方法如何被拦截,我们稍微修改一下Order类,同时把它设计为ContextBoundObject的派生类:

//Inventory.cs

//Order.cs

using System;

namespace NiwalkerDemo

{

[CallTrace]

public class Order : ContextBoundObject

{

...

public void Submit(string product, int quantity)

{

this.product=product;

this.quantity=quantity;

}

...

}

}

客户端调用代码:

...

public class AppMain

{

static void Main()

{

Order order1=new Order(100);

order1.Submit("Item1",150);

Order order2=new Order(101);

order2.Submit("Item2",150);

}

}

...

运行结果表明了我们对Order的Sbumit成功地进行了拦截。需要说明的是,这里的代码仅仅是作为对ContextAttribute应用的演示,它是粗线条的。在具体的实践中,大家可以设计的更精妙。

后记:本来想对Attribute进行更多的介绍,发现要讲的东西实在是太多了。请允许我在其他的专题中再来讨论它们。十分感谢大家有耐心读完这个系列。如果这里介绍的内容在你的编程生涯有所启迪的话,那么就是我的莫大荣幸了。再一次谢谢大家。

(全文完)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有