在WCF中分页传输数据(Duplex方式)

我们在开发WCF应用的过程中,经常碰见数据量太大无法传输的问题,有时可以通过在数据库中分页查取解决,但有时又必须一次性查询出所有数据发送到Client端,我们可以修改WCF配置,但这不是个根本的解决办法。例如,我们需要在客户端生成一个节点太多的树。经过研究发现可以采用多种方式解决这个问题,本文论述的是基于简单三层架构采用WCF的Duplex方式分页传输大量数据。
我们的Service要实现如下功能,可以将某次大批量的查询结果自动分页返回到客户端,可以在返回过程报告进度。

首先看看数据的获得,为了增加通用性,我们假设某查询需要某个类型的实例作为参数,返回的是某个类型的IList。这样可以为实际执行查询的类定义一个接口如下:

using  System;
using  System.Collections.Generic;
using  System.Text;
namespace  BNCommonPlus.ServiceHelper
{
   
public interface IDALQueryDataListByPar<TResult,TPar>
   
{
        IList
<TResult> GetDataByPar(TPar par);
   }

}

这是个范型接口,TResult代表返回结果类型,TPar代表查询参数类型。
那么我们的DAL层可以i这么写:

using  System;
using  System.Collections.Generic;
using  System.Text;
// 其他要引用的名字空间.....
namespace  BNClinicService.DAL
{
     
//假设我们需要获得一个BNV_RegisterInfo列表发送到客户端,该查询接收的是一个String作为参数
     public class BNVClinicRegisterDAL : BNCommonPlus.ServiceHelper.IDALQueryDataListByPar<BNV_RegisterInfo, string>
    
{   
        
IDALQueryDataListByPar 成员

}

现在我们有的DAL,在BNVClinicRegisterDAL中GetDataByPar方法会得到大量数据需要分页发送到客户端。
显然,需要一个类自动将得到的数据分页,我们把它放在BLL层, 代码如下:

using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.Reflection;
using  System.ServiceModel;
using  System.ServiceProcess;

namespace  BNCommonPlus.ServiceHelper
{
    
/// <summary>
    
/// 分页发送数据到客户端,对应BLL层
    
/// </summary>
    
/// <typeparam name="TResult">要发送的数据类型</typeparam>
    
/// <typeparam name="TPar">产生数据所需要的参数类型</typeparam>

    public class DuplexDataTransferServiceBLLHelper<TResult,TPar>
    
{
        
/// <summary>
        
/// 客户端标志
        
/// </summary>

        private Guid _Guid;
        
/// <summary>
        
/// 要发送的数据
        
/// </summary>

        private IList<TResult> ListToSendOut = new List<TResult>();   
        
/// <summary>
        
/// 总行数
        
/// </summary>

        private int RowCount = -1;
        
/// <summary>
        
/// 总页数
        
/// </summary>

        private int PageCount = -1;
        
/// <summary>
        
/// 每页发送数据量
        
/// </summary>

        private int PerPage = 30;
        
/// <summary>
        
/// 处理数据的DAL
        
/// </summary>

        private IDALQueryDataListByPar<TResult, TPar> DALQueryDataListByPar = null;
        
private TPar QueryPar = default(TPar);
        
public DuplexDataTransferServiceBLLHelper(TPar par, Guid guid, IDALQueryDataListByPar<TResult, TPar> IDAL, int _PerPage)
        
{
            QueryPar 
= par;
            _Guid 
= guid;
            DALQueryDataListByPar 
= IDAL;
            PerPage 
= _PerPage;
        }


        
public DuplexDataTransferServiceBLLHelper(TPar par,Guid guid,IDALQueryDataListByPar<TResult,TPar> IDAL)
        
{           
            QueryPar 
= par;
            _Guid 
= guid;
            DALQueryDataListByPar 
= IDAL;
        }


        
public DuplexDataTransferServiceBLLHelper(TPar par, Guid guid)
        
{
            QueryPar 
= par;
            _Guid 
= guid;            
        }


        
protected void SetIDAL(IDALQueryDataListByPar<TResult, TPar> IDAL)
        
{
            DALQueryDataListByPar 
= IDAL;
        }


        
/// <summary>
        
/// 计算页数
        
/// </summary>

        private void ComputePageCount()
        
{
            PageCount 
= RowCount / PerPage;
            
if (RowCount % PerPage != 0)
            
{
                PageCount 
+= 1;
            }


        }


        
异步相关


        
/// <summary>
        
/// 查询并发送
        
/// </summary>

        private void DoQuery()
        
{
            
try
            
{
                ListToSendOut 
= DALQueryDataListByPar.GetDataByPar(QueryPar);
                RowCount 
= ListToSendOut.Count;
                
//送出总行数到客户端
                FireEventSendListCountOut();
                
//计算页数
                ComputePageCount();
                
for (int i = 0; i < PageCount; i++)
                
{
                    List
<TResult> list = new List<TResult>();
                    
for (int t = i * PerPage; t < PerPage * (i + 1&& t < RowCount; t++)
                    
{
                        list.Add(ListToSendOut[t]);
                    }

                    
//送出一页数据 
                    FireEventSendListAPageOut(list,i);
                }

                
//发送完成
                FireEventSendAllListComplete();
            }

            
catch(Exception ex)
            
{
                BNServiceEvents.FireEventServiceMethodExecError(ex);
            }

        }

        
/// <summary>
        
/// 送出查询结果列表行数
        
/// </summary>
        
/// <param name="ListCount">查询结果列表行数</param>
        
/// <param name="_guid"></param>

        public delegate void HandlerSendListCountOut(int ListCount, Guid _guid);
        
/// <summary>
        
/// 送出查询结果列表行数
        
/// </summary>

        public event HandlerSendListCountOut EventSendListCountOut;
        
private void FireEventSendListCountOut()
        
{
            HandlerSendListCountOut handler 
= EventSendListCountOut;
            
if (handler != null)
            
{
                handler(ListToSendOut.Count, _Guid);
            }

        }


        
/// <summary>
        
/// 送出查询一页结果列表
        
/// </summary>
        
/// <param name="_guid"></param>
        
/// <param name="list"></param>

        public delegate void HandlerSendListAPageOut(Guid _guid, List<TResult> list,int PageNo);
        
/// <summary>
        
/// 送出查询一页结果列表
        
/// </summary>

        public event HandlerSendListAPageOut EventSendListAPageOut;
        
private void FireEventSendListAPageOut(List<TResult> list,int PageNo)
        
{
            HandlerSendListAPageOut handler 
= EventSendListAPageOut;
            
if (handler != null)
            
{
                handler(_Guid, list, PageNo);
            }

        }


        
/// <summary>
        
/// 所有查询结果发送完毕
        
/// </summary>
        
/// <param name="_guid"></param>

        public delegate void HandlerSendAllListComplete(Guid _guid);
        
/// <summary>
        
/// 所有查询结果发送完毕
        
/// </summary>

        public event HandlerSendAllListComplete EventSendAllListComplete;
        
private void FireEventSendAllListComplete()
        
{
            HandlerSendAllListComplete handler 
= EventSendAllListComplete;
            
if (handler != null)
            
{
                handler(_Guid);
            }

        }

    }

}

这个类也是范型类,TResult代表返回结果类型,TPar代表查询参数类型。它默认按照每页30行分页数据。它包含三个事件
EventSendListCountOut 对应通知客户端一共有多少行数据需要发送。
EventSendListAPageOut 对应向客户端发送一页数据。
EventSendAllListComplete 对应通知客户端所有数据发送完成。
这个类支持异步查询发送。
在实际应用时我们可以这样用这个类:

using  System;
using  System.Collections.Generic;
using  System.Text;
using  BNCommonPlus.ServiceHelper;
using  BNClinicService.Model;
using  BNClinicService.DAL;

namespace  BNClinicService.BLL
{
    
/// <summary>
    
/// 获得Clinic挂号客户列表,Duplex分页返回数据
    
/// </summary>

