【分享】 在silverlight中使用wcf上传文件并实时显示进度
2012-02-25 16:35
507 查看
公司一个项目要用到文件上件, Google后了解到上传一般有三种方式:WebClient、WebService和WCF。
最开始用WebClient.OpenWrite实现了文件上传,但弄不明白怎么才能得到上传进度,只好放弃了。
用WebService还不如直接WCF,参考http://www.cnblogs.com/blackcore/archive/2009/11/21/1607823.html后,自己做了一个,最终的效果图如下:
简单实现步骤如下:
一、在sl.Web项目中添加“启用了 Silverlight 的 WCF 服务”。WCF服务的内容十分简单,只需一个功能:接收字节并储存即可。
代码如下:
二、为让WCF服务支持大文件需对sl.Web项目中的web.config进行配置,增加MaxArrayLength属性的设置:
三、在sl项目中添加上传类,实现上传方法。
利用WCF异步调用的特点,将要上传的文件分成N个文件块依次上传,由此获得准确的上传进度。代码如下:
四、制作简单的上传控件,代码如下:
五、新建一个Page,前台界面如下:
注意添加第四步中定义的UploadFileControl的引用
后台代码:
HOHO运行一下看效果怎么样吧!
项目源码 我接触siverlight和wcf不久,望大牛指教啊。
最开始用WebClient.OpenWrite实现了文件上传,但弄不明白怎么才能得到上传进度,只好放弃了。
用WebService还不如直接WCF,参考http://www.cnblogs.com/blackcore/archive/2009/11/21/1607823.html后,自己做了一个,最终的效果图如下:
简单实现步骤如下:
一、在sl.Web项目中添加“启用了 Silverlight 的 WCF 服务”。WCF服务的内容十分简单,只需一个功能:接收字节并储存即可。
代码如下:
[ServiceContract(Namespace = "")] [SilverlightFaultBehavior] [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] public class UploadFileWCFService { [OperationContract] public void DoWork() { // 在此处添加操作实现 return; } /// <summary> /// 开始上传。需要在WCF服务启动文件夹下建立UploadFiles、TempUploadFolder文件夹。 /// UploadFiles储存上传文件夹 /// TempUploadFolder为上传临时文件夹 /// </summary> /// <param name="FullPath">保存路径及文件名</param> /// <param name="FileContext">文件内容</param> /// <param name="Overwrite">是否覆盖</param> [OperationContract] public void BeginUpload(string FullPath, byte[] FileContext, bool Overwrite) { try { if (!FullPath.StartsWith("\\")) { FullPath = "\\" + FullPath; } string defaultFolder = System.Web.Hosting.HostingEnvironment.MapPath("~/UploadFiles"); string tempUploadFolder = System.Web.Hosting.HostingEnvironment.MapPath("~/TempUploadFolder"); string SaveFolder = Path.GetDirectoryName(FullPath); string Filename = Path.GetFileName(FullPath); string BlockString = Path.GetExtension(Filename); string[] block = BlockString.Split('-'); if (block.Length != 2) { throw new Exception("系统不支持此操作"); } int FilesIndex = Convert.ToInt32(block[0].Replace(".", "")); int FilesCount = Convert.ToInt32(block[1]); string tempFolder = tempUploadFolder + "\\" + Path.GetFileNameWithoutExtension(FullPath); //上传到临时文件夹 Directory.CreateDirectory(tempFolder); if (!Directory.Exists(defaultFolder + "\\" + SaveFolder)) { Directory.CreateDirectory(defaultFolder + "\\" + SaveFolder); } FileMode mode = FileMode.Create; if (!Overwrite) { mode = FileMode.Append; } using (FileStream fs = new FileStream(tempFolder + "\\" + Filename, mode, FileAccess.Write)) { fs.Write(FileContext, 0, FileContext.Length); } if (FilesIndex == FilesCount - 1)//是否最后一块文件,如是则合并文件块得到完整文件 { string UploadFile = defaultFolder + "\\" + SaveFolder + "\\" + Path.GetFileNameWithoutExtension(FullPath); string[] files = Directory.GetFiles(tempFolder); using (FileStream sFile = new FileStream(UploadFile, FileMode.Create, FileAccess.Write)) { foreach (string file in files) { using (FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read)) { byte[] context = new byte[fs.Length]; fs.Read(context, 0, context.Length); sFile.Write(context, 0, context.Length); } File.Delete(file); } } Directory.Delete(tempFolder); } } catch (Exception) { throw; } return; } }
二、为让WCF服务支持大文件需对sl.Web项目中的web.config进行配置,增加MaxArrayLength属性的设置:
<system.serviceModel> <behaviors> <serviceBehaviors> <behavior name=""> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="false" /> </behavior> </serviceBehaviors> </behaviors> <bindings> <customBinding> <binding name="AutoloanMobileManager.Web.Service.UploadFileWCFService.customBinding0"> <binaryMessageEncoding> <readerQuotas maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" /> </binaryMessageEncoding> <httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" /> </binding> </customBinding> </bindings> <services> <service name="AutoloanMobileManager.Web.Service.UploadFileWCFService"> <endpoint address="" binding="customBinding" bindingConfiguration="AutoloanMobileManager.Web.Service.UploadFileWCFService.customBinding0" contract="AutoloanMobileManager.Web.Service.UploadFileWCFService" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
三、在sl项目中添加上传类,实现上传方法。
利用WCF异步调用的特点,将要上传的文件分成N个文件块依次上传,由此获得准确的上传进度。代码如下:
public class WcfUploadFileService : INotifyPropertyChanged { public class FileList : INotifyPropertyChanged { private void NotifyPropertyChanged(string info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } private int m_BufferSize = 4096; private FileInfo m_FileList; private UploadStatusType m_UploadStauts; private long m_BytesSent; private long m_BytesSentCount; private int m_SentPercentage; private string m_SavePath; private ObservableCollection<UploadLog> m_LOG = new ObservableCollection<UploadLog>(); public enum UploadStatusType { Waitting, Uploading, Completed, Failed, Pause } /// <summary> /// 每次上传的字节数。应在给File赋值前设定。 /// </summary> public int BufferSize { get { return m_BufferSize; } set { m_BufferSize = value; } } public class UploadLog { public UploadLog(DateTime time, string context, object tag) { LogTime = time; LogContext = context; Tag = tag; } public DateTime LogTime { get; set; } public string LogContext { get; set; } public object Tag { get; set; } } /// <summary> /// 上传日志 /// </summary> public ObservableCollection<UploadLog> LOG { get { return m_LOG; } set { m_LOG = value; NotifyPropertyChanged("LOG"); } } private void AddLog(UploadLog log) { LOG.Add(log); } /// <summary> /// 等待传输的字节数据列表。设计this.File时自动赋值,按BufferSize读取至Byte[]等待上传。 /// </summary> public List<Byte[]> FileContext { get; set; } /// <summary> /// 要上传的文件 /// </summary> public FileInfo File { get { return m_FileList; } set { m_FileList = value; Stream soureFile = null; UploadStatus = UploadStatusType.Waitting; try { soureFile = value.OpenRead(); } catch (Exception) { UploadStatus = UploadStatusType.Failed; AddLog(new UploadLog(DateTime.Now, "无法读取文件", null)); } long BytesCount = soureFile.Length; long BytesRead = 0; if (FileContext == null) { FileContext = new List<byte[]>(); } else { FileContext.Clear(); } long ReadSize = BufferSize; while (BytesRead < BytesCount) { if (BytesRead + BufferSize > BytesCount) //调整最后一个文件块的大小 { ReadSize = BytesCount - BytesRead; } byte[] bytes = new byte[ReadSize]; BytesRead += soureFile.Read(bytes, 0, bytes.Length); FileContext.Add(bytes); } soureFile.Close(); soureFile.Dispose(); NotifyPropertyChanged("File"); } } /// <summary> /// 保存路径 /// </summary> public string SavePath { get { return m_SavePath; } set { m_SavePath = value; NotifyPropertyChanged("SavePath"); } } /// <summary> /// 上传状态 /// </summary> public UploadStatusType UploadStatus { get { return m_UploadStauts; } set { m_UploadStauts = value; NotifyPropertyChanged("UploadStatus"); } } /// <summary> /// 本次上传字节 /// </summary> public long BytesSent { get { return m_BytesSent; } set { m_BytesSent = value; NotifyPropertyChanged("BytesSent"); } } /// <summary> /// 已上传字节 /// </summary> public long BytesSentCount { get { return m_BytesSentCount; } set { m_BytesSentCount = value; NotifyPropertyChanged("BytesSentCount"); } } /// <summary> /// 已上传比率 /// </summary> public int SentPercentage { get { return m_SentPercentage; } set { m_SentPercentage = value; NotifyPropertyChanged("SentPercentage"); } } #region INotifyPropertyChanged 成员 public event PropertyChangedEventHandler PropertyChanged; #endregion } UploadFileWCFServiceClient uploadClient = new UploadFileWCFServiceClient(); public WcfUploadFileService() { uploadClient.BeginUploadCompleted += new EventHandler<AsyncCompletedEventArgs>(uploadClient_BeginUploadCompleted); } void uploadClient_BeginUploadCompleted(object sender, AsyncCompletedEventArgs e) { //通过CurrentFileIndex 、CurrentFileContextIndex控制下一个上传的块 bool beginNew = false; //是开始一个新文件或续传 if (e.Error != null) { //如错误,放弃当前文件,传下一文件 Files[CurrentFileIndex].UploadStatus = FileList.UploadStatusType.Failed; Files[CurrentFileIndex].LOG.Add(new FileList.UploadLog(DateTime.Now, e.Error.Message, null)); CurrentFileIndex++; CurrentFileContextIndex = 0; beginNew = true; } else { Files[CurrentFileIndex].BytesSent = Files[CurrentFileIndex].FileContext[CurrentFileContextIndex].Length; Files[CurrentFileIndex].BytesSentCount += Files[CurrentFileIndex].BytesSent; Files[CurrentFileIndex].SentPercentage = Convert.ToInt32((double)Files[CurrentFileIndex].BytesSentCount / (double)Files[CurrentFileIndex].File.Length * 100); //计算下一个上传的文件号和块号 if (CurrentFileIndex < Files.Count) { if (CurrentFileContextIndex < Files[CurrentFileIndex].FileContext.Count - 1) { CurrentFileContextIndex++; } else { Files[CurrentFileIndex].UploadStatus = FileList.UploadStatusType.Completed; CurrentFileIndex++; CurrentFileContextIndex = 0; beginNew = true; } } } if (CurrentFileIndex < Files.Count) { Files[CurrentFileIndex].UploadStatus = FileList.UploadStatusType.Uploading; uploadClient.BeginUploadAsync(Files[CurrentFileIndex].SavePath + "//" + Files[CurrentFileIndex].File.Name + "." + CurrentFileContextIndex.ToString().PadLeft(9,'0') + "-" + Files[CurrentFileIndex].FileContext.Count, Files[CurrentFileIndex].FileContext[CurrentFileContextIndex], beginNew); } else { Files[CurrentFileIndex - 1].UploadStatus = FileList.UploadStatusType.Completed; } } private ObservableCollection<FileList> m_Files = new ObservableCollection<FileList>(); /// <summary> /// 准备上传的文件列表 /// </summary> public ObservableCollection<FileList> Files { get { return m_Files; } set { m_Files = value; NotifyPropertyChanged("Files"); } } /// <summary> /// 当前上传的文件索引 /// </summary> private int CurrentFileIndex; /// <summary> /// 当前上传的文件块索引 /// </summary> private int CurrentFileContextIndex; /// <summary> /// 开始上传。按BufferSize将文件分块,块命名规则为 filename.blockid-blockcount,服务器接收完最后一块后合并成源文件。 /// </summary> public void BeginUpload() { if (Files.Count > 0) { CurrentFileIndex = 0; CurrentFileContextIndex = 0; Files[CurrentFileIndex].UploadStatus = FileList.UploadStatusType.Uploading; uploadClient.BeginUploadAsync(Files[CurrentFileIndex].SavePath + "//" + Files[CurrentFileIndex].File.Name + "." + CurrentFileContextIndex.ToString().PadLeft(9, '0') + "-" + Files[CurrentFileIndex].FileContext.Count, Files[CurrentFileIndex].FileContext[CurrentFileContextIndex], true); } } #region INotifyPropertyChanged 成员 public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string info) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(info)); } } #endregion
四、制作简单的上传控件,代码如下:
<UserControl x:Class="AutoloanMobileManager.Controls.UploadFileControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="70"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <ProgressBar x:Name="uploadProgress" Value="{Binding SentPercentage}" Height="20" Background="Yellow" Width="400" Grid.Column="1"/> <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right"> <TextBlock Text="{Binding BytesSentCount}" VerticalAlignment="Center"/> <TextBlock Text="/" VerticalAlignment="Center"/> <TextBlock Text="{Binding File.Length}" VerticalAlignment="Center"/> </StackPanel> <TextBlock Text="{Binding File.Name}" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="DarkBlue" Margin="8,0"/> <TextBlock Text="{Binding UploadStatus}" Grid.Column="0" VerticalAlignment="Center"/> </Grid> </UserControl>
五、新建一个Page,前台界面如下:
注意添加第四步中定义的UploadFileControl的引用
<navigation:Page x:Class="AutoloanMobileManager.Pages.UploadFilePage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:control="clr-namespace:AutoloanMobileManager.Controls" mc:Ignorable="d" xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" d:DesignWidth="640" d:DesignHeight="480" Title="UploadFilePage Page"> <StackPanel> <ListBox Margin="10" x:Name="list_uploadlist"> <ListBox.ItemTemplate> <DataTemplate> <control:UploadFileControl/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> <Button Content="选择文件" Click="Button_Click" Width="80" HorizontalAlignment="Left" Margin="5"/> </StackPanel> </navigation:Page>
后台代码:
public partial class UploadFilePage : Page { WcfUploadFileService upload = new WcfUploadFileService(); public UploadFilePage() { InitializeComponent(); list_uploadlist.ItemsSource = upload.Files; } // 当用户导航到此页面时执行。 protected override void OnNavigatedTo(NavigationEventArgs e) { } private void Button_Click(object sender, RoutedEventArgs e) { OpenFileDialog file = new OpenFileDialog(); file.Multiselect = true; bool? result = file.ShowDialog(); if (result.HasValue) { if (result.Value) { upload.Files.Clear(); foreach (System.IO.FileInfo f in file.Files) { WcfUploadFileService.FileList filelist = new WcfUploadFileService.FileList(); filelist.SavePath = "20120222"; filelist.BufferSize = 1024 * 32; filelist.File = f; upload.Files.Add(filelist); } upload.BeginUpload(); } } } }
HOHO运行一下看效果怎么样吧!
项目源码 我接触siverlight和wcf不久,望大牛指教啊。
相关文章推荐
- Silverlight 3 中使用WCF上传文件 (简单进度条展示)
- Silverlight 3 中使用WCF上传文件 (简单进度条展示)
- php 使用html5 XHR2 上传文件 进度显示
- vue使用axios实现文件上传进度的实时更新详解
- [C#]在WinForm下使用HttpWebRequest上传文件并显示进度[转]
- 使用Uploadify实现上传图片生成缩略图例子,实时显示进度条
- Struts2实现文件上传并显示实时进度
- html 使用Ajax 实现多文件上传,并显示进度
- [C#]在WinForm下使用HttpWebRequest上传文件并显示进度
- 使用Retrofit2.0实现Google Drive文件上传进度显示
- 使用HttpURLConnection上传文件,进度条显示不正确
- [转]C#在WinForm下使用HttpWebRequest上传文件并显示进度
- C#在WinForm下使用HttpWebRequest上传文件并显示进度
- c#在WinForm下使用HttpWebRequest上传文件并显示进度
- silverlight漂亮的文件上传进度显示原理及示例
- 使用struts2和AJAX实现文件上传并显示进度条
- 关于 javaweb的文件上传实时显示进度
- [C#]在WinForm下使用HttpWebRequest上传文件并显示进度
- C#在WinForm下使用HttpWebRequest上传文件并显示进度
- [C#]在WinForm下使用HttpWebRequest上传文件并显示进度