最开始用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,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,context.Length); sfile.Write(context,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,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,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中使用wcf上传文件并实时显示进度全部内容,希望文章能够帮你解决【分享】 在silverlight中使用wcf上传文件并实时显示进度所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)