在前面一篇文章中,我对Enterprise Library中的PIAB (Policy Injection Application Block)作了简单的介绍。在这篇文章主要谈谈我个人对PIAB设计和实现原理的一些理解。在介绍过程中,我尽量采用由浅入深出的方式,同时结合例子、Source Code。希望通过本篇文章让大家对PIAB有一个全面、深刻的认识。
一、MBR、ObjRef、RealProxy、TransparentProxy
在真正进入PIAB之前,我们现来谈论一些与之相关的、必要的背景知识。MBR、ObjRef、RealProxy和TransparentProxy,对于这些名词,我想熟悉或者接触过.NET Remoting的人肯定不会不陌生。由于PIAB的实现机制依赖于Remoting的这种Marshaling,如果对此不了解的读者将对后面的介绍很难理解,所以很有必要先做以下简单的介绍。
我们知道,CLR通过AppDomain实现不同Application之间的隔离,在通常情况下,不同AppDomain不同共享内存。在一个AppDomain中创建的对象不能直接被运行在另一个AppDomain的程序使用。跨AppDomain对象的共享依赖于一个重要的过程:Marshaling。我们有两种不同的Marshaling方式:Marshaling by Value和Marshaling by Reference。前者采用的是Serialization/Deserialization的方式,而后者则是采用传递Reference的方式来实现,其实现原来如下:
Remoting Infrastructure先生成对象的ObjRef Instance,ObjRef(System.Runtime.Remoting.ObjRef)代表远程对象的一个Reference,存储着跨AppDomain远程调用所需的所有的信息,比如URI、类型的层次结构、以及实现的Interface等等。ObjRef是可以序列化的,也就是说它可以按照by Value的方式进行Marshaling。所以可以这么说Marshaling by Reference依赖对对ObjRef的Marshaling by Value。
当ObjRef产地到另一个AppDomain的实现,将根据ObjRef的数据生成两个Proxy对象:RealProxy和TransparentProxy。RealProxy根据ObjRef创建,通过RealProxy创建TransparentProxy。当进行远程调用的时候,Client直接和TransparentProxy打交道,对TransparentProxy的调用将会Forward到RealProxy,RealProxy通过Remoting Infrastructure的Communicate和Activation机制将Invocate传递给被激活的Remote Object。
MBR通常在一个跨AppDomain的环境下实现远程调用,但是这种机制在用一个AppDomian依然有效,而且可以免去跨AppDomain的性能损失。PIAB就是充分运用了这种在同一个AppDomain下的MBR。
二、Method Interception & Custom RealProxy
在第一部分我们知道,PIAB的实现是通过将Policy应用到对应的Method上,在真正执行目标对象具体的方法的之前,PIAB将整个方法的调用拦截,然后逐个调用应在该Method上的Policy包含的所有CallHandler(在前一章我们说过Policy = Matching Rule + Call Handler),最后再调用真正目标对象的方法。我们把这种机制成为Method Injection。
如何才有实现这样的Method Injection呢?这就要需要使用到我们在上面一节介绍的MBR了。通过上面的介绍,我们知道我们调用一个MBR Object的过程是这样的:
Client Code==〉Transparent Proxy==〉Real Proxy==〉Target Object
在上面的Invocate Chain中,由于真正的目标对象的方法在最后一部才被调用,我们完全有可以在中途将调用”劫持”,使之先调用我们的CallHandler。而这种Inject的突破口在于RealProxy。在FCL(Framework Class Library)中RealProxy(System.Runtime.Remoting.Proxies.RealProxy)是个特殊的Abstract Class,你可以继承RealProxy定义你自己的Custom RealProxy,将你需要注入的操作写在Invoke方法中。PIAB采用的就是这样一种解决方案。
我们先不忙介绍PIAB的具体的实现原理,因为相对比较复杂。为了使读者能够更加容易地理解PIAB的实现,我写了一个简单的例子。我们它能够大体体现PIAB的实现机制。
这是一个简单的Console Application,我首先定义了一个Custom RealProxy:
publicclass MyRealProxy<T>:RealProxy
{
private T _target;
public MyRealProxy(T target)
: base(typeof(T))
{
this._target = target;
}
public override IMessage Invoke(IMessage msg)
{
//Invoke injected pre-operation.
Console.WriteLine("The injected pre-operation is invoked");
//Invoke the real target instance.
IMethodCallMessage callMessage = (IMethodCallMessage)msg;
object returnValue = callMessage.MethodBase.Invoke(this._target, callMessage.Args);
//Invoke the injected post-operation.
Console.WriteLine("The injected post-peration is executed");
//Return
return new ReturnMessage(returnValue, new object[0], 0, null, callMessage);
}
}
这是一个Generic的RealProxy。在Invoke方法中,两个Console.Write()代表PIAB注入的CallHandler的调用(对于CallHandler的操作可以是在调用Target Object之前调用,也可以在之后调用,我们不妨称这两种类型的操作为Pre-operation和Post-op
eration)。而对Target object的调用实际上是通过Reflection的方式调用的(callMessage.MethodBase.Invoke)。MyRealProxy通过传入Target Instance来创建。
我们在创建一个Factory Class,用于创建TransparentProxy。在PIAB中,这样一个Class由Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjection来充当。
public static class PolicyInjectionFactory
{
public static T Create<T>()
{
T instance = Activator.CreateInstance<T>();
MyRealProxy<T> realProxy = new MyRealProxy<T>(instance);
T transparentProxy = (T)realProxy.GetTransparentProxy();
return transparentProxy;
}
}
先通过Reflection的方式来创建Target Instance。通过该Instance创建我们在上面定义的Custom RealProxy。最后通过RealProxy返回一个TransparentProxy。
有了上面两个Class,我们的编写如下的Code来验证我们自己的Method Injection:
public class Foo:MarshalByRefObject
{
public voidDoSomeThing()
{
Console.WriteLine("The method of target object is invoked!");
}
}
public class Program
{
public static void Main()
{
Foo foo = PolicyInjectionFactory.Create<Foo>();
foo.DoSomeThing();
}
}
我们来看看程序运行后的结果:
可以看到正式我们需要的结果。从这个例子中我们可以看到,我们的Client code中包含的仅仅是Business Logic相关的code, 而另外一些业务无关的Code则是通过Custom RealProxy的形式注入到Invocation Stack中。这充分体现了Business Concern和Crosscutting Concern的分离。
三、Call Handler Pipeline
我想有了上面的理论和例子作基础,大家对于PIAB真正的实现不难理解了。我们先来介绍一下PI一个重要的概念:CallHandler Pipeline。我们知道Policy被运用Method方面,一个Policy有多个CallHandler。所有一个Method往往关联着一连串的CallHandler。这种现在很常见,就上我们第一部分给出的例子一样,一个简单的ProcessOrder方面需要执行许多额外的业务无关的逻辑:Authorization、Auditing、Transaction Enlist、Exception Handling和Logging。
在PIAB中,这些基于某个Method的所有CallHandler逐个串联在一起,组成一个CallHandler Pipeline。具体情况如下图:
我们从Class Diagram的角度来认识CallHandler Pipeline(在PIAB中通过Microsoft.Practices.EnterpriseLibrary.PolicyInjection.HandlerPipeline来表示)。
public delegate IMethodReturnInvokeHandlerDelegate(IMethodInvocation input, GetNextHandlerDelegate getNext);
public interface IMethodInvocation
{
// Methods
IMethodReturnCreateExceptionMethodReturn(Exception ex);
IMethodReturnCreateMethodReturn(object returnValue, params object[] outputs);
// Properties
IParameterCollectionArguments { get; }
IParameterCollectionInputs { get; }
IDictionaryInvocationContext { get; }
MethodBaseMethodBase { get; }
objectTarget { get; }
}
public delegate InvokeHandlerDelegate GetNextHandlerDelegate();
public interface ICallHandler
{
// Methods
IMethodReturnInvoke(IMethodInvocation input, GetNextHandlerDelegate getNext);
}
IMethodInvocation代表对一个方法的调用,它封装了一个Method Invocation的相关信息。比如:Parameter List、Invocation Context和Target Object.InvokeHandlerDelegate代表的是对CallHandler的调用,由于所有的CallHandler被串成一个CallHandler Pipeline,在调用了当前CallHandler之后,需要调用Pipeline中后一个CallHandler,对后一个CallHandler调用通过一个Delegate,GetNextHandlerDelegate来表示,而该Delegate的返回值是InvokeHandlerDelegate。结合上面的CallHandler Pipeline的链状结构,对这些应该不难理解。
我们最后来看看HandlerPipeline的定义,它的所有的CallHandler通过一个List来表示。
public class HandlerPipeline
{
// Fields
private List<ICallHandler> handlers;
// Methods
public HandlerPipeline();
public HandlerPipeline(IEnumerable<ICallHandler> handlers);
public IMethodReturnInvoke(IMethodInvocation input, InvokeHandlerDelegate target);
}
HandlerPipeline通过Invoke开始对其CallHandler PipeLine的调用:
public IMethodReturn Invoke(IMethodInvocation input, InvokeHandlerDelegate target)
{
if (this.handlers.Count == 0)
{
return target(input, null);
}
int handlerIndex = 0;
return this.handlers[0].Invoke(input, delegate {
handlerIndex++;
if (handlerIndex < this.handlersfont-size
分享到:
相关推荐
PIAB 与 WCF: 将 Policy Injection Application Block 与 WCF 服务集成 <br>• WF 操作指导: 使用 Windows Workflow Foundation 构建状态机 <br>• CLR 完全介绍: 动态语言和 Silverlight <br>• 基本技术:...
PIAB 真空发生器 piCLASSIC 产品简介pdf,PIAB 真空发生器 piCLASSIC 产品简介
第一步、基本入门 第二步、使用VS2010+Data Access模块建立多数据库项目 第三步、为项目加上异常处理(采用自定义扩展方式记录到数据库...扩展学习篇、库中的依赖关系注入(重构 Microsoft Enterprise Library)[转]
PIAB 真空吸盘 B8 选型册pdf,PIAB 真空吸盘 B8 选型册
PIAB 真空过滤器选型资料pdf,PIAB 真空过滤器选型资料
PIAB 模块化真空吸盘手册pdf,PIAB 模块化真空吸盘手册
PIAB 真空发生器 P6010 英文手册pdf,PIAB 真空发生器 P6010 英文手册
piab XLF大尺寸吸盘选型资料(中文)pdf,piab XLF大尺寸吸盘选型资料(中文)
PIAB L28型真空泵技术手册(英文)pdf,PIAB L28型真空泵技术手册(英文)
PIAB 真空吸盘 F110 选型册pdf,PIAB 真空吸盘 F110 选型册
PIAB 真空吸盘资料(英文)pdf,PIAB 真空吸盘资料(英文)
PIAB 真空发生器 P6010(英文) 产品简介pdf,PIAB 真空发生器 P6010(英文) 产品简介
可配置型吸盘,采用可循环利用的零件 。此外,不同的硬度特性也使吸盘同时 具有稳定和灵活的双重优势。...40kPa的工作条件下,可以实现最佳性 能和耐用性。可以更换唇边。 适用于水平调节和薄物体分离。
PIAB 真空吸盘选型手册pdf,PIAB 真空吸盘选型手册
PIAB 真空泵 CLASSIC 样本册pdf,PIAB 真空泵 CLASSIC 样本册
PIAB 真空泵L25 选型册pdf,PIAB 真空泵L25 选型册
PIAB 真空泵 L7 选型册pdf,PIAB 真空泵 L7 选型册
PIAB 真空泵6010 选型册pdf,PIAB 真空泵6010 选型册
瑞典PIAB真空吸盘产品说明pdf,瑞典PIAB真空吸盘产品说明
PIAB B8吸盘选型手册(英文)pdf,PIAB B8吸盘选型手册(英文)