    public class GetBNVClientRegisterListBLL : DuplexDataTransferServiceBLLHelper<BNV_RegisterInfo,string>
    
{
        
public GetBNVClientRegisterListBLL(string par, Guid _guid)
            : 
base(par, _guid)
        
{
            
base.SetIDAL(new BNVClinicRegisterDAL() as IDALQueryDataListByPar<BNV_RegisterInfo,string>);
        }

    }

}


那么Service的Callback接口可以定义如下:
using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.ServiceModel;
namespace  BNCommonPlus.ServiceHelper
{
    
public interface IBusinessDuplexServiceLibCallback<TResult>
    
{
        [OperationContract(IsOneWay 
= true)]
        
void SendQueryInfoByParRowCount(int RowCount);
        [OperationContract(IsOneWay 
= true)]
        
void SendQueryInfoByParAPage(List<TResult> list, int PageNo);
        [OperationContract(IsOneWay 
= true)]
        
void SendQueryInfoByParComplete();
    }

}

这是个范型接口,TResult代表返回结果类型。
void SendQueryInfoByParRowCount(int RowCount);用于在查询完成后向客户端通报数据行数。
void SendQueryInfoByParAPage(List<TResult> list, int PageNo);用于在向客户端分页发送数据及页号。
void SendQueryInfoByParComplete();用于在通知客户端所有数据发送完成。
现在我们需要一个通用的Service来发送数据,代码如下:

using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.Reflection;
using  System.ServiceModel;
using  System.ServiceProcess;
namespace  BNCommonPlus.ServiceHelper
{
    
public class DuplexDataTransferServiceLIBHelper<TResult,TPar>
    
{
        
/// <summary>
        
/// 客户端回调字典
        
/// </summary>

        protected Dictionary<Guid, IBusinessDuplexServiceLibCallback<TResult>> DICClients = new Dictionary<Guid, IBusinessDuplexServiceLibCallback<TResult>>();
        
/// <summary>
        
/// Server端查询BLL字典
        
/// </summary>

        protected Dictionary<Guid, DuplexDataTransferServiceBLLHelper<TResult, TPar>> DICBLLs = new Dictionary<Guid, DuplexDataTransferServiceBLLHelper<TResult, TPar>>();

        
public void BeginDoSomeByPar( Guid _guid, DuplexDataTransferServiceBLLHelper<TResult, TPar> _DuplexDataTransferServiceBLLHelper)
        
{
            
lock (DICClients)
            
{                
                
try
                
{
                    
//Client 加入Dic
                    DICClients.Add(_guid, Callback);
                    
//查询类加入DIC
                    DICBLLs.Add(_guid, _DuplexDataTransferServiceBLLHelper);
                    
//查询行数
                    _DuplexDataTransferServiceBLLHelper.EventSendListCountOut += new DuplexDataTransferServiceBLLHelper<TResult, TPar>.HandlerSendListCountOut(_DuplexDataTransferServiceBLLHelper_EventSendListCountOut);
                   
                    
////发送一页数据
                    _DuplexDataTransferServiceBLLHelper.EventSendListAPageOut += new DuplexDataTransferServiceBLLHelper<TResult, TPar>.HandlerSendListAPageOut(_DuplexDataTransferServiceBLLHelper_EventSendListAPageOut);
                    
////所有数据发送完成
                    _DuplexDataTransferServiceBLLHelper.EventSendAllListComplete += new DuplexDataTransferServiceBLLHelper<TResult, TPar>.HandlerSendAllListComplete(_DuplexDataTransferServiceBLLHelper_EventSendAllListComplete);
                    
//开始查询
                    _DuplexDataTransferServiceBLLHelper.BeginDoQuery();
                }

                
catch (Exception ex)
                
{
                    BNServiceEvents.FireEventServiceMethodExecError(ex);
                }

            }

        }

        
/// <summary>
        
/// 完成某次查询结果的发送
        
/// </summary>
        
/// <param name="_guid"></param>

        void _DuplexDataTransferServiceBLLHelper_EventSendAllListComplete(Guid _guid)
        
{
            
lock (DICClients)
            
{

                IBusinessDuplexServiceLibCallback
<TResult> _Callback;
                
if (DICClients.TryGetValue(_guid, out _Callback))
                
{
                    
try
                    
{
                        
//通知客户端数据已经发送完成
                        _Callback.SendQueryInfoByParComplete();
                        
//查询完成,结束相关类
                        DICClients.Remove(_guid);
                        DICBLLs.Remove(_guid);
                        DuplexDataTransferServiceEvents.FireEventServiceMethodCompleteOp(_guid);
                    }

                    
catch (Exception ex)
                    
{                        
                        
try
                        
{
                            DICClients.Remove(_guid);
                        }

                        
catch
                        
{ }
                        
try
                        
{
                            DICBLLs.Remove(_guid);
                        }

                        
catch
                        
{ }
                        
//BNServiceEvents.FireEventServiceMethodExecError(ex);//发生错误记录日志等操作
                    }

                }

            }

        }

        
/// <summary>
        
/// 发送一页数据到客户端
        
/// </summary>
        
/// <param name="_guid"></param>
        
/// <param name="list"></param>

