1. 程式人生 > >使用簡單的wcf檔案實現上傳,下載檔案到伺服器

使用簡單的wcf檔案實現上傳,下載檔案到伺服器

    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