在上文我粗略的介绍了如何创建WCF Service,并在客户端调用生成的WCF Service来取得数据
本文将用一个上传程序来继续介绍下Silverlight中的WCF Service应用
问题:
调用WCF Service的时候,并没有一个DownloadProcessChanged之类的事件来反馈已经上传了多少
那么我们如何来实现在客户端实时展示当天已经上传了多少呢?
解决方案:
我们可以把文件分成很多块,逐次上传一小部分(比如2K,4K,8K等等)
1。首先我们还是按照Silverlight专题(9)-WCF通信(1)这个教程中所示的先创建个新的Silverlight工程
并添加进一个Silverlight-Enabled WCF Service(我取名为DownloadService,以前随便去的名字,懒得改了)
其里面含有的操作契约如下:
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文件,结果返回一个上传后的图片的相对路径)
代码如下:
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.选择上传文件对话框的实现如下
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.展示上传进度并显示最终上传结果

2



3

4



5

6

7

8

9

10



11

12

13

14

15

16

17

18

19



20

21

22

23

24

每上传完一个包就更新下上传进度条
如果传送的包的大小已经等于文件大小时,隐藏进度条,并展示上传的图片
总结:
Silverlight目前对WCF的支持虽然只局限在普通的HttpBinding,但是功能也还算强大
本文只是小试牛刀,展示了个小小的图片上传工具实现,希望能起到抛砖引玉的作用
源代码下载地址如下: