代码如下:[AttributeUsage(AttributeTargets.Class)]
public class TestProxyAttribute:ProxyAttribute
{
    public override MarshalByRefObject CreateInstance(Type t)
    {
        MarshalByRefObject target = base.CreateInstance(t);
        RealProxy realProxy = new CalcRealProxy(target,t);
        return (MarshalByRefObject)realProxy.GetTransparentProxy();
    }
}[TestProxy]
public class Calc:ContextBoundObject
{
    public double add(double x,double y)
    {
        return (x + y);
    }
}public class CalcRealProxy:RealProxy
{
    private MarshalByRefObject target;    public CalcRealProxy(MarshalByRefObject target,Type targetType):base(targetType)
    {
        this.target = target;    }    public override IMessage Invoke(IMessage msg)
    {
        IMessage response = null;
        IMethodCallMessage call = (IMethodCallMessage)msg;
        IConstructionCallMessage ctor
            = call as IConstructionCallMessage;        if (ctor != null)  
        {
    
            RealProxy defaultProxy = RemotingServices.GetRealProxy(target);//问题开始
            this.InitializeServerObject(ctor);
            //defaultProxy.InitializeServerObject(ctor);
//问题结束            Console.WriteLine(target.GetType());
            MarshalByRefObject tp =
                (MarshalByRefObject)this.GetTransparentProxy();
            response = EnterpriseServicesHelper.CreateConstructionReturnMessage(ctor, tp);
        }
        else
        {
            Console.WriteLine("before call");
            response = RemotingServices.ExecuteMessage(target, call);
        }
        return response;
    }
}public class Test
{
    public static void Main()
    {
        Calc calc = new Calc();
        Console.WriteLine(calc.add(1.0,2.0));
    }
}
请注意中间CalcRealProxy的Invoke方法中的注释
如果使用defaultProxy.InitializeServerObject(ctor);则可以在calc.add(1.0,2.0)调用时得到预期输出的before call
而使用this.InitializeServerObject(ctor);则得不到预期的输出原因何在?谢谢

