WebService 应用(3) - 提高WebService的性能

一、一个简单的Webservice示例

  a. 在数据库中创建一个Database,名为WebServiceDemo,然后创建一个表student,插入相关测试数据。(我使用了4万多条数据,方便下面的比较测试)。

  b. 在VS中创建一个Web Service 应用程序,并调加一个 WebMethod:GetDataSet,该方法返回用"Select * From Student"查询得到的DataSet。

GetDataSet
[WebMethod(Description = "直接返回DataSet对象")]
public DataSet GetDataSet()
{
    
string sqlCmd = "Select * From Student";
    SqlConnection sqlConn 
= new SqlConnection(szConn);
    sqlConn.Open();
    SqlDataAdapter dataAdapter 
= new SqlDataAdapter(sqlCmd, sqlConn);
    DataSet sqlDS 
= new DataSet("Demo");
    dataAdapter.Fill(sqlDS);
    sqlConn.Close();
    
return sqlDS;
}


二、Webservice部署到本地

  部署过程中,需要注意两个问题:

  1. 需要为数据库添加‘机器名\ASPNET’登录名并给予权限, 不然在客户端调用时会出现异常: System.Data.SqlClient.SqlException: 用户 '......\ASPNET' 登录失败。

  2. 需要为这个发布的service创建虚拟目录,不然会在这一行提示错误:

  <authentication mode="Windows"/>

 

三、 创建客户端----Webservice使用者

  新建一个winform程序,添加刚刚部署的webservice(References->Add Service Reference)。在form中添加一个DataGridView用来显示数据。下面会介绍几种方法,这里用一个 button的click事件对应处理一种情况,然后进行比较。

 

四、提高WebService的性能

  然而这种直接返回dataset的方法,在数据量比较大的时候,传递处理慢,消耗网络资源较多。下面介绍几种常用的方法,将dataset序列化/压缩后传输。

  1. Webservice方法返回DataSet对象用Binary序列化后的字节数组,然后在客户端进行反序列化。采用字节数组流的处理模式,易于处理。

代码
//Webservice
[WebMethod(Description = "返回DataSet对象用Binary序列化后的字节数组")]
public byte[] GetDataSetBytes()
{
    DataSet sqlDS 
= GetDataSet();
    BinaryFormatter bFormatter 
= new BinaryFormatter();
    MemoryStream mStream 
= new MemoryStream();
    bFormatter.Serialize(mStream, sqlDS);
    
byte[] buffer = mStream.ToArray();
    
return buffer;
}
//Client
/// <summary>
/// 反序列化DataSet对象用Binary序列化后的字节数组
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button2_Click(object sender, EventArgs e)
{
//    DateTime dtBegin = DateTime.Now;

    
byte[] buffer = webService.GetDataSetBytes();
    BinaryFormatter bFormatter 
= new BinaryFormatter();
    DataSet dataSet 
= bFormatter.Deserialize(new MemoryStream(buffer)) as DataSet;

//    this.label2.Text = string.Format("耗时:{0}", DateTime.Now - dtBegin + "          " + buffer.Length.ToString());
//    BindDataSet(dataSet);
}

  

  2. Webservice方法返回DataSetSurrogate对象用Binary序列化后的字节数组。这里用到微软提供的开源组件DataSetSurrogate.dll进行序列化。

代码
//WebService
[WebMethod(Description = "返回DataSetSurrogate对象用Binary序列化后的字节数组")]
public byte[] GetDataSetSurrogateBytes()
{
    DataSet sqlDS = GetDataSet();
    DataSetSurrogate dss = new DataSetSurrogate(sqlDS);
    BinaryFormatter bFormatter = new BinaryFormatter();
    MemoryStream mStream = new MemoryStream();
    bFormatter.Serialize(mStream, dss);

    
byte[] buffer = mStream.ToArray();
    
return buffer;
}

//Client
/// <summary>
/// 反序列化DataSetSurrogate对象用Binary序列化后的字节数组(Microsoft组件处理)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button3_Click(object sender, EventArgs e)
{
//    DateTime dtBegin = DateTime.Now;

    
byte[] buffer = webService.GetDataSetSurrogateBytes();
    BinaryFormatter bFormatter = new BinaryFormatter();

    DataSetSurrogate dss = bFormatter.Deserialize(new MemoryStream(buffer)) as DataSetSurrogate;
    DataSet dataSet = dss.ConvertToDataSet();

//    this.label3.Text = string.Format("耗时:{0}", DateTime.Now - dtBegin + "          " + buffer.Length.ToString());
//    BindDataSet(dataSet);
}

  

  3. Webservice方法返回DataSetSurrogate对象用Binary序列化并ZIP压缩后的字节数组。

代码
//WebService
[WebMethod(Description = "返回DataSetSurrogate对象用Binary序列化并ZIP压缩后的字节数组")]
public byte[] GetDataSetSurrogateZipBytes()
{
    DataSet sqlDS = GetDataSet();
    DataSetSurrogate dss = new DataSetSurrogate(sqlDS);
    BinaryFormatter bFormatter = new BinaryFormatter();
    MemoryStream mStream = new MemoryStream();
    bFormatter.Serialize(mStream, dss);

    
byte[] buffer = mStream.ToArray();
    
byte[] zipBuffer = Compress(buffer);
    
return zipBuffer;
}
/// <summary>
/// zip 压缩
/// </summary>
/// <param name="data">初始字节数组</param>
/// <returns>压缩后的字节数组</returns>
public byte[] Compress(byte[] data)
{
    MemoryStream ms = new MemoryStream();
    Stream zipStream = null;
    zipStream = new GZipStream(ms, CompressionMode.Compress, true);
    zipStream.Write(data, 0, data.Length);
    zipStream.Close();
    ms.Position = 0;
    
byte[] compressed_data = new byte[ms.Length];
    ms.Read(compressed_data, 0int.Parse(ms.Length.ToString()));
    
return compressed_data;
}

//Client
/// <summary>
/// 返回DataSetSurrogate对象用Binary序列化并ZIP压缩后的字节数组(Microsoft组件处理)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, EventArgs e)
{
    DateTime dtBegin = DateTime.Now;

    
byte[] zipBuffer = webService.GetDataSetSurrogateZipBytes();
    
byte[] buffer = Decompress(zipBuffer);
    BinaryFormatter bFormatter = new BinaryFormatter();
    DataSetSurrogate dss = bFormatter.Deserialize(new MemoryStream(buffer)) as DataSetSurrogate;
    DataSet dataSet = dss.ConvertToDataSet();

    
this.label4.Text = string.Format("耗时:{0}", DateTime.Now - dtBegin + "          " + zipBuffer.Length.ToString());

    BindDataSet(dataSet);
}
/// <summary>
/// Decompresses the specified data.
/// </summary>
/// <param name="data">The data.</param>
/// <returns></returns>
private byte[] Decompress(byte[] data)
{
    
try
    {
        MemoryStream ms = new MemoryStream(data);
        Stream zipStream = null;
        zipStream = new GZipStream(ms, CompressionMode.Decompress);
        
byte[] dc_data = null;
        dc_data = EtractBytesFormStream(zipStream, data.Length);
        
return dc_data;
    }
    
catch
    {
        
return null;
    }
}
private byte[] EtractBytesFormStream(Stream zipStream, int dataBlock)
{
    
try
    {
        
byte[] data = null;
        
int totalBytesRead = 0;
        
while (true)
        {
            Array.Resize(ref data, totalBytesRead + dataBlock + 1);
            
int bytesRead = zipStream.Read(data, totalBytesRead, dataBlock);
            
if (bytesRead == 0)
            {
                
break;
            }
            totalBytesRead += bytesRead;
        }
        Array.Resize(ref data, totalBytesRead);
        
return data;
    }
    
catch
    {
        
return null;
    }
}


  下图是四种方法的测试结果:(Sql Server2005, 数据line>40000,4个字段)

 

 

 从这里可以下载我所用Demo的源代码

 

posted on 2010-05-31 23:17  lantionzy  阅读(908)  评论(0编辑  收藏  举报