使用简单的wcf文件实现上传,下载文件到服务器

2023-05-16

    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



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用简单的wcf文件实现上传,下载文件到服务器 的相关文章

  • WCF 模拟和 SQL 可信连接?

    我们有一个托管在 IIS7 下的服务 SQL 服务器的连接字符串设置为 受信任 为了进行身份验证 我需要在服务上设置模拟并让客户端启动模拟连接 有没有办法不设置模拟并仍然允许服务通过可信连接登录到 SQL Server 我们希望避免让客户端
  • WCF:Per-Call 和 Per-Session 服务...需要说服 Per-Call 是值得的

    我们目前正在审查 WCF 服务设计 困扰我的一件事是 Per Call 和 Per Session 服务之间的决定 我相信我理解两者背后的概念 但我并没有真正看到按呼叫服务的优势 我知道使用 Per Call 服务的动机是 WCF 服务仅在
  • 如何研究.NET 中的非托管内存泄漏?

    我有一个通过 MSMQ 运行的 WCF 服务 内存随着时间的推移逐渐增加 表明存在某种内存泄漏 我在本地运行该服务并使用 PerfMon 监视一些计数器 CLR 内存托管堆字节总数保持相对恒定 而进程的私有字节随着时间的推移而增加 这让我相
  • WCF 数据契约/序列化

    我创建了一个简单的 WCF 应用程序 它公开一个操作 此操作采用复合数据类型作为参数 我没有用 DataContract 属性修饰这个复合数据类型 但这是有效的 我可以在 WSDL 中看到它的架构 现在我的理解是 这个新的自定义类型应该用
  • 优雅地终止 WCF 服务 - 完成所有打开的会话并限制新会话

    我有一个我编写的 WCF 服务 它托管在 Windows 服务中 它以 PerSession 模式运行 该服务允许客户端通过该服务远程打开文件 更改文件以及关闭文件 到目前为止一切工作都非常顺利 当 Windows 服务停止时 我希望能够让
  • 带有 WCF BadContextToken 的 PHP Soap 客户端

    经过几天的谷歌 in 尝试 脱发 我仍然找不到解决方案 所以请帮助 简短信息 我需要使用 PHP SOAP 客户端 的 WCF 服务 它使用 wsHttpBinding ws security 并且无法设置 basicHttpBinding
  • 将 fetch 与 Content-Type 结合使用时出现 CORS 错误 [重复]

    这个问题在这里已经有答案了 我正在尝试从 FireFox 中的不同域向 REST Web 服务发送 POST 请求 我为此使用 JavaScript 获取 函数 我在 IIS 中托管 REST Web 服务 在我在 JavaScript 中
  • wsdl 文件中的 svcutil:找不到目标命名空间的错误架构

    在我的机器上 我有一个 WSDL 文件和所有必需的架构文件 我正在尝试使用 svcutil 从 WSDL 创建客户端代理代码 命令 svcutil myfile wsdl 我在使用 svcutil 时不断收到错误 但在使用soapUI 加载
  • WCF - 如何增加消息大小配额

    我有一个 WCF 服务 它将 1000 条记录从数据库返回给客户端 我有一个 ASP NET WCF 客户端 我在 asp net Web 应用程序项目中添加了服务引用来使用 WCF 当我运行客户端应用程序时 我收到以下消息 传入消息的最大
  • WCF 回调:它可以与 Java 互操作吗?

    目前 我以 正常 方式实现所有 Web 服务 也就是说 我在 Eclipse 中创建一个 WSDL 文件 然后使用 WSCF blue 一个 Visual Studio 扩展 自动生成必要的代码 它是回复 请求 不过 我希望改用回调 这样我
  • 如何在 REST WCF 服务中接受任意 JSON 对象?

    我想实现这样的服务方法 OperationContract WebInvoke RequestFormat WebMessageFormat Json ResponseFormat WebMessageFormat Json public
  • WCF:在 ServiceModel 客户端配置部分中找不到引用协定“IService”的默认端点元素。当托管在 IIS 中时

    我有一个 WCF 服务托管在 IIS 中 我还有一个 WCF 客户端 控制台应用程序 我用过svcutil构建代理类和配置文件 然后将它们添加到我的客户端项目中 它建造得很好 但是当我尝试运行该程序时 它抛出以下异常 在 ServiceMo
  • 如何防止在 CXF Web 服务客户端中生成 JAXBElement

    我正在尝试使用 CXF 创建一个 Web 服务客户端来使用 WCF Web 服务 当我使用 wsdl2java 时 它生成具有 JAXBElement 类型而不是 String 的对象 我读到有关使用 jaxb bindings xml 文
  • 自定义 WCF DataContractSerializer

    是否可以用我自己的序列化程序替换 Windows Communication Foundation 中的 dataContractSerializer 如果可能的话 我怎样才能实现这一目标 是的 您可以提供自己的序列化器实现 默认情况下 W
  • 我应该何时何地使用 WCF

    我浏览了几个在线教程 其中涵盖了 WCF 的优点 如何构建服务 客户端等 不过 我想了解一点整体情况 问题 gt 什么样的应用程序或应用程序中的哪些功能要求我使用 WCF 功能 一个具体的例子应该可以更好地帮助我 有几种情况 需要 WCF
  • 自定义行为的配置错误

    我创建了一个与 WCF 服务一起使用的自定义行为 以将所有错误记录到应用程序日志中 我做了一个BehaviorExtensionElement对于行为 public ErrorLoggingBehaviorExtensionElement
  • WCF 服务中的“即发即忘”

    我在 Azure 上有很多 WCF REST 服务 在某些 WCF 服务中 我向外部服务调用 Http 请求 例如发送电子邮件 短信 对非关键第三方服务的 http 请求 我不希望这阻碍我对客户电话的响应 需要一些关于在这种情况下使用的模式
  • 如何为本机启用现有 WCF 服务的 JSONP?

    我有一个现有的服务 如下方法 AspNetCompatibilityRequirements RequirementsMode AspNetCompatibilityRequirementsMode Allowed ServiceBehav
  • 如何保证单向方法的可靠性?

    The 关于单向调用 回调和事件您需要了解的信息 http msdn microsoft com en us magazine cc163537 aspx文章讲述 客户端不关心调用结果的事实并不意味着客户端根本不关心调用是否发生 一般来说
  • 如何为新的 Silverlight 应用程序在 WCF、REST、POX 和 RIA 服务之间进行选择

    There a lotSilverlight 应用程序连接回其服务器的不同方式 包括 WCF Windows 通信基础 http msdn microsoft com en us netframework aa663324 aspx RES

随机推荐