解决方案 »

  1.   

    this.InitializeServerObject(ctor);will cause an error likeUnhandled Exception: System.Runtime.Remoting.RemotingException: Trying to call proxy while constructor call is in progress.
    as you might know, you need defaultProxy.InitializeServerObject(ctor);to forward the call to the real object, response = EnterpriseServicesHelper.CreateConstructionReturnMessage(ctor, tp);just creats a reference to your transparent proxy which you can return to the caller
      

  2.   

    谢谢先不过error应该是我在下边Console.WriteLine(target.GetType());产生的,只用this.InitializeServerObject(ctor);没error产生的
      

  3.   

    我修改了你的代码,下面是使用this.InitializeServerObject的程序:
    ===============================================================using System;
    using System.Threading;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Contexts;
    using System.Runtime.Remoting.Proxies;
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Activation;
    using System.Runtime.Remoting.Services;namespace QQChen.CSharp.Remoting
    {
    [AttributeUsage(AttributeTargets.Class)]
    public class TestProxyAttribute:ProxyAttribute
    {
    public override MarshalByRefObject CreateInstance(Type t)
    {
    RealProxy realProxy = new CalcRealProxy(t);
    return (MarshalByRefObject)
                                   realProxy.GetTransparentProxy(); 
    }
    } [TestProxy]
    public class Calc : ContextBoundObject
    {
    public double add(double x,double y)
    {
    return (x + y);
    }
    } public class CalcRealProxy : RealProxy
    {
    public CalcRealProxy(Type targetType)
                             :base(targetType)
    {
    } public override IMessage Invoke(IMessage msg)
    {
    IMessage response = null;
    IMethodCallMessage call = (IMethodCallMessage)msg;
    IConstructionCallMessage ctor
    = call as IConstructionCallMessage; if (ctor != null)  
    {
    //问题开始
    this.InitializeServerObject(ctor);
                      SetStubData(this, 
                                            "Anything but the Context ID"); //<--- Clear the context information.
    //问题结束 MarshalByRefObject tp =
    (MarshalByRefObject)this.GetTransparentProxy();
    response = EnterpriseServicesHelper.CreateConstructionReturnMessage(ctor, tp);
    }
    else
    {
    Console.WriteLine("before call");
    response = RemotingServices.ExecuteMessage(GetUnwrappedServer(), call);
    }
    return response;
    }
    } public class Test
    {
    public static void Main()
    {
    Calc calc = new Calc();
    Console.WriteLine(calc.add(1.0,2.0));
    }
    }
    }
      

  4.   

    如果只是要intercept方法调用,不需要建立一个独立的Context,那么最好直接使用Factory模式来建立RealProxy,而不是使用ProxyAttribute,看这个例子:
    http://www.gotdotnet.com/team/douglasp/samples/RealProxy.html
      

  5.   

    the problem is that since you are calling through the "target" instance, you have to use the proxy based on that target,RealProxy defaultProxy = RemotingServices.GetRealProxy(target);to initialize the proxydefaultProxy.InitializeServerObject(ctor);when you use  MarshalByRefObject target = base.CreateInstance(t);you create an instance which uses the default proxy, RemoteProxy, and all your later calls go through this object
      

  6.   

    想了一下,还不是很清楚。这周末有空,再仔细研究一下,但如果我理解正确的话,你也许应该象qqchen79说的那么做
      

  7.   

    这个是Don Box的书里的例子,看来上次读的时候没完全理解,:-), to chain up the proxies and make it work, you need to call defaultProxy.InitializeServerObject(ctor);
    //this instance is uninitialized, actually a reference to the transparent proxy
    MarshalByRefObject target = base.CreateInstance(t);
      

  8.   

    多谢两位的回复
    恩,的确是Don Box的书里的例子,看的时候觉得
    MarshalByRefObject tp = (MarshalByRefObject)this.GetTransparentProxy();
    response = EnterpriseServicesHelper.CreateConstructionReturnMessage(ctor, tp);
    似乎与上面的调用无关,后来又在网上看了篇文章,于是将defaultProxy.InitializeServerObject(ctor)调用换成this.InitializeServerObject(ctor);就产生了无法拦截普通方法调用的问题。如qqchen79所说,如果仅仅是intercept方法调用的确没必要从ContextBoundObject里派生。现在我这么理解这个过程:
    在TestProxyAttribute的CreateInstance中new CalcRealProxy得到CalcRealProxy的实例后,stub为RealProxy._default,stubData为RealProxy._defaultStubData,_tp(也就是该实例GetTransparentProxy()的返回)为RemotingServices.CreateTransparentProxy()在stub,stubData创建的typeof(Calc)和当前CalcRealProxy的实例之间的透明代理,该实例的target为一个尚未实例化typeof(Calc)对象的与RemoteProxy对应的透明代理对象,调用GetProxiedType()将返回typeof(Calc).在TestProxyAttribute的CreateInstance返回之后,Calc对象的操作任何操作将通过直接CalcRealProxy来处理。接着在CalcRealProxy的Invoke处理在Calc对象的任何操作时,如果是实例化:
    1).若调用CalcRealProxy实例的InitializeServerObject(ctor)
    则首先调用RemotingServices.AllocateUninitializedObject()产生一个尚未实例化的Calc,
    然后将调用的结果传给CalcRealProxy实例的_serverobject,并调用CalcRealProxy实例的SetContextForDefaultStub();然后取得CalcRealProxy实例的透明代理,也就是开始new CalcRealProxy时已创建好的,typeof(Calc)和当前CalcRealProxy的实例之间的透明代理_tp,然后是RemotingServices.ExecuteMessage(_tp,ctorMsg);
    在InitializeServerObject(ctor)返回后,调用EnterpriseServicesHelper.CreateConstructionReturnMessage(ctor, (MarshalByRefObject)_tp)返回一个包含_tp这个透明代理的消息2).若调用RemotingServices.GetRealProxy(target).InitializeServerObject(ctor)
    RemotingServices.GetRealProxy(target)会返回RemoteProxy实例,然后RemoteProxy实例调用RemotingServices.AllocateUninitializedObject()产生一个尚未实例化的Calc,
    然后将调用的结果传给RemoteProxy实例的_serverobject,并调用RemoteProxy实例的SetContextForDefaultStub();然后取得RemoteProxy实例的透明代理,也就是开始base.CreateInstance(t)创建的target,然后就调用RemotingServices.ExecuteMessage(target,ctorMsg);
    在InitializeServerObject(ctor)返回后,调用EnterpriseServicesHelper.CreateConstructionReturnMessage(ctor, (MarshalByRefObject)_tp)返回一个包含_tp这个透明代理的消息
    可是分析完,还是不明白怎么拦截不到普通方法调用,just why?原因是什么?为什么qqchen79提供的方法就能解决拦截的普通方法调用。stub是起什么作用的?RealProxy的_serverobject字段又是什么意思?呵呵,我笨了点也烦了点还喜欢问到底,不知者无罪,还希望两位多多指点。谢谢
      

  9.   

    >> 截的普通方法调用。stub是起什么作用的?RealProxy的_serverobject字段又是什么意思?  .NET Remoting对ContextBoundObject的一个规则是:如果Caller和Callee在同一个Context内,那么它们的调用是直接方法调用,不需要Proxy或者MessagingStack的介入。而每个CBO的Context信息就存在Stub里面,SetContextForDefaultStub()把它设成了当前Thread的Context的一个InternalContextID。
      如果你的对象用this.InitializeServerObject初始化,那么你的RealProxy的Stub就被设成了当时的Context,这和Main方法调用使用的Context相同(你没有建立任何附加的Context),所以Remoting在比较了Context数据之后就跳过了Proxy直接调用真正的对象方法。
     base.CreateInstance返回的是一个RemotingProxy。如果你调用defaultProxy.InitializeServerObject,那么的这个RemotingProxy的Stub数据会被初始化,但是你的CalcRealProxy就不会。所以Context得比较会失败,方法调用仍然发生在Proxy之上。
      

  10.   

    >> RealProxy的_serverobject字段又是什么意思?
    这是RealProxy给包装起来的MarshalByRefObject预留的饮用。InitializeServerObject会把这个引用初始化。这也是在使用了ProxyAttribute之后唯一可以创建真实对象的方法。GetUnwrappedServer返回这个不带Proxy的真实对象。  其实对于同一个Appdomain中的Remoting,用上面的Don Box的方法效率不好。因为需要两个TransparentProxy,两个RealProxy。其实在调用this.InitializeServerObject之后把Stub重置为0就行了(0不是有效的InternalContextID)。
      

  11.   

    (-:
    看起来老大们也都在关心AOP
    怎么从来不说呢...MSDN里面有个很详细的例子
    http://msdn.microsoft.com/msdnmag/issues/02/03/aop/实际上就是被《MSDN开发精选》翻译的那篇
      

  12.   

    but if you check the System.Threading.Thread.CurrentContext, it looks like same across the boundaries. Also, if you have a ContextBoundObject, you always go through a proxy...
      

  13.   

    >> but if you check the System.Threading.Thread.CurrentContext, it looks like same across the boundaries.  Yes. It is the same Context across the application. but the question is how Remoting knows about it. A Remoting created object has its activation context infromation saved in Stub data, thus by comparing it with current context, remoting knows whether a switch of context is reqired. On the otherhand, If nothing is stored in stub, which is the case for the program above, remoting will always switch context.>> Also, if you have a ContextBoundObject, you always go through a proxy...
      
      It is true that what you get will always be a proxy. However, Remoting will check the necessity of using the proxy/message-stack or direct object call for each method invocation on the proxy. For example, if an object being ed as Transaction.ReqiredNew activates an object that is ed as Transaction.Reqired, they can live in the same context, thus function calls between them doesn't need to be interpreted.