优化.NET Remoting的传输的DataSet的序列化以提供性能

首先大家可以先看一下这篇文章:
Improving DataSet Serialization and Remoting Performance

这篇文章使用了一个DataSetSurrogate  代理类来包装DataSet,在序列化的时候,就可以被序列化成完全的Binary。关于这个DataSetSurrogate的用法,我这里就不多说了,大家可以看文章和其中包含的使用帮助。
但是,使用这个代理类有一个问题,就是需要写多余的代码来使用它,尤其对于已经编写好的代码,要每个往返数据的地方都加上它,肯定是不现实的。于是,我就想到了使用ChannelSink的方式,来统一处理往返中的DataSet。
基本原理是:在ClientSink中截获方法调用,检查传入参数是否是数据集或者其子类,如果是,就把这些参数包装成DataSetSurrogate,以CallContext来传递,且把原始的参数值设置为null;在ServerSink接受到这个被修改过的方法调用,把CallContext的参数DataSetSurrogate恢复成DataSet,同时也要把ReturnValue包装成DataSetSurrogate,以同样的方式传递给客户端;在客户端接受到方法的ReturnValue后,也要把ReturnValue恢复成DataSet。

相应的代码如下:
【ClientSink】
public class UAPClientSink:BaseChannelObjectWithProperties, IMessageSink,IClientChannelSink
 {
  //接收链中,在Formatter之上,在配置文件中,在Formatter上面
  private IClientChannelSink m_NextChnlSink;
  private IMessageSink m_NextMsgSink;
  //private IDictionary m_Prop;

  public UAPClientSink(object next)
  {
   m_NextChnlSink=next as IClientChannelSink;
   m_NextMsgSink=next as IMessageSink;
  }
 
  #region IMessageSink 成员

  public IMessage SyncProcessMessage(IMessage msg)
  {
   IMessage myReturnMsg;

   //用于设置是否要使用DataSetSurrogate来包装DataSet
   if (CallContext.GetData("NotSurrogate")!=null && (bool)CallContext.GetData("NotSurrogate"))
   {
    CallContext.SetData("NotSurrogate_Server",new LogicalCallContextData("true"));
    IMessage retmsg= m_NextMsgSink.SyncProcessMessage(msg);
    CallContext.SetData("NotSurrogate",null);
    return retmsg;
   }
   else
   {
    CallContext.SetData("NotSurrogate_Server",new LogicalCallContextData("false"));
   }

   LogicalCallContext lcc = (LogicalCallContext) msg.Properties["__CallContext"];

   if (msg is IMethodCallMessage) //处理调用
   {
    //包装DataSet为DataSetSurrogate
    Type[] ts=(Type[])msg.Properties["__MethodSignature"];
    Object[] vs=(Object[])msg.Properties["__Args"];
    if (ts!=null)
    {
     for (int i=0;i<=ts.Length-1;i++)
     {
      System.Diagnostics.Debug.WriteLine(vs[i].ToString());
      if ((vs[i] is System.Data.DataSet) && vs[i]!=null)
      {
       System.Data.DataSet ds=(System.Data.DataSet)vs[i];
       DataSetSurrogate dss=new DataSetSurrogate(ds);
       lcc.SetData("DataSetSurrogate_" + i.ToString(),dss);
       vs[i]=null;
      }
     }
    }
   }
   //执行下一个Sink的操作,直到执行到真实的Endpoint的方法,并得到访问值
   myReturnMsg=m_NextMsgSink.SyncProcessMessage(msg);

   if (myReturnMsg is IMethodReturnMessage)//处理返回
   {
    //恢复ReturnValue中DataSet
    System.Diagnostics.Debug.WriteLine("==========处理返回的DataSet=========");
    IMethodReturnMessage returnMsg=(IMethodReturnMessage)myReturnMsg;
    System.Data.DataSet ds=returnMsg.ReturnValue as System.Data.DataSet;
    if (ds!=null)
    {
     try
     {
      System.Diagnostics.Debug.WriteLine("处理前 ReturnValue中的DataSet的数据:" + ds.GetXml());
      
      //再获得returnMsg的__CallContext
      lcc = (LogicalCallContext)returnMsg.Properties["__CallContext"];
      DataSetSurrogate returnDSS=(DataSetSurrogate)lcc.GetData("DataSetSurrogate_Return");
      System.Diagnostics.Debug.WriteLine("=== 有DataSetSurrogate_Return ===");
      Object nds;

      if (returnMsg.ReturnValue.GetType()==typeof(System.Data.DataSet))
      {
       nds=returnDSS.ConvertToDataSet();
      }
      else
      {
       nds=Activator.CreateInstance(returnMsg.ReturnValue.GetType());
//ReadDataIntoDataSetEx是我扩展了DataSetSurrogate的方法,以支持类型数据集包含额外列的模式
       returnDSS.ReadDataIntoDataSetEx(nds as System.Data.DataSet);
      }
     
      Debug.WriteLine("处理后 ReturnValue中的DataSet的数据(行的数目):" +((System.Data.DataSet)nds).Tables[0].Rows.Count);
      
      MethodReturnWrapper mrw=new MethodReturnWrapper(myReturnMsg as IMethodReturnMessage);
      mrw.SetReturnValue(nds);
      myReturnMsg=mrw;
      lcc.SetData("DataSetSurrogate_Return",null);
     }
     catch(Exception ex)
     {
      Debug.WriteLine(ex.ToString());
     }
    }
   
    CallContext.SetData("NotSurrogate",null);
    return myReturnMsg;
   }
   else
   {
    Debug.WriteLine(myReturnMsg.GetType().FullName);
    CallContext.SetData("NotSurrogate",null);
    return myReturnMsg;
   }
  }

  public IMessageSink NextSink
  {
   get
   {
    return m_NextMsgSink;
   }
  }

  public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
  {
   return m_NextMsgSink.AsyncProcessMessage(msg,replySink);
  }

  #endregion
 
  #region IClientChannelSink 成员

  public void AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg, ITransportHeaders headers, Stream stream)
  {
   throw new Exception("在配置文件中的顺序不对");
  }

  public void ProcessMessage(IMessage msg, ITransportHeaders requestHeaders, Stream requestStream, out ITransportHeaders responseHeaders, out Stream responseStream)
  {
   throw new Exception("在配置文件中的顺序不对");
  }

  public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, object state, ITransportHeaders headers, Stream stream)
  {
   throw new Exception("在配置文件中的顺序不对");
  }

  public Stream GetRequestStream(IMessage msg, ITransportHeaders headers)
  {
   throw new Exception("在配置文件中的顺序不对");
  }

  public IClientChannelSink NextChannelSink
  {
   get
   {
    return m_NextChnlSink;
   }
  }

  #endregion


  public override IDictionary Properties
  {
   get
   {
    return base.Properties;
   }
  }
 }

【ServerSink】
public class UAPServerSink:BaseChannelObjectWithProperties,IServerChannelSink, IChannelSinkBase
 {
  //接收链中,在Formatter之上,在配置文件中,在Formatter下面
  IServerChannelSink m_Next;

  public UAPServerSink(IServerChannelSink nextSink)
  {
   m_Next=nextSink;
  }

  #region IChannelSinkBase 成员

  public override IDictionary Properties
  {
   get
   {
    // TODO:  添加 UAPServerSink.Properties getter 实现
    return base.Properties;
   }
  }

  #endregion
 
  #region IServerChannelSink 成员

  public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, object state, IMessage msg, ITransportHeaders headers)
  {
   return null;
  }

  public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
  {

   LogicalCallContext lcc = (LogicalCallContext) requestMsg.Properties["__CallContext"];
   if (lcc!=null)
   {
//不需要包装
    if (lcc.GetData("NotSurrogate_Server")!=null &&
     ((LogicalCallContextData)lcc.GetData("NotSurrogate_Server")).Data=="true")
    {
     sinkStack.Push(this,null);

     return m_Next.ProcessMessage(sinkStack,requestMsg,requestHeaders,requestStream,out responseMsg,out responseHeaders,out responseStream);

    }

    if (requestMsg!=null && requestMsg is IMethodCallMessage)
    {
     //恢复传入DataSet的参数值
     Type[] ts=(Type[])requestMsg.Properties["__MethodSignature"];
     Object[] vs=(Object[])requestMsg.Properties["__Args"];
     if (ts!=null)
     {
      for (int i=0;i<=ts.Length-1;i++)
      {
       if (ts[i]==typeof(System.Data.DataSet) || ts[i].BaseType==typeof(System.Data.DataSet))
       {
        Object v=lcc.GetData("DataSetSurrogate_" + i.ToString());
        DataSetSurrogate dss=(DataSetSurrogate)v;
        Object ds;
        if (ts[i]==typeof(System.Data.DataSet))
        {
         ds=dss.ConvertToDataSet();
        }
        else
        {
         ds=Activator.CreateInstance(ts[i]);
         dss.ReadDataIntoDataSetEx(ds as System.Data.DataSet);
        }
        vs[i]=ds;
        lcc.SetData("DataSetSurrogate_" + i.ToString(),null);
       }
      }
     }
    }
  
   
    sinkStack.Push(this,null);

    ServerProcessing spres=m_Next.ProcessMessage(sinkStack,requestMsg,requestHeaders,requestStream,out responseMsg,out responseHeaders,out responseStream);

    if (responseMsg is IMethodReturnMessage)
    {
     IMethodReturnMessage returnMsg=responseMsg as IMethodReturnMessage;
     if (returnMsg!=null)
     {
      //包装ReturnValue中DataSet为DataSetSurrogate
      lcc= (LogicalCallContext) returnMsg.Properties["__CallContext"];
      Object retval=returnMsg.ReturnValue;
      if (retval!=null && retval is System.Data.DataSet)
      {
       System.Data.DataSet ds=(System.Data.DataSet)retval;
       DataSetSurrogate dss=new DataSetSurrogate(ds);
       lcc.SetData("DataSetSurrogate_Return",dss);
       MethodReturnWrapper mrw=new MethodReturnWrapper(returnMsg);
       Object nds=Activator.CreateInstance(retval.GetType());
       mrw.SetReturnValue(nds);
       responseMsg=mrw;
      }
     }
    }

    return spres; 
   }
   else
   {
    sinkStack.Push(this,null);
    return m_Next.ProcessMessage(sinkStack,requestMsg,requestHeaders,requestStream,out responseMsg,out responseHeaders,out responseStream);
   }
  }

  public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, object state, IMessage msg, ITransportHeaders headers, Stream stream)
  {
   m_Next.AsyncProcessResponse(sinkStack,state,msg,headers,stream);
  }

  public IServerChannelSink NextChannelSink
  {
   get
   {
    return m_Next;
   }
  }

  #endregion
 }
【ReadDataIntoDataSetEx】
/// <summary>
  /// 以支持在Typed DataSet的动态列的添加(而不是异常),添加到末尾
  /// </summary>
  /// <param name="ds"></param>
  public void ReadDataIntoDataSetEx(System.Data.DataSet ds)
  {
   if (ds == null)
   {
    throw new ArgumentNullException("The dataset parameter cannot be null");
   }

   if (IsMissTableOrColumn(ds))
   {
    System.Data.DataSet nds=new System.Data.DataSet();
    ReadSchemaIntoDataSet(nds);
    ReadDataIntoDataSet(nds);
    ds.Merge(nds);
   }
   else
   {
    ReadDataIntoDataSet(ds); 
   }
  }

以上的代码并没有考虑到异步调用,也没有考虑方法调用的参数的ref out 属性。

posted @ 2004-07-02 21:46  朱永光  阅读(6096)  评论(4编辑  收藏  举报