使用简单的wcf文件实现上传,下载文件到服务器
2014-02-10 16:27
1036 查看
wcf是微软开发出的用户数据通信的app接口,在.net framework3.0中与wpf,wf一同集成,是.net框架的一部分。
具体请参见点击打开链接。
本文主要讲述了使用wcf服务契约来进行文件或者数据的服务器上传或者下载工作,使用的工具为vs2012(使用过程中发现了不少bug)。WCF是以契约来规定通信双方的沟通协议。双方必须定义相同的协议绑定才能实现沟通。本文使用基本的http支持,也就是basicHttpBinding。看具体步骤
1:搭建服务器,添加ServiceFile.svc文件
添加成功后,会在项目中增加一个该服务类对应的一个接口,IServiceFile,这个接口中定义的未实现方法就是将来要实现的服务代码,也是契约的定义声明,这里使用操作契约。
定义的接口代码:
ServiceInfo.svc实现:
服务端协议:
并成功部署到IIS(本文IIS版本为8.0),创建过程中创建存放上传文件的文件夹。
2:创建客户端项目看界面:
其实就三个操作,选择文件,上传文件,下载文件。
1:选择文件,最简单的弹出框选择文件,使用OpenFileDialog。
2:上传文件,使用的是独立线程。
定义客户端协议
客户端:
上传代码:
3:下载文件 使用WebRequest,WebResponse对象获取Internet相应数据流大小,使用FileStream保存文件。下载使用了多线程。
下载代码:
4:Helper类代码
经过测试,本地局域网可以上传<=2G的文件。应该可以满足需求。
下载成功图:
下载的时候对于选择文件名称有严格的要求,如果你的文件包含特殊字符或者其它wcf服务解析不了的字符,就会出现 404 not found 错误。
总结:继续努力工作,努力学习。
源码地址:WCF
具体请参见点击打开链接。
本文主要讲述了使用wcf服务契约来进行文件或者数据的服务器上传或者下载工作,使用的工具为vs2012(使用过程中发现了不少bug)。WCF是以契约来规定通信双方的沟通协议。双方必须定义相同的协议绑定才能实现沟通。本文使用基本的http支持,也就是basicHttpBinding。看具体步骤
1:搭建服务器,添加ServiceFile.svc文件
添加成功后,会在项目中增加一个该服务类对应的一个接口,IServiceFile,这个接口中定义的未实现方法就是将来要实现的服务代码,也是契约的定义声明,这里使用操作契约。
定义的接口代码:
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IServiceFile”。 [ServiceContract] public interface IServiceFile { /// <summary> /// 上传操作 /// </summary> /// <param name="fileInfo"></param> /// <returns></returns> [OperationContract] CustomFileInfo UpLoadFileInfo(CustomFileInfo fileInfo); /// <summary> /// 获取文件操作 /// </summary> /// <param name="fileName"></param> /// <returns></returns> [OperationContract] CustomFileInfo GetFileInfo(string fileName); } /// <summary> /// 自定义文件属性类 /// </summary> [DataContract] public class CustomFileInfo { /// <summary> /// 文件名称 /// </summary> [DataMember] public string Name { get; set; } /// <summary> /// 文件大小 /// </summary> [DataMember] public long Length { get; set; } /// <summary> /// 文件偏移量 /// </summary> [DataMember] public long OffSet { get; set; } /// <summary> /// 发送的字节 /// </summary> [DataMember] public byte[] SendByte { get; set; } }
ServiceInfo.svc实现:
// 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码、svc 和配置文件中的类名“ServiceFile”。 // 注意: 为了启动 WCF 测试客户端以测试此服务,请在解决方案资源管理器中选择 ServiceFile.svc 或 ServiceFile.svc.cs,然后开始调试。 public class ServiceFile : IServiceFile { public CustomFileInfo UpLoadFileInfo(CustomFileInfo fileInfo) { // 获取服务器文件上传路径 string fileUpLoadPath = System.Web.Hosting.HostingEnvironment.MapPath("~/UpLoadFile/"); // 如需指定新的文件夹,需要进行创建操作。 Console.WriteLine("1"); // 创建FileStream对象 FileStream fs = new FileStream(fileUpLoadPath + fileInfo.Name, FileMode.OpenOrCreate); Console.WriteLine("2"); long offSet = fileInfo.OffSet; // 使用提供的流创建BinaryWriter对象 var binaryWriter = new BinaryWriter(fs, Encoding.UTF8); binaryWriter.Seek((int)offSet, SeekOrigin.Begin); binaryWriter.Write(fileInfo.SendByte); fileInfo.OffSet = fs.Length; fileInfo.SendByte = null; binaryWriter.Close(); fs.Close(); Console.WriteLine("2"); return fileInfo; } public CustomFileInfo GetFileInfo(string fileName) { string filePath = System.Web.Hosting.HostingEnvironment.MapPath("~/UpLoadFile/") + fileName; if (File.Exists(filePath)) { var fs = new FileStream(filePath, FileMode.OpenOrCreate); CustomFileInfo fileInfo = new CustomFileInfo { Name = fileName, OffSet = fs.Length, }; fs.Close(); return fileInfo; } return null; }
服务端协议:
<span style="font-size:18px;"> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="FileTransferServicesBinding" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" transferMode="Streamed" messageEncoding="Mtom" sendTimeout="01:30:00"> <readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" maxBytesPerRead="2147483647"/> </binding> </basicHttpBinding> </bindings> <services> <service behaviorConfiguration="WebApplication1.ServiceFileBehavior" name="WebApplication1.ServiceFile"> <endpoint address="" binding="basicHttpBinding" bindingConfiguration="FileTransferServicesBinding" contract="WebApplication1.IServiceFile"> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" /> </service> </services> <behaviors> <serviceBehaviors> <behavior name="WebApplication1.ServiceFileBehavior"> <dataContractSerializer maxItemsInObjectGraph="2147483647"/> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> <system.webServer> <modules runAllManagedModulesForAllRequests="true"></modules> </system.webServer></span>
并成功部署到IIS(本文IIS版本为8.0),创建过程中创建存放上传文件的文件夹。
2:创建客户端项目看界面:
其实就三个操作,选择文件,上传文件,下载文件。
1:选择文件,最简单的弹出框选择文件,使用OpenFileDialog。
2:上传文件,使用的是独立线程。
定义客户端协议
客户端:
<?xml version="1.0"?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_IServiceFile" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" maxBufferPoolSize="2147483647" transferMode="Streamed" messageEncoding="Mtom"> <readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" maxBytesPerRead="2147483647"/> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="http://10.0.30.98:8001/ServiceFile.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IServiceFile" contract="ULF.IServiceFile" name="BasicHttpBinding_IServiceFile" /> </client> </system.serviceModel> </configuration>
上传代码:
string filePath = this.txtFileName.Text; BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += worker_DoWork; worker.WorkerReportsProgress = true; worker.ProgressChanged += worker_ProgressChanged; worker.RunWorkerCompleted += worker_RunWorkerCompleted; worker.RunWorkerAsync(filePath);
#region 独立线程 /// <summary> /// 进度条更改 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) { if (progressBar.InvokeRequired) { progressBar.Invoke((ThreadStart)delegate { progressBar.Value = e.ProgressPercentage; }); } else { progressBar.Value = e.ProgressPercentage; progressBar.Update(); } } /// <summary> /// 执行操作完成 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { if ((bool)e.Result == false) { } else { if (this.InvokeRequired) { this.Invoke((ThreadStart)delegate { MessageBox.Show("上传成功"); }); } else { MessageBox.Show("上传成功"); } } if (progressBar.InvokeRequired) { progressBar.Invoke((ThreadStart)delegate { progressBar.Value = 0; }); } else { progressBar.Value = 0; } if (txtFileName.InvokeRequired) { txtFileName.Invoke((ThreadStart)delegate { this.txtFileName.Clear(); }); } else { this.txtFileName.Clear(); } if (this.btnUpload.InvokeRequired) { this.btnUpload.Invoke((ThreadStart)delegate { this.btnUpload.Enabled = true; }); } else { this.btnUpload.Enabled = true; } } void worker_DoWork(object sender, DoWorkEventArgs e) { string path = e.Argument.ToString(); System.IO.FileInfo fileInfoIO = new System.IO.FileInfo(path); // 要上传的文件地址 FileStream fs = File.OpenRead(fileInfoIO.FullName); // 实例化服务客户的 ServiceFileClient client = new ServiceFileClient(); try { int maxSiz = 1024 * 100; // 根据文件名获取服务器上的文件 CustomFileInfo file = client.GetFileInfo(fileInfoIO.Name); if (file == null) { file = new CustomFileInfo(); file.OffSet = 0; } file.Name = fileInfoIO.Name; file.Length = fs.Length; if (file.Length == file.OffSet) //如果文件的长度等于文件的偏移量,说明文件已经上传完成 { MessageBox.Show("该文件已存在"); e.Result = false; // 设置异步操作结果为false } else { while (file.Length != file.OffSet) { file.SendByte = new byte[file.Length - file.OffSet <= maxSiz ? file.Length - file.OffSet : maxSiz]; //设置传递的数据的大小 fs.Position = file.OffSet; //设置本地文件数据的读取位置 fs.Read(file.SendByte, 0, file.SendByte.Length);//把数据写入到file.Data中 file = client.UpLoadFileInfo(file); //上传 //int percent = (int)((double)file.OffSet / (double)((long)file.Length)) * 100; int percent = (int)(((double)file.OffSet / (double)((long)file.Length)) * 100); (sender as BackgroundWorker).ReportProgress(percent); } // 移动文件到临时目录(此部分创建可以使用sqlserver数据库代替) string address = string.Format(@"{0}\{1}", Helper.ServerFolderPath, file.Name); fileInfoIO.CopyTo(address, true); LoadUpLoadFile(); // 上传成功重新加载文件 e.Result = true; } } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { fs.Close(); fs.Dispose(); client.Close(); client.Abort(); } } /// <summary> /// 选择文件对话框 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void button2_Click(object sender, EventArgs e) { OpenFileDialog dialog = new OpenFileDialog(); dialog.InitialDirectory = "C:"; //dialog.Multiselect = true; //dialog.Filter = ""; if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) { return; } this.txtFileName.Text = dialog.FileName; } #endregion
3:下载文件 使用WebRequest,WebResponse对象获取Internet相应数据流大小,使用FileStream保存文件。下载使用了多线程。
下载代码:
Thread downLoadThread = new Thread(new ThreadStart(DownLoadFile)); downLoadThread.IsBackground = true; downLoadThread.SetApartmentState(ApartmentState.STA); downLoadThread.Name = "downLoadThreade"; downLoadThread.Start(); #region 下载多线程 private void DownLoadFile() { // 测试使用 //string fileFullpath = "http://localhost:29700//UpLoadFile"; string fileFullpath = Helper.ServerFilePath; // 获得DataGridView选中行 DataGridViewRow selectedRow = this.dgvFiles.SelectedRows[0]; string fileName = selectedRow.Cells[0].Value.ToString(); // 文件名称 SaveFileDialog sfd = new SaveFileDialog(); sfd.InitialDirectory = "C:"; sfd.FileName = fileName; if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { fileFullpath += string.Format("//{0}", fileName); WebRequest request = WebRequest.Create(fileFullpath); WebResponse fs = null; try { fs = request.GetResponse(); } catch (Exception ex) { MessageBox.Show(ex.Message); } long contentLength = fs.ContentLength; if (pbDownLoad.InvokeRequired) { pbDownLoad.Invoke((ThreadStart)delegate { pbDownLoad.Maximum = (int)contentLength; }); } Stream st = fs.GetResponseStream(); try { byte[] byteLength = new byte[contentLength]; int allByte = (int)contentLength; int startByte = 0; while (contentLength > 0) { int downByte = st.Read(byteLength, startByte, allByte); if (downByte == 0) { break; } startByte += downByte; // 计算下载进度 //int percent = (int)(((double)startByte / ((long)(double)allByte)) * 100); //(sender as BackgroundWorker).ReportProgress(percent); if (pbDownLoad.InvokeRequired) { pbDownLoad.Invoke((ThreadStart)delegate { pbDownLoad.Value = startByte; }); } allByte -= downByte; } // 保存路径 string downLoadPath = sfd.FileName; FileStream stream = new FileStream(downLoadPath, FileMode.OpenOrCreate, FileAccess.Write); stream.Write(byteLength, 0, byteLength.Length); stream.Close(); fs.Close(); } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { st.Close(); st.Dispose(); request.Abort(); Thread.Sleep(500); MessageBox.Show("下载成功"); if (pbDownLoad.InvokeRequired) { pbDownLoad.Invoke((ThreadStart)delegate { pbDownLoad.Maximum = 0; }); } } } #endregion
4:Helper类代码
public static class Helper { public static string ServerFilePath { get { // 获取客户端中定义的服务器地址 ClientSection clientSection = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection; if (clientSection == null) { return ""; } ChannelEndpointElementCollection collection = clientSection.Endpoints; Uri uri = collection[0].Address; return "http://" + uri.Authority + "//UpLoadFile"; } } /// <summary> /// 服务器存放文件的文件夹地址 /// </summary> public static string ServerFolderPath { //get { return @"E:\WCFCESHI1\UpLoadFile"; } get { return @"C:\Test"; } } }上传成功图:
经过测试,本地局域网可以上传<=2G的文件。应该可以满足需求。
下载成功图:
下载的时候对于选择文件名称有严格的要求,如果你的文件包含特殊字符或者其它wcf服务解析不了的字符,就会出现 404 not found 错误。
总结:继续努力工作,努力学习。
源码地址:WCF
相关文章推荐
- springmvc文件上传下载简单实现案例(ssm框架使用)
- 使用jsp/servlet简单实现文件上传与下载
- 【转载】使用jsp实现文件上传到服务器或者从服务器上下载文件到本地计算机完整说明版
- Windows下配置ftp服务器,使用QT实现文件上传和下载
- springmvc文件上传下载简单实现案例(ssm框架使用)
- springmvc文件上传下载简单实现案例(ssm框架使用)
- Openssh服务器的搭建,并使用PSFTP实现文件自动上传,下载的script命令
- 简单实现的自定义圆环进度条,可使用于文件的上传下载图片加载等地方.
- 使用asp.net mvc3实现简单的文件上传与下载
- 使用jsp/servlet简单实现文件上传与下载
- 【转载】使用jsp实现文件上传到服务器或者从服务器上下载文件到本地计算机完整说明版
- 使用Struts2实现简单的文件上传和下载
- springmvc文件上传下载简单实现案例(ssm框架使用)
- 使用Struts2简单的基本文件上传下载实现
- 使用jsp/servlet实现文件上传与下载
- 使用SFTP实现Linux上文件上传下载
- 使用JSP+Servlet实现文件上传下载
- Java Web实现使用浏览器从服务器下载文件(后台)
- 使用Paramiko实现SSH登陆,文件上传下载
- java 简单的文件上传下载服务器模型(NIO 版本)