.NET 上下文拦截(2) [转]
在 .NET 中,默认的对象都是上下文敏感对象,他们会被放置在引用他们的宿主的上下文中,如果我们想使用上下文服务,必须使我们的对象放置在提供特定的服务的上下文中,这一类型的对象是面向上下文的对象,这些对象的类必须直接或间接继承自ContextBoundObject类.面向上下文对象在创建时会检查创建宿主的上下文是否提供他所需要的服务,如果宿主不提供需要的服务,那么.NET 将首先创建一个可以提供需要服务的上下文,然后在新创建的上下文中创建对象.
在.NET 中,跨上下文的访问和Remoting很相似.他们都不直接引用创建的代理,而是使用代理访问另一个上下文中对象.
通常的情况是 客户端 ->透明代理 ->真实代理 ->客户端接收器 ->信道 ->服务器端接收器->堆栈构造 ->面向上下文对象.通过这个调用链,我们可以发现,在跨上下文调用中没有Remoting 中使用的格式器,并且跨上下文调用使用的信道也和Remoting 中的信道不一样,在跨上下文调用中使用CrossContextChannel信道.
上面的调用链并不完整(大家有兴趣可以查看相关资料),但通过上面的调用链已经可以让我们大致了解.NET 的上下文拦截框架.在.NET中我们可以在客户段接收器和服务端接受器上加入我们自己的消息接收器来实现消息拦截. .NET为了支持添加消息接收器,提供了类似装饰器的模式,我们在自己的消息接收器类中必须维持一个对下一个消息接收器的引用.
下面我们就实现一个简单的拦截.为了更直观的展示拦截技术,我们只实现极其简单的功能,就是把方法的调用参数和返回值打印出来,当然打印的方法并不是在客户端,而是在消息接收器中,客户代码和正常代码没有任何区别.
首先我们要实现接收器.代码如下
在.NET 中,跨上下文的访问和Remoting很相似.他们都不直接引用创建的代理,而是使用代理访问另一个上下文中对象.
通常的情况是 客户端 ->透明代理 ->真实代理 ->客户端接收器 ->信道 ->服务器端接收器->堆栈构造 ->面向上下文对象.通过这个调用链,我们可以发现,在跨上下文调用中没有Remoting 中使用的格式器,并且跨上下文调用使用的信道也和Remoting 中的信道不一样,在跨上下文调用中使用CrossContextChannel信道.
上面的调用链并不完整(大家有兴趣可以查看相关资料),但通过上面的调用链已经可以让我们大致了解.NET 的上下文拦截框架.在.NET中我们可以在客户段接收器和服务端接受器上加入我们自己的消息接收器来实现消息拦截. .NET为了支持添加消息接收器,提供了类似装饰器的模式,我们在自己的消息接收器类中必须维持一个对下一个消息接收器的引用.
下面我们就实现一个简单的拦截.为了更直观的展示拦截技术,我们只实现极其简单的功能,就是把方法的调用参数和返回值打印出来,当然打印的方法并不是在客户端,而是在消息接收器中,客户代码和正常代码没有任何区别.
首先我们要实现接收器.代码如下
public class DemoSink : IMessageSink
{
private IMessageSink m_NextSink;
public DemoSink(IMessageSink nextSink)
{
m_NextSink = nextSink;
}
IMessageSink 成员IMessageSink 成员
}
{
private IMessageSink m_NextSink;
public DemoSink(IMessageSink nextSink)
{
m_NextSink = nextSink;
}
IMessageSink 成员IMessageSink 成员
}
通过上面的代码可以看出,消息接收器的实现很简单.我们在同步方法调用中,在方法调用前和调用后插入了一些处理,把方法调用参数和返回值打印了出来.
在实现了消息接收器后,我们还要添加两个类,用于把接收器添加到消息接收链中.
首先我们要创建一个自定义特性(Attribute)类,使用自定义特性来标注使用上下文拦截是组件(类).这个特性类不能直接继承自Attribute 类,必须继承自 ContextAttribute 类,然后还要创建一个实现接口IContextProperty和IContributeServerContextSink的类.
两个类的代码如下
[AttributeUsage(AttributeTargets.Class)]
public class DemoContextAttribute : ContextAttribute
{
public DemoContextAttribute()
: base("DemoContextAttribute")
{
}
public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
DemoProperty proerty = new DemoProperty();
ctorMsg.ContextProperties.Add(proerty);
}
public override bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
{
DemoProperty property = ctx.GetProperty("DemoTest") as DemoProperty;
if (property == null) return false;
else return true;
}
}
public class DemoContextAttribute : ContextAttribute
{
public DemoContextAttribute()
: base("DemoContextAttribute")
{
}
public override void GetPropertiesForNewContext(IConstructionCallMessage ctorMsg)
{
DemoProperty proerty = new DemoProperty();
ctorMsg.ContextProperties.Add(proerty);
}
public override bool IsContextOK(Context ctx, IConstructionCallMessage ctorMsg)
{
DemoProperty property = ctx.GetProperty("DemoTest") as DemoProperty;
if (property == null) return false;
else return true;
}
}
public class DemoProperty : IContextProperty, IContributeServerContextSink
{
public DemoProperty()
{
}
IContextProperty 成员IContextProperty 成员
IContributeServerContextSink 成员IContributeServerContextSink 成员
}
{
public DemoProperty()
{
}
IContextProperty 成员IContextProperty 成员
IContributeServerContextSink 成员IContributeServerContextSink 成员
}
然后我们就可以为指定的组件(类)添加上下文服务了
[DemoContext]
class Class1 : ContextBoundObject
{
public int Add(int a, int b)
{
return a + b;
}
}
class Class1 : ContextBoundObject
{
public int Add(int a, int b)
{
return a + b;
}
}
客户端代码和没有任何改变
class Program
{
static void Main(string[] args)
{
Class1 c = new Class1();
int a = c.Add(1, 2);
}
}
{
static void Main(string[] args)
{
Class1 c = new Class1();
int a = c.Add(1, 2);
}
}
上面的代码只是演示上下文拦截技术的实现,在实际编程中,我们可以使用上下文拦截实现把日志管理,角色权限管理,事务管理等一些管道工作从我们的组件(类)代码中剥离,使我们的组件(类)只关注服务的实现,而不需要去关心这些管道工作.
本文来源:http://www.cnblogs.com/TomCat007/archive/2008/05/19/1202845.html