Enterprise Library Policy Injection Application Block 之二: PIAB设计和实现原理
2012-05-30 20:08
816 查看
[code] public class 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);
}
}[/code]
这是一个Generic的RealProxy。在Invoke方法中,两个Console.Write()代表PIAB注入的CallHandler的调用(对于CallHandler的操作可以是在调用Target Object之前调用,也可以在之后调用,我们不妨称这两种类型的操作为Pre-operation和Post-operation)。而对Target object的调用实际上是通过Reflection的方式调用的(callMessage.MethodBase.Invoke)。MyRealProxy通过传入Target Instance来创建。
我们在创建一个Factory Class,用于创建TransparentProxy。在PIAB中,这样一个Class由Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjection来充当。
[code] 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;
}
}[/code]先通过Reflection的方式来创建Target Instance。通过该Instance创建我们在上面定义的Custom RealProxy。最后通过RealProxy返回一个TransparentProxy。
有了上面两个Class,我们的编写如下的Code来验证我们自己的Method Injection:
[code] public class Foo : MarshalByRefObject
{
public void DoSomeThing()
{
Console.WriteLine("The method of target object is invoked!");
}
}
public class Program
{
public static void Main()
{
Foo foo = PolicyInjectionFactory.Create<Foo>();
foo.DoSomeThing();
}
}[/code]我们来看看程序运行后的结果:
可以看到正式我们需要的结果。从这个例子中我们可以看到,我们的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来表示)。
[code] public delegate IMethodReturnInvokeHandlerDelegate(IMethodInvocation input, GetNextHandlerDelegate getNext);
public interface IMethodInvocation
{
IMethodReturnCreateExceptionMethodReturn(Exception ex);
IMethodReturnCreateMethodReturn(object returnValue, params object[] outputs);
IParameterCollectionArguments{ get;}
IParameterCollectionInputs{ get;}
IDictionaryInvocationContext{ get;}
MethodBaseMethodBase{ get;}
objectTarget{ get;}
}
public delegate InvokeHandlerDelegate GetNextHandlerDelegate();
public interface ICallHandler
{
IMethodReturnInvoke(IMethodInvocation input, GetNextHandlerDelegate getNext);
}[/code]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来表示。
[code] public class HandlerPipeline
{
private List<ICallHandler> handlers;
public HandlerPipeline();
public HandlerPipeline(IEnumerable<ICallHandler> handlers);
public IMethodReturnInvoke(IMethodInvocation input, InvokeHandlerDelegate target);
}[/code]HandlerPipeline通过Invoke开始对其CallHandler PipeLine的调用:
[code] 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.handlers.Count)
{
ICallHandler local1 = this.handlers[handlerIndex];
return new InvokeHandlerDelegate(local1.Invoke);
}
return target;
});
}[/code]逻辑并不复杂,按照CallHandler List的先后顺序逐个调用,最后调用Target Object。方法中的第二个参数代表target代表对Target Object的调用。
四、PIAB中的Custom RealProxy:InterceptingRealProxy
我们一直再强调,PIAB实际上是通过自定义RealProxy来实现的。而且在第二节我们也实验了这种做法的可行性。我们现在就来看看PIAB的Custom RealProxy:Microsoft.Practices.EnterpriseLibrary.PolicyInjection.RemotingInterception.InterceptingRealProxy。[code] public class InterceptingRealProxy : RealProxy, IRemotingTypeInfo
{
private Dictionary<MethodBase, HandlerPipeline> memberHandlers;
private readonly object target;
private string typeName;
public InterceptingRealProxy(object target, Type classToProxy, PolicySet policies);
private void AddHandlersForInterface(Type targetType, Type itf);
private void AddHandlersForType(Type classToProxy, PolicySet policies);
public bool CanCastTo(Type fromType, object o);
public override IMessage Invoke(IMessage msg);
public object Target{ get;}
public string TypeName{ get; set;}
}[/code]
上面是它所有的成员定义,其中memberHandlers是一个以MethodBase为Key的Dictionary,表示应用在Target Object上面的所有的CallHandler Pipeline。通过这个很容易获得某个具体的方法调用的Pipeline。而target值得是真正的Target Object。我们着重来看看Invoke的定义:
[code] public override IMessage Invoke(IMessage msg)
{
HandlerPipeline pipeline;
IMethodCallMessage callMessage = (IMethodCallMessage) msg;
if (this.memberHandlers.ContainsKey(callMessage.MethodBase))
{
pipeline = this.memberHandlers[callMessage.MethodBase];
}
else
{
pipeline = new HandlerPipeline();
}
RemotingMethodInvocation invocation = new RemotingMethodInvocation(callMessage, this.target);
return ((RemotingMethodReturn) pipeline.Invoke(invocation, delegate (IMethodInvocation input, GetNextHandlerDelegate getNext){
try
{
object returnValue = callMessage.MethodBase.Invoke(this.target, invocation.Arguments);
return input.CreateMethodReturn(returnValue, invocation.Arguments);
}
catch (TargetInvocationException exception)
{
return input.CreateExceptionMethodReturn(exception.InnerException);
}
})).ToMethodReturnMessage();
}[/code]上面的一段代码不长,多看几遍应该不难理解。总的来说上面的Code现根据msg解析出MethodBase,再获取对应的CallHandler Pipeline,最后调用Pipeline。
五、Policy Injection Transparent Proxy Factory
介绍到这里,细心的读者可以意识到了,我们实际上还还有两件事情没有解决:CallHandler Pipeline的初始化和Transparent Proxy的创建。这两件事情都由PolicyInject.Create和方法来完成。需要指出的,应用PIAB的Class需要具有两个条件中至少一个:
[code]public static TInterface Create<TObject, TInterface>(params object[] args);
public static TObject Create<TObject>(params object[] args);[/code]其实还有两个重载,在这里就不需要多做介绍了。在具体的实现中,最终又是调用一个PolicyInjector对象来实现的。
[code] public static TObject Create<TObject>(params object[] args)
{
return DefaultPolicyInjector.Create<TObject>(args);
}
public static TInterface Create<TObject, TInterface>(params object[] args)
{
returnDefaultPolicyInjector.Create<TObject, TInterface>(args);
}[/code]
PolicyInjector是一个Abstract Class。其中Policies属性代表应用在该对象上的所有Policy(Policy = CallHandler + Matching Rule)
[code] [CustomFactory(typeof(PolicyInjectorCustomFactory))]
public abstract class PolicyInjector
{
private PolicySetpolicies;
public PolicyInjector();
public PolicyInjector(PolicySet policies);
public TInterface Create<TObject, TInterface>(params object[] args);
public TObject Create<TObject>(params object[] args);
public objectCreate(Type typeToCreate, params object[] args);
public object Create(Type typeToCreate, Type typeToReturn, params object[] args);
public PolicySetPolicies{ get; set;}
//Otehrs
}[/code]在PolicyInjection Class中定义了一个叫做DefaultPolicyInjector的属性,其定义如下:
[code] private static PolicyInjectorDefaultPolicyInjector
{
get
{
if (defaultPolicyInjector == null)
{
lock (singletonLock)
{
if (defaultPolicyInjector == null)
{
defaultPolicyInjector = GetInjectorFromConfig(ConfigurationSourceFactory.Create());
}
}
}
return defaultPolicyInjector;
}
}[/code]由于上面这个方法具体调用的Stack trace太深了,不可能很详细地指出其具体的实现。简单地说,该属性会返回一个默认的PolicyInjector:RemotingPolicyInjector,并对其进行初始化。初始化的内容就包括初始化所有的Policy(这就是我们在本节开始提出的CallHandler Pipeline的初始化)。由于我们可以有两种方式将Policy映射到目标成员:Attribute和Configuration。所有具体的做法是先通过分析Configuration找出所有通过configuration方式添加的Policy,然后通过Reflection找出所有通过使用Attribute方式添加的Policy。所以,如果你通过两种方式将相同的Policy应用到同一个对象上,该对象上将会有两个一样CallHandler,个人觉得这是一个值得商榷的做法,我不太赞成这样的行为。
我们接着看PolicyInjector接着是如何工作的:
[code] public TInterface Create<TObject, TInterface>(params object[] args)
{
return (TInterface) this.Create(typeof(TObject), typeof(TInterface), args);
}
public TObject Create<TObject>(params object[] args)
{
return (TObject) this.Create(typeof(TObject), typeof(TObject), args);
}[/code]上面连个方法由于调用到同一个Create Overload:
[code] publicobjectCreate(Type typeToCreate, Type typeToReturn, params object[] args)
{
PolicySet policiesFor = this.policies.GetPoliciesFor(typeToCreate);
this.EnsureTypeIsInterceptable(typeToReturn, policiesFor);
return this.DoCreate(typeToCreate, typeToReturn, policiesFor, args);
}[/code]首先找出对应Type的Policy,然后判断该类型是否支持Method Interception。RemotingPolicyInjector对该方法是这样实现的:要么继承MarshalByRefObject的Class,要么是个Interface。所以我们才有本节开始提出的两个条件。
[code] public override boolTypeSupportsInterception(Type t)
{
if (!typeof(MarshalByRefObject).IsAssignableFrom(t))
{
return t.IsInterface;
}
return true;
}[/code]上面连个方法由于调用到同一个Create Overload:
[code] public object Create(Type typeToCreate, Type typeToReturn, params object[] args)
{
PolicySet policiesFor = this.policies.GetPoliciesFor(typeToCreate);
this.EnsureTypeIsInterceptable(typeToReturn, policiesFor);
return this.DoCreate(typeToCreate, typeToReturn, policiesFor, args);
}[/code]首先找出对应Type的Policy,然后判断该类型是否支持Method Interception。RemotingPolicyInjector对该方法是这样实现的:要么继承MarshalByRefObject的Class,要么是个Interface。所以我们才有本节开始提出的两个条件。
[code] protected override object DoWrap(object instance, Type typeToReturn, PolicySet policiesForThisType)
{
if (PolicyInjector.PolicyRequiresInterception(policiesForThisType))
{
InterceptingRealProxy proxy = new InterceptingRealProxy(this.UnwrapTarget(instance), typeToReturn, policiesForThisType);
return proxy.GetTransparentProxy();
}
return instance;
}[/code]和我们给出的例子差不多,创建RealPoxy,根据该RealProxy返回Transparent Proxy。
五、Policy Injection Design
最后给出整个PIAB实现的所使用的Class,基本上所有的Class都在上面的内容中介绍过了:转自:http://www.cnblogs.com/artech/archive/2008/01/31/1059492.html
相关文章推荐
- [原创]Enterprise Library Policy Injection Application Block 之二: PIAB设计和实现原理
- Enterprise Library Policy Injection Application Block 之二: PIAB设计和实现原理
- WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成
- WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成
- [原创]WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成
- Enterprise Library Policy Injection Application Block 之三:PIAB的扩展—创建自定义CallHandler(提供Source Code下载)
- WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成
- [原创]Enterprise Library Policy Injection Application Block 之三:PIAB的扩展—创建自定义CallHandler(提供Source Code下载)
- [原创]Enterprise Library Policy Injection Application Block 之一: PIAB Overview
- WCF后续之旅(8):通过WCF Extension 实现与MS Enterprise Library Policy Injection Application Block 的集成
- MS Enterprise Library Policy Injection Application Block
- [原创]Enterprise Library Policy Injection Application Block 之四:如何控制CallHandler的执行顺序
- Enterprise Library Policy Injection Application Block 之四:如何控制CallHandler的执行顺序
- Enterprise Library Policy Injection Application Block(5.0) 函数调用链整理
- Enterprise Library Policy Injection Application Block(5.0) 函数调用链整理
- [原创]MS Enterprise Library Policy Injection Application Block 深入解析[总结篇]
- Enterprise Library Policy Injection Application Block 之一: PIAB Overview
- Microsoft Enterprise Library 5.0 系列教程(九) Policy Injection Application Block
- Microsoft Enterprise Library 5.0 系列(九) Policy Injection Application Block
- [原创]Enterprise Library深入解析与灵活应用(1):通过Unity Extension实现和Policy Injection Application Block的集成