        void _DuplexDataTransferServiceBLLHelper_EventSendListAPageOut(Guid _guid, List<TResult> list,int PageNo)
        
{
            
lock (DICClients)
            
{
                IBusinessDuplexServiceLibCallback
<TResult> _Callback;
                
if (DICClients.TryGetValue(_guid, out _Callback))
                
{
                    
try
                    
{
                        _Callback.SendQueryInfoByParAPage(list, PageNo);
                        DuplexDataTransferServiceEvents.FireEventServiceSendData(PageNo, list.Count, _guid);
                    }

                    
catch (Exception ex)
                    
{
                        
                        
try
                        
{
                            DICClients.Remove(_guid);
                        }

                        
catch
                        
{ }
                        
try
                        
{
                            DICBLLs.Remove(_guid);
                        }

                        
catch
                        
{ }
                        
//BNServiceEvents.FireEventServiceMethodExecError(ex);//发生错误记录日志等操作
                    }

                }

            }

        }

        
/// <summary>
        
/// 发送数据行数到客户端
        
/// </summary>
        
/// <param name="ListCount"></param>
        
/// <param name="_guid"></param>

        void _DuplexDataTransferServiceBLLHelper_EventSendListCountOut(int ListCount, Guid _guid)
        
{
            
lock (DICClients)
            
{

                IBusinessDuplexServiceLibCallback
<TResult> _Callback;
                
if (DICClients.TryGetValue(_guid, out _Callback))
                
{
                    
try
                    
{
                        _Callback.SendQueryInfoByParRowCount(ListCount);
                        DuplexDataTransferServiceEvents.FireEventServiceSendDataCount(ListCount, _guid);

                    }

                    
catch (Exception ex)
                    
{
                       
                        
try
                        
{
                            DICClients.Remove(_guid);
                        }

                        
catch
                        
{ }
                        
try
                        
{
                            DICBLLs.Remove(_guid);
                        }

                        
catch
                        
{ }
                        
//BNServiceEvents.FireEventServiceMethodExecError(ex);//发生错误记录日志等操作
                    }

                }

            }

        }




        IBusinessDuplexServiceLibCallback
<TResult> Callback
        
{
            
get
            
{
                
return OperationContext.Current.GetCallbackChannel<IBusinessDuplexServiceLibCallback<TResult>>();
            }

        }

    }

}

我们可以使用这个Service了,在Server端我们这样写:

using  System;
using  System.Collections.Generic;
using  System.Text;
using  BNCommonPlus.ServiceHelper;
using  BNClinicService.Model;
using  BNClinicService.BLL;

namespace  BNClinicService.ServiceLib
{
    
public class BNClinicDataTransferServiceDuplexLib : BNClinicService.IServiceLib.IBNClinicDataTransferServiceDuplexLib, IBNDuplexDataTransferService
    
{        
        
IBNClinicServiceDuplexLib 成员
    }

}

这里需要说明的是IBNDuplexDataTransferService是个空接口,用来标识这个DuplexService,这个接口的目的将在以后描述。这个Service对应的Contract如下:

using  System;
using  System.Collections.Generic;
using  System.Text;
using  BNCommonPlus.ServiceHelper;
using  BNClinicService.Model;
using  System.ServiceModel;

namespace  BNClinicService.IServiceLib
{
    [ServiceContract(Namespace 
= "http://BNClinicService.IBNClinicDataTransferServiceDuplexLib", SessionMode = SessionMode.Required,
                  CallbackContract 
= typeof(IBusinessDuplexServiceLibCallback<BNV_RegisterInfo>))]
    
public interface IBNClinicDataTransferServiceDuplexLib
    
{
        [OperationContract(IsOneWay 
= true)]
        
void BeginDoQueryClinicRegisterByPar(string par, Guid _guid, BNCommonPlus.BNCommonModel.UserIdentity UI);
    }

}

定义完成后再配置一下就可以使用这个Service了,新的问题来了,如果有很多类型的数据要传,我们需要为每一种数据类型,每一种查询方法建立不同的Service并配置它们,那样太痛苦。幸运的是目前找到了多种解决方法,具体解决方案将在以后描述。现在,我们看看用"SvcUtil.exe"生成的Client是怎样的

using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.ServiceModel;
using  System.ServiceProcess;
using  System.ServiceModel.Dispatcher;
using  System.ServiceModel.Description;
using  System.ServiceModel.Channels;

namespace  BNClinicClient.BLL.ServiceClients
{
    [System.CodeDom.Compiler.GeneratedCodeAttribute(
"System.ServiceModel""3.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(Namespace 
= "http://BNClinicService.IBNClinicDataTransferServiceDuplexLib", ConfigurationName = "IBNClinicDataTransferServiceDuplexLib", CallbackContract = typeof(IBNClinicDataTransferServiceDuplexLibCallback), SessionMode = System.ServiceModel.SessionMode.Required)]
    
public interface IBNClinicDataTransferServiceDuplexLib
    
{

