热门:网页模板.net视频教程JQueryMVCjsonExtJs源码示例三级联动JQuery菜单
您现在的位置:.Net中文社区>> Silverlight>>正文内容

Silverlight WCF通信(二)

发布时间:2009年04月10日点击数: 笑看风云淡

返回连载教程目录     实例源码下载

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

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

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

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

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

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

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

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

[ServiceContract(Namespace = "")]  
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]  
public class DownloadService  
{  
    [OperationContract]  
    public string UploadImg(string fileName, byte[] fileData, bool firstChunk, bool lastChunk)  
    {  
        if (!File.Exists(@HostingEnvironment.ApplicationPhysicalPath + @"/Uploads/" + fileName))  
        {  
            string tmpExtension = "_tmp";  
             string tempFileName = fileName + tmpExtension;  
             if (firstChunk)  
             {  
                 fileName += tmpExtension;  
                 if (File.Exists(@HostingEnvironment.ApplicationPhysicalPath + tempFileName))  
                 {  
                     File.Delete(@HostingEnvironment.ApplicationPhysicalPath + tempFileName);  
                 }
  
            }
  
  
             FileStream fs = File.Open(@HostingEnvironment.ApplicationPhysicalPath + tempFileName, FileMode.Append);  
             fs.Write(fileData, 0, fileData.Length);  
             fs.Close();  
  
             if (lastChunk)  
             {  
                 //Rename file to original file  
                 File.Move(@HostingEnvironment.ApplicationPhysicalPath + tempFileName, @HostingEnvironment.ApplicationPhysicalPath + "/ClientBin/Uploads/" + fileName);  
             }
  
         }
  
  
         return "./Uploads/" + fileName;  
     }
  
}

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

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

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

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

2.实现客户端的界面

我们需要三个东西

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

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

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

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

代码如下:

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

3.具体底层的控制代码

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

public void uploadBtn_Click(object sender, RoutedEventArgs e)  
{  
     OpenFileDialog ofd = new OpenFileDialog();  
     ofd.Filter = "JPG Files|*.jpg|PNG Files|*.png";  
     ofd.Multiselect = false;  
  
     if ((bool)ofd.ShowDialog())  
     {  
         this.pb.Visibility = Visibility.Visible;  
         this.img.Opacity = 0;  
         dataSent = 0;  
         stream = ofd.File.OpenRead();  
         dataLength = stream.Length;  
         if (dataLength > 16384)  
         {  
             firstChunk = true;  
             lastChunk = false;  
             fileName = ofd.File.Name;  
             byte[] buffer = new byte[4 * 4096];  
             int read = stream.Read(buffer, 0, buffer.Length);  
             dataSent += read;  
             if (read != 0)  
             {  
                 if (dataSent == dataLength)  
                     lastChunk = true;  
                 client.UploadImgAsync(fileName, buffer, firstChunk, lastChunk);  
                 firstChunk = false;  
             }
  
         }
  
  
         else  
         {  
             MessageBox.Show("The upload file is too small!");  
         }
  
     }
  
}

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

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

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

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

void client_UploadImgCompleted(object sender, ReadImageTest.DownloadServiceRef.UploadImgCompletedEventArgs e)  
{  
    if (dataSent < dataLength)  
    {  
        byte[] buffer = new byte[4 * 4096];  
        int read = stream.Read(buffer, 0, buffer.Length);  
        dataSent += read;  
        this.pb.Value = (double)dataSent / dataLength;  
        if (read != 0)  
        {  
            if (dataSent == dataLength)  
                lastChunk = true;  
            client.UploadImgAsync(fileName, buffer, firstChunk, lastChunk);  
            firstChunk = false;  
        }
  
    }
  
  
    else  
    {  
        this.pb.Visibility = Visibility.Collapsed;  
        this.img.Opacity = 1;  
        this.img.Source = new BitmapImage(new Uri(e.Result, UriKind.RelativeOrAbsolute));  
    }
  
}

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

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

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

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

本站热点业务

更多模板/案例展示

关于我们 | 联系我们 | 团队日志 | 网站地图 | 网站合作