优化.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 属性。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步