上一篇中提高Silverlight实现文件上传的一些思路,说实在的,在写哪篇文章之前并没有亲身试验过,虽说是思路,但是万一有偏差还是有点冒险。
经过自己测试后,得意证明,Silverlight 利用 WCF实现上传确实是如此的简单方便,逻辑上也非常的顺畅。
废话不说,看过前一篇文章后对Silverlight 利用 WCF实现上传大概有概念上的理解,下面直接就是代码部分了。
此代码只是先了文件上传,界面没怎么做就两个按钮,文件名和上传消息通知都直接显示在按钮上,这是为了让代码看上去简单,更容易理解,见谅。
实现:
首先,创建一个ASP.NET项目,然后再该项目中创建一个用于启动于Silverlight的WCF服务 ,也就是一个SVC文件以及.CS代码文件。我取名为Upload.svc,代码如下
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Text;
namespace WebApp4SL
{
[ServiceContract(Namespace = "Zeta")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class UpLoad
{
[OperationContract]
public string Upload(byte[] bytes,string filename)
{
System.IO.FileStream fs = new System.IO.FileStream(System.Web.HttpContext.Current.Server.MapPath("UploadFile")+"/"+filename,System.IO.FileMode.Create);
fs.Write(bytes,0,bytes.Length);
fs.Flush();
fs.Close();
return "成功!";
}
}
}
这里成功与否当然应该加入更多判断,例如文件是否有重名,或者是否是可支持的类型,我的示例中都没有判断,实际项目中都应该加上,还有就是错误处理 TRY。
服务器端就此完成,当然,你还得在ASP.NET项目下新建一个目录用于存放上传来的文件,我命名为UploadFile
接下来就是客户端Silverlight的代码了,首先创建一个Silverlight项目,然后引用刚才我们创建的WCF服务。接下来写Page.xaml及其代码,Page.xaml.cs 如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Xml;
using System.IO;
using System.Text;
namespace SilverlightTest
{
public partial class Page : UserControl
{
byte[] bytes;
string filename;
public Page()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
}
private void UserControl_KeyDown(object sender, KeyEventArgs e)
{
}
private void openfile_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog op = new OpenFileDialog();
if (op.ShowDialog()==true)
{
FileStream fs = op.File.OpenRead();
bytes = new byte[fs.Length];
fs.Read(bytes,0,bytes.Length);
openfile.Content =op.File.Name;
filename = op.File.Name;
}
}
private void upload_Click(object sender, RoutedEventArgs e)
{
if (bytes != null)
{
WebApp.UpLoadClient uc = new SilverlightTest.WebApp.UpLoadClient();
uc.UploadCompleted += new EventHandler<SilverlightTest.WebApp.UploadCompletedEventArgs>(uc_UploadCompleted);
uc.UploadAsync(bytes,filename);
}
}
void uc_UploadCompleted(object sender, SilverlightTest.WebApp.UploadCompletedEventArgs e)
{
openfile.Content = e.Result;
}
}
}
很简单,可以说是简陋,但是很能说明问题。
最后就是更简单的Page.xaml文件
<UserControl x:Class="SilverlightTest.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300" xmlns:SilverlightTest="clr-namespace:SilverlightTest" Loaded="UserControl_Loaded" KeyDown="UserControl_KeyDown">
<StackPanel x:Name="sp">
<Button x:Name="openfile" Content="浏览" Click="openfile_Click"></Button>
<Button x:Name="upload" Content="上传" Click="upload_Click"></Button>
</StackPanel>
</UserControl>
至此,完成了Silverlight的上传功能。可以看到,Silverlight在客户端获取文件流,写到了一个缓冲块,然后直接将缓冲块作为WCF服务方法的参数,请求执行WCF服务的方法,这个缓冲块就被传递到了服务器,并在服务器上的WCF服务后台代码被处理,处理效果就是将这个缓冲块写入到一个文件流保存起来。
很简单吧,而且很直观,与以往写入到HTTP请求流,再从请求流里操作简单了一些,但是你也许会说,这样的方法并不比ASP.NET里那个上传控件简单多少啊。但是直接用上传控件会遇到的两个问题很让人棘手,第一就是文件的体积问题,上传大体积会消耗很多时间,也占用较大服务器内存,随之而来的就是HTTP超时问题,另一个就是进度问题,HTTP上传是无法显示进度的,当然AJAX的分块可以解决,但是如果我们用SILVERLIGHT,就更简单了,将客户端文件流分块写入到缓冲块,然后再一次次分别去调用WCF的服务方法,保存成分块的小文件,最后,执行一次合并方法,将文件合并后保存,我的这个例里没有实现这个功能,但是改进下很容易,分块后,做进度就不是什么问题了吧,因为有WCF方法的异步回调时间,一切都是那么简单。
另外,如果在没有使用分块上传的情况下单个上传文件比较大,或者分块上传单块过大,有可能出现 NOTFOUND异常,为什么,那是你的WCF配置限制引起的,可以在 WEBCONFI文件里进行修改。添加类似以下配置代码
<basicHttpBinding>
<binding name="LargeBuffer" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" textEncoding="UTF-8" sendTimeout="00:05:10" receiveTimeout="00:05:10" openTimeout="00:05:10" closeTimeout="00:05:10">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>
</binding>
</basicHttpBinding>
如果不知道怎么配置,可以在VS2008里右键点解WEB.CONFIG 选择 编辑WCF配置 进入配置界面。