使用簡單的wcf檔案實現上傳,下載檔案到伺服器
阿新 • • 發佈:2018-12-31
wcf是微軟開發出的使用者資料通訊的app介面,在.net framework3.0中與wpf,wf一同整合,是.net框架的一部分。
本文主要講述了使用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