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

在上文我粗略的介绍了如何创建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.展示上传进度并显示最终上传结果

1void client_UploadImgCompleted(object sender, ReadImageTest.DownloadServiceRef.UploadImgCompletedEventArgs e)
2{
3    if (dataSent < dataLength)
4    {
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)
10        {
11            if (dataSent == dataLength)
12                lastChunk = true;
13            client.UploadImgAsync(fileName, buffer, firstChunk, lastChunk);
14            firstChunk = false;
15        }

16    }

17
18    else
19    {
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,但是功能也还算强大

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

 

源代码下载地址如下:

posted @ 2008-10-26 22:59  ibillguo  阅读(3132)  评论(4编辑  收藏  举报