        [System.ServiceModel.OperationContractAttribute(IsOneWay 
= true, Action = "http://BNClinicService.IBNClinicDataTransferServiceDuplexLib/IBNClinicDataTransfe" +
            
"rServiceDuplexLib/BeginDoQueryClinicRegisterByPar")]
        
void BeginDoQueryClinicRegisterByPar(string par, System.Guid _guid, BNCommonPlus.BNCommonModel.UserIdentity _UserIdentity);
    }


    [System.CodeDom.Compiler.GeneratedCodeAttribute(
"System.ServiceModel""3.0.0.0")]
    
public interface IBNClinicDataTransferServiceDuplexLibCallback
    
{

        [System.ServiceModel.OperationContractAttribute(IsOneWay 
= true, Action = "http://BNClinicService.IBNClinicDataTransferServiceDuplexLib/IBNClinicDataTransfe" +
            
"rServiceDuplexLib/SendQueryInfoByParRowCount")]
        
void SendQueryInfoByParRowCount(int RowCount);

        [System.ServiceModel.OperationContractAttribute(IsOneWay 
= true, Action = "http://BNClinicService.IBNClinicDataTransferServiceDuplexLib/IBNClinicDataTransfe" +
            
"rServiceDuplexLib/SendQueryInfoByParAPage")]
        
void SendQueryInfoByParAPage(List<BNClinicService.Model.BNV_RegisterInfo> list, int PageNo);

        [System.ServiceModel.OperationContractAttribute(IsOneWay 
= true, Action = "http://BNClinicService.IBNClinicDataTransferServiceDuplexLib/IBNClinicDataTransfe" +
            
"rServiceDuplexLib/SendQueryInfoByParComplete")]
        
void SendQueryInfoByParComplete();
    }


    [System.CodeDom.Compiler.GeneratedCodeAttribute(
"System.ServiceModel""3.0.0.0")]
    
public interface IBNClinicDataTransferServiceDuplexLibChannel : IBNClinicDataTransferServiceDuplexLib, System.ServiceModel.IClientChannel
    
{
    }


    
//[System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel""3.0.0.0")]
    
public partial class BNClinicDataTransferServiceDuplexLibClient : System.ServiceModel.DuplexClientBase<IBNClinicDataTransferServiceDuplexLib>, IBNClinicDataTransferServiceDuplexLib
    
{

        
public BNClinicDataTransferServiceDuplexLibClient(System.ServiceModel.InstanceContext callbackInstance)
            :
                
base(callbackInstance)
        
{
        }


        
public BNClinicDataTransferServiceDuplexLibClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName)
            :
                
base(callbackInstance, endpointConfigurationName)
        
{
        }


        
public BNClinicDataTransferServiceDuplexLibClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, string remoteAddress)
            :
                
base(callbackInstance, endpointConfigurationName, remoteAddress)
        
{
        }


        
public BNClinicDataTransferServiceDuplexLibClient(System.ServiceModel.InstanceContext callbackInstance, string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress)
            :
                
base(callbackInstance, endpointConfigurationName, remoteAddress)
        
{
        }


        
public BNClinicDataTransferServiceDuplexLibClient(System.ServiceModel.InstanceContext callbackInstance, System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress)
            :
                
base(callbackInstance, binding, remoteAddress)
        
{
        }


        
public void BeginDoQueryClinicRegisterByPar(string par, System.Guid _guid, BNCommonPlus.BNCommonModel.UserIdentity _UserIdentity)
        
{
            
base.Channel.BeginDoQueryClinicRegisterByPar(par, _guid, _UserIdentity);
        }

    }


}

注意:Callback接口发生了改变。
现在我们为客户端定义一个帮助类,代码如下:

using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.Reflection;
using  System.ServiceModel;
using  System.ServiceProcess;
using  System.Threading;

namespace  BNCommonPlus.ClientHelper
{
    
/// <summary>
    
/// 
    
/// </summary>
    
/// <typeparam name="TResult"></typeparam>
    
/// <typeparam name="TPar"></typeparam>

    public abstract class DuplexDataTransferClientBLLHelper<TResult, TPar>
    
{   
        
/// <summary>
        
/// 客户端标志
        
/// </summary>

        public Guid _Guid = Guid.NewGuid();
        
/// <summary>
        
/// 要发送的数据
        
/// </summary>

        public List<TResult> ListToSendOut = new List<TResult>();
       
        
/// <summary>
        
/// 每页发送数据量
        
/// </summary>

        public int PerPage = 30;

        
protected void ClearList()
        
{
            ListToSendOut 
= new List<TResult>();
        }


        
public DuplexDataTransferClientBLLHelper(int _PerPage)
        
{
            PerPage 
= _PerPage;
        }



        
public DuplexDataTransferClientBLLHelper(int _PerPage, Guid _guid)
            :
this(_PerPage)
        
{
            _Guid 
= _guid;
        }


        
public DuplexDataTransferClientBLLHelper(Guid _guid)            
        
{
            _Guid 
= _guid;
        }


        
public DuplexDataTransferClientBLLHelper()
        
{
            
        }


        
/// <summary>
        
/// 客户端开始查询操作
        
/// </summary>

        public abstract void StartDoQuery(TPar par);

        
/// <summary>
        
/// 客户端关闭Client
        
/// </summary>

        public abstract void CloseClient();

        
/// <summary>
        
/// 服务器送回结果行数
        
/// </summary>
        
/// <param name="RowCount"></param>

        protected void ReceiveQueryByParRowCount(int RowCount)
        
{
            FireEventReceiveQueryByParRowCount(RowCount);
        }


        
/// <summary>
        
/// 服务器送回一页数据
        
/// </summary>
        
/// <param name="list">数据</param>
        
/// <param name="pageno">页号</param>

        protected void ReceiveQueryByParAPage(List<TResult> list,int pageno)
        
{
            ListToSendOut.AddRange(list);
            FireEventReceiveQueryByParAPage(list, pageno);
        }


        
/// <summary>
        
/// 数据发送完毕
        
/// </summary>

        protected void ReceiveQueryByParComplete()
        
{
            FireReceiveQueryByParCompleteWithData();
            FireEventReceiveQueryByParComplete();
            CloseClient();            
        }


        
/// <summary>
        
/// 服务器传回查询结果行数
        
/// </summary>
        
/// <param name="RowCount"></param>

        public delegate void HandleReceiveQueryByParRowCount(int RowCount);
        
/// <summary>
        
/// 服务器传回查询结果行数事件
        
/// </summary>

        public event HandleReceiveQueryByParRowCount EventReceiveQueryByParRowCount;
        
/// <summary>
        
/// 触发服务器传回查询结果行数事件
        
/// </summary>
        
/// <param name="RowCount"></param>

        private void FireEventReceiveQueryByParRowCount(int RowCount)
        
{
            HandleReceiveQueryByParRowCount handler 
= EventReceiveQueryByParRowCount;
            
if (handler != null)
            
{
                handler(RowCount);
            }

        }

        
/// <summary>
        
/// 服务器传回一页数据
        
/// </summary>
        
/// <param name="list"></param>

        public delegate void HandleReceiveQueryByParAPage(List<TResult> list,int PageNo);
        
/// <summary>
        
/// 服务器传回一页数据事件
        
/// </summary>

        public event HandleReceiveQueryByParAPage EventReceiveQueryByParAPage;
        
/// <summary>
        
/// 触发服务器传回一页数据事件
        
/// </summary>
        
/// <param name="list"></param>
        
/// <param name="PageNo"></param>

        private void FireEventReceiveQueryByParAPage(List<TResult> list,int PageNo)
        
{
            HandleReceiveQueryByParAPage handler 
= EventReceiveQueryByParAPage;
            
if (handler != null)
            
{
                handler(list,PageNo);
            }

        }

        
/// <summary>
        
/// 数据发送完成,携带数据
        
/// </summary>

        public delegate void HandleReceiveQueryByParCompleteWithData(List<TResult> list);
        
/// <summary>
        
/// 数据发送完成,携带数据 事件
        
/// </summary>

        public event HandleReceiveQueryByParCompleteWithData EventReceiveQueryByParCompleteWithData;
        
/// <summary>
        
/// 触发事件 数据发送完成,携带数据
        
/// </summary>

        private void FireReceiveQueryByParCompleteWithData()
        
{
            HandleReceiveQueryByParCompleteWithData handler 
= EventReceiveQueryByParCompleteWithData;
            
if (handler != null)
            
{
                handler(ListToSendOut);
            }

        }
        
        
/// <summary>
        
/// 数据发送完成
        
/// </summary>

        public delegate void HandleReceiveQueryByParComplete();
        
/// <summary>
        
///  数据发送完成,通知客户类,此事件不携带数据
        
/// </summary>

        public event HandleReceiveQueryByParComplete EventReceiveQueryByParComplete;
        
private void FireEventReceiveQueryByParComplete()
        
{
            HandleReceiveQueryByParComplete handler 
= EventReceiveQueryByParComplete;
            
if (handler != null)
            
{
                handler();
            }

        }

    }
    
}

在客户端,我们这样使用这个类:

using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.ServiceModel;
using  BNClinicService.Model;
using  BNCommonPlus.ClientHelper;
using  BNClinicClient.BLL.ServiceClients;

namespace  BNClinicClient.BLL.ClinicRegister
{
    
public class GetClinicRegisterInfo : DuplexDataTransferClientBLLHelper<BNV_RegisterInfo, string >, IBNClinicDataTransferServiceDuplexLibCallback
    
{
        
        
private InstanceContext _InstanceContext = null;
        
private BNClinicDataTransferServiceDuplexLibClient client = null;

        
public override void StartDoQuery(string par)
        
{
            CloseClient();
            ListToSendOut 
= new List<BNV_RegisterInfo>();
            _InstanceContext 
= new InstanceContext(this);
            client 
= new BNClinicDataTransferServiceDuplexLibClient(_InstanceContext, "NetTcpBinding_IBNClinicDataTransferServiceDuplexLib");
            client.BeginDoQueryClinicRegisterByPar(par,_Guid,BNClinicClient.BLL.Common.ClientCache._UserIdentity);
        }


        
public override void CloseClient()
        
{
            
if (client != null)
            
{                
                client.Close();                
                _InstanceContext 
= null;
            }

        }




        
IBNClinicDataTransferServiceDuplexLibCallback 成员
    }

}

最后在UI层,可以这样写:

using  System;
using  System.Collections.Generic;
using  System.ComponentModel;
using  System.Data;
using  System.Drawing;
using  System.Text;
using  System.Windows.Forms;
using  BNClinicClient.BLL.ClinicRegister;
using  BNClinicService.Model;
using  BNCommonPlus.Controls;

namespace  BNClinicClient.FormC.ClinicRegister
{
    
public partial class FormClinicRegister : Form
    
{
        
public FormClinicRegister()
        
{
            InitializeComponent();
        }


        
private void FormClinicRegister_Load(object sender, EventArgs e)
        
{
            GetClinicRegisterInfo _GetClinicRegisterInfo 
= new GetClinicRegisterInfo();
            _GetClinicRegisterInfo.EventReceiveQueryByParCompleteWithData 
+= new BNCommonPlus.ClientHelper.DuplexDataTransferClientBLLHelper<BNV_RegisterInfo, string>.HandleReceiveQueryByParCompleteWithData(_GetClinicRegisterInfo_EventReceiveQueryByParCompleteWithData);
            _GetClinicRegisterInfo.StartDoQuery(
"123456");

        }


        
void _GetClinicRegisterInfo_EventReceiveQueryByParCompleteWithData(List<BNV_RegisterInfo> list)
        
{
            
foreach (BNV_RegisterInfo model in list)
            

                treeView1.Nodes.Add(
new MyTreeNode<BNV_RegisterInfo>(model,model.ClientID,true));
            }

        }

    }

}

本文描述了通过一个通用的DuplexService分页传输数据到客户端,还有很多其他解决方案将在以后描述。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值