问题: WCF Service时候并没有个DownloadProcessChanged的类事件来反馈已经上传了多少
那么我们如何来实现在客户端实时展示当天已经上传了多少呢?
解决方案: 我们可以把文件分成很多块逐次上传小部分(比如2K4K8K等等)
1首先我们还是按照Silverlight专题(9)-WCF通信(1)这个教程中所示先创建个新Silverlight工程
并添加进个Silverlight-Enabled WCF Service(我取名为DownloadService以前随便去名字懒得改了)
其里面含有操作契约如下:
1 [ServiceContract(Namespace = "")]
2 [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
3 public DownloadService
4 {
5 [OperationContract]
6 public UploadImg( fileName, fileData, bool firstChunk, bool lastChunk)
7 {
8 (!File.Exists(@HostingEnvironment.ApplicationPhysicalPath + @"/Uploads/" + fileName))
9 {
10 tmpExtension = "_tmp";
11 tempFileName = fileName + tmpExtension;
12 (firstChunk)
13 {
14 fileName tmpExtension;
15 (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 (lastChunk)
26 {
27 //Rename file to original file
28 File.Move(@HostingEnvironment.ApplicationPhysicalPath + tempFileName, @HostingEnvironment.ApplicationPhysicalPath + "/ClientBin/Uploads/" + fileName);
29 }
30 }
31
32 "./Uploads/" + fileName;
33 }
34 }
Upload这个操作契约输入参数有文件名文件比特firstChunk用来表示是否传输是文件第个包
lastChunk代表文件包是不是最后个包
如果还不是最后个包时将传输过来文件文件扩展名加上后缀_tmp来存放
旦lastChunk为true时将该文件存为原文件名
2.实现客户端界面
我们需要 3个东西
个用来选择上传文件对话框Button
个用来展示上传进度进度条
个用来展示结果ImageControl控件
(我设置为只能上传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 = OpenFileDialog;
4 ofd.Filter = "JPG Files|*.jpg|PNG Files|*.png";
5 ofd.Multiselect = false;
6
7 ((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 (dataLength > 16384)
15 {
16 firstChunk = true;
17 lastChunk = false;
18 fileName = ofd.File.Name;
19 buffer = [4 * 4096];
20 read = stream.Read(buffer, 0, buffer.Length);
21 dataSent read;
22 (read != 0)
23 {
24 (dataSent dataLength)
25 lastChunk = true;
26 client.UploadImgAsync(fileName, buffer, firstChunk, lastChunk);
27 firstChunk = false;
28 }
29 }
30
31
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 (dataSent < dataLength)
4 {
5 buffer = [4 * 4096];
6 read = stream.Read(buffer, 0, buffer.Length);
7 dataSent read;
8 this.pb.Value = (double)dataSent / dataLength;
9 (read != 0)
10 {
11 (dataSent dataLength)
12 lastChunk = true;
13 client.UploadImgAsync(fileName, buffer, firstChunk, lastChunk);
14 firstChunk = false;
15 }
16 }
17
18
19 {
20 this.pb.Visibility = Visibility.Collapsed;
21 this.img.Opacity = 1;
22 this.img.Source = BitmapImage( Uri(e.Result, UriKind.RelativeOrAbsolute));
23 }
24}
每上传完个包就更新下上传进度条
如果传送包大小已经等于文件大小时隐藏进度条并展示上传图片
整理总结: Silverlight目前对WCF支持虽然只局限在普通HttpBinding但是功能也还算强大
本文只是小试牛刀展示了个小小图片上传工具实现希望能起到抛砖引玉作用
最新评论