Silverlight专题(9)-WCF通信(2)

本文介绍了一种利用WCFService进行分块文件上传的方法,并通过Silverlight客户端实现了文件上传进度的实时展示。

在上文我粗略的介绍了如何创建WCF Service,并在客户端调用生成的WCF Service来取得数据

本文将用一个上传程序来继续介绍下Silverlight中的WCF Service应用

问题:

调用WCF Service的时候,并没有一个DownloadProcessChanged之类的事件来反馈已经上传了多少

那么我们如何来实现在客户端实时展示当天已经上传了多少呢?

解决方案:

我们可以把文件分成很多块,逐次上传一小部分(比如2K,4K,8K等等)

1。首先我们还是按照Silverlight专题(9)-WCF通信(1)这个教程中所示的先创建个新的Silverlight工程

并添加进一个Silverlight-Enabled WCF Service(我取名为DownloadService,以前随便去的名字,懒得改了)

其里面含有的操作契约如下:

1  [ServiceContract(Namespace =   "" )]
2  [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
3  public   class DownloadService
4  {
5      [OperationContract]
6      public   string UploadImg( string fileName, byte [] fileData, bool firstChunk, bool lastChunk)
7      {
8          if ( ! File.Exists(@HostingEnvironment.ApplicationPhysicalPath +   @" /Uploads/ "   + fileName))
9          {
10              string tmpExtension =   " _tmp " ;
11              string tempFileName = fileName + tmpExtension;
12              if (firstChunk)
13              {
14                  fileName += tmpExtension;
15                  if (File.Exists(@HostingEnvironment.ApplicationPhysicalPath + tempFileName))
16                  {
17                      File.Delete(@HostingEnvironment.ApplicationPhysicalPath + tempFileName);
18                  }
19              }
20 
21              FileStream fs = File.Open(@HostingEnvironment.ApplicationPhysicalPath + tempFileName, FileMode.Append);
22              fs.Write(fileData, 0 , fileData.Length);
23              fs.Close();
24 
25              if (lastChunk)
26              {
27                  // Rename file to original file
28                  File.Move(@HostingEnvironment.ApplicationPhysicalPath + tempFileName, @HostingEnvironment.ApplicationPhysicalPath +   " /ClientBin/Uploads/ "   + fileName);
29              }
30          }
31 
32          return   " ./Uploads/ "   + fileName;
33      }
34  }

Upload这个操作契约的输入参数有文件名,文件的比特数组,firstChunk用来表示是否传输的是文件的第一个包

lastChunk代表文件的包是不是最后一个包

如果还不是最后一个包时,将传输过来的文件的文件扩展名加上后缀_tmp来存放

一旦lastChunk为true时,将该文件存为原文件名

2.实现客户端的界面

我们需要三个东西

一个用来调用选择上传文件对话框的Button

一个用来展示上传进度的进度条

一个用来展示结果的Image控件

(我设置为只能上传JPG或者PNG文件,结果返回一个上传后的图片的相对路径)

代码如下:

1  < UserControl x:Class = " ReadImageTest.Page "
2      xmlns = " http://schemas.microsoft.com/winfx/2006/xaml/presentation "  
3      xmlns:x = " http://schemas.microsoft.com/winfx/2006/xaml " >
4      < StackPanel x:Name = " LayoutRoot " Background = " #3C3C3C " >
5          < Grid >
6              < Image x:Name = " img " Width = " 800 " Height = " 600 " />
7              < ProgressBar x:Name = " pb " Height = " 20 " Width = " 400 " Maximum = " 1 " Visibility = " Collapsed " />
8          </ Grid >
9          < Button Margin = " 0,5 " x:Name = " uploadBtn " Content = " Upload " Padding = " 8,4 " FontSize = " 15 " HorizontalAlignment = " Center " Click = " uploadBtn_Click " />
10      </ StackPanel >
11  </ UserControl >

3.具体底层的控制代码

a.选择上传文件对话框的实现如下

1  public   void uploadBtn_Click( object sender, RoutedEventArgs e)
2  {
3      OpenFileDialog ofd =   new OpenFileDialog();
4      ofd.Filter =   " JPG Files|*.jpg|PNG Files|*.png " ;
5      ofd.Multiselect =   false ;
6 
7      if (( bool )ofd.ShowDialog())
8      {
9          this .pb.Visibility = Visibility.Visible;
10          this .img.Opacity =   0 ;
11          dataSent =   0 ;
12          stream = ofd.File.OpenRead();
13          dataLength = stream.Length;
14          if (dataLength >   16384 )
15          {
16              firstChunk =   true ;
17              lastChunk =   false ;
18              fileName = ofd.File.Name;
19              byte [] buffer =   new   byte [ 4   *   4096 ];
20              int read = stream.Read(buffer, 0 , buffer.Length);
21              dataSent += read;
22              if (read !=   0 )
23              {
24                  if (dataSent == dataLength)
25                      lastChunk =   true ;
26                  client.UploadImgAsync(fileName, buffer, firstChunk, lastChunk);
27                  firstChunk =   false ;
28              }
29          }
30 
31          else
32          {
33              MessageBox.Show( " The upload file is too small! " );
34          }
35      }
36  }

我设置了每个包的大小是16K

也就是每次调用WCF Service最多只能传16K的东西

BTW:其中Client的定义为 private DownloadServiceRef.DownloadServiceClient client;

b.展示上传进度并显示最终上传结果

1 void client_UploadImgCompleted( object sender, ReadImageTest.DownloadServiceRef.UploadImgCompletedEventArgs e)
2 ExpandedBlockStart.gifContractedBlock.gif {
3    if (dataSent < dataLength)
4ExpandedSubBlockStart.gifContractedSubBlock.gif    {
5        byte[] buffer = new byte[4 * 4096];
6        int read = stream.Read(buffer, 0, buffer.Length);
7        dataSent += read;
8        this.pb.Value = (double)dataSent / dataLength;
9        if (read != 0)
10ExpandedSubBlockStart.gifContractedSubBlock.gif        {
11            if (dataSent == dataLength)
12                lastChunk = true;
13            client.UploadImgAsync(fileName, buffer, firstChunk, lastChunk);
14            firstChunk = false;
15        }

16    }

17
18    else
19ExpandedSubBlockStart.gifContractedSubBlock.gif    {
20        this.pb.Visibility = Visibility.Collapsed;
21        this.img.Opacity = 1;
22        this.img.Source = new BitmapImage(new Uri(e.Result, UriKind.RelativeOrAbsolute));
23    }

24}

每上传完一个包就更新下上传进度条

如果传送的包的大小已经等于文件大小时,隐藏进度条,并展示上传的图片

总结:

Silverlight目前对WCF的支持虽然只局限在普通的HttpBinding,但是功能也还算强大

本文只是小试牛刀,展示了个小小的图片上传工具实现,希望能起到抛砖引玉的作用

 

源代码下载地址如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值