广

ASP.NET

  • IOS开发
  • android开发
  • PHP编程
  • JavaScript
  • ASP.NET
  • ASP编程
  • JSP编程
  • Java编程
  • 易语言
  • Ruby编程
  • Perl编程
  • AJAX
  • 正则表达式
  • C语言
  • 编程开发

    asp.net下实现支持文件分块多点异步上传的 Web Services

    2018-05-07 10:25:01 次阅读 稿源:互联网
    广告
    本文的客户端应用程序不包括 ASP.Net Web 应用程序!

    本文假设 URL: http://localhost/mywebservices/updownload.asmx

    共有 4 个程序文件 (Web.Config 就不赘述了)

    Server Side: 

    标题中所提到的 "异步" 其实在服务器端的程序并没有什么特殊的,而主要是通过客户端应用程序
    异步调用相关 Web Method 实现的!

    1. updownload.asmx ,位于 IIS 的某个 Web 共享目录,代码如下,只有一句话:

    <%@ WebService Language="c#" Codebehind="UpDownLoad.asmx.cs" Class="Service1" %>

    2. updownload.asmx.cs ,即: updownload.asmx 的 Codebehind ,位于 IIS 的某个 Web 共享目录的 bin 子目录下,代码如下:

    /*

    本文件位于 Web 共享目录的 bin 子目录下,通过执行如下命令行编译:
    csc /t:library updownload.asmx.cs

    */
    using System.Diagnostics;
    using System.Web;
    using System.Web.Services;
    using System.IO;
    using System;

    public class Service1 : System.Web.Services.WebService
    {
     [WebMethod]
     public string HelloWorld()
     {
      return "Hello World";
     }

     //从 Web Method 本身,其实看不出 "同步" 还是 "异步"
     [WebMethod(Description = "为了支持多点分块异步上传文件,此方法必须由客户端预先调用,以便在服务器端生成指定 FileName 和 Length 大小的空白文件预定空间! 建议客户端同步调用")]
     public string CreateBlankFile(string FileName,int Length) //建议由客户端同步调用
     {
      FileStream fs = new FileStream(Server.MapPath(".") + "//" + FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
      fs.Write(new byte[Length], 0, Length);
      fs.Close();
      fs = null;
      return FileName + " (" + Length + ") 空白文件已经创建!";
     }

     [WebMethod(Description = "提供一个用于一次完整上传整个文件的方法! 建议客户端同步调用")]
     public string UploadFileBytes(byte[] Bytes,string FileName)
     {
      return UploadFileChunkBytes(Bytes, 0, FileName);
     }

     [WebMethod(Description = "提供一个用于一次只上传由 Position 位置起始的, Bytes 字节的 FileName 文件块存入服务器端相应文件的相应字节位置! 建议客户端异步调用")]
     // 这里只要多提供一个 Position 参数,余下的再由客户端调用异步的该方法,就轻松达到目的了!
     public string UploadFileChunkBytes(byte[] Bytes,int Position,string FileName)
     {
      try
      {
       FileStream fs = new FileStream(Server.MapPath(".") + "//" + FileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
       //该 Bytes 的字节要写到 服务器端 相应文件的从 Position 开始的字节
       fs.Position = Position;
       fs.Write(Bytes, 0, Bytes.Length);
       fs.Close();
       fs = null;
       return FileName + " 文件块: 位置[" + Position + "," + (Position + Bytes.Length) + "] 大小(" + Bytes.Length + ") 上传成功!";
      }
      catch (Exception e)
      {
       return e.Message;
      }
     }

     [WebMethod]
     public byte[] DownloadFileBytes(string FileName)
     {
      if (File.Exists(FileName))
      {
       try
       {
        FileStream fs = File.OpenRead(FileName);
        int i = (int) fs.Length;
        byte[] ba = new byte[i];
        fs.Read(ba,0,i);
        fs.Close();
        return ba;
       }
       catch
       {
        return new byte[0];
       }
      }
      else
      {
       return new byte[0];
      }
     }
    }


    //=======================================================================

    Client Side:
    3. UpDownloadProxy.cs :
     本文件由如下命令生成
     % Visual Studio .Net 2003 安装目录下的 %/SDK/v1.1/Bin/wsdl.exe
     具体命令行如下:
     wsdl.exe /l:CS /out:UpDownloadProxy.cs http://localhost/MyWebServices/updownload.asmx?wsdl
     生成的本地的客户端代理类代码里已经为每个 Web Method 生成了可异步和同步执行的方法,例如:
        public string HelloWorld() {}
        public System.IAsyncResult BeginHelloWorld(...) {}
        public string EndHelloWorld(...) {}

     下面是该命令行生成的完整的 UpDownloadProxy.cs 代码,就不修改了:
    /*

    通过执行如下命令行编译,生成 UpDownloadProxy.dll :
    csc /t:library UpDownloadProxy.cs

    */

    //------------------------------------------------------------------------------
    // <autogenerated>
    //     This code was generated by a tool.
    //     Runtime Version: 1.1.4322.573
    //
    //     Changes to this file may cause incorrect behavior and will be lost if 
    //     the code is regenerated.
    // </autogenerated>
    //------------------------------------------------------------------------------

    // 
    // 此源代码由 wsdl, Version=1.1.4322.573 自动生成。
    // 
    using System.Diagnostics;
    using System.Xml.Serialization;
    using System;
    using System.Web.Services.Protocols;
    using System.ComponentModel;
    using System.Web.Services;


    /// <remarks/>
    [System.Diagnostics.DebuggerStepThroughAttribute()]
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Web.Services.WebServiceBindingAttribute(Name="Service1Soap", Namespace="http://tempuri.org/")]
    public class Service1 : System.Web.Services.Protocols.SoapHttpClientProtocol {

        /// <remarks/>
        public Service1() {
            this.Url = "http://localhost/MyWebServices/updownload.asmx";
        }

        /// <remarks/>
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/HelloWorld", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        public string HelloWorld() {
            object[] results = this.Invoke("HelloWorld", new object[0]);
            return ((string)(results[0]));
        }

        /// <remarks/>
        public System.IAsyncResult BeginHelloWorld(System.AsyncCallback callback, object asyncState) {
            return this.BeginInvoke("HelloWorld", new object[0], callback, asyncState);
        }

        /// <remarks/>
        public string EndHelloWorld(System.IAsyncResult asyncResult) {
            object[] results = this.EndInvoke(asyncResult);
            return ((string)(results[0]));
        }

        /// <remarks/>
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/CreateBlankFile", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        public string CreateBlankFile(string FileName, int Length) {
            object[] results = this.Invoke("CreateBlankFile", new object[] {
                        FileName,
                        Length});
            return ((string)(results[0]));
        }

        /// <remarks/>
        public System.IAsyncResult BeginCreateBlankFile(string FileName, int Length, System.AsyncCallback callback, object asyncState) {
            return this.BeginInvoke("CreateBlankFile", new object[] {
                        FileName,
                        Length}, callback, asyncState);
        }

        /// <remarks/>
        public string EndCreateBlankFile(System.IAsyncResult asyncResult) {
            object[] results = this.EndInvoke(asyncResult);
            return ((string)(results[0]));
        }

        /// <remarks/>
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/UploadFileBytes", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        public string UploadFileBytes([System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] System.Byte[] Bytes, string FileName) {
            object[] results = this.Invoke("UploadFileBytes", new object[] {
                        Bytes,
                        FileName});
            return ((string)(results[0]));
        }

        /// <remarks/>
        public System.IAsyncResult BeginUploadFileBytes(System.Byte[] Bytes, string FileName, System.AsyncCallback callback, object asyncState) {
            return this.BeginInvoke("UploadFileBytes", new object[] {
                        Bytes,
                        FileName}, callback, asyncState);
        }

        /// <remarks/>
        public string EndUploadFileBytes(System.IAsyncResult asyncResult) {
            object[] results = this.EndInvoke(asyncResult);
            return ((string)(results[0]));
        }

        /// <remarks/>
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/UploadFileChunkBytes", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        public string UploadFileChunkBytes([System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")] System.Byte[] Bytes, int Position, string FileName) {
            object[] results = this.Invoke("UploadFileChunkBytes", new object[] {
                        Bytes,
                        Position,
                        FileName});
            return ((string)(results[0]));
        }

        /// <remarks/>
        public System.IAsyncResult BeginUploadFileChunkBytes(System.Byte[] Bytes, int Position, string FileName, System.AsyncCallback callback, object asyncState) {
            return this.BeginInvoke("UploadFileChunkBytes", new object[] {
                        Bytes,
                        Position,
                        FileName}, callback, asyncState);
        }

        /// <remarks/>
        public string EndUploadFileChunkBytes(System.IAsyncResult asyncResult) {
            object[] results = this.EndInvoke(asyncResult);
            return ((string)(results[0]));
        }

        /// <remarks/>
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/DownloadFileBytes", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        [return: System.Xml.Serialization.XmlElementAttribute(DataType="base64Binary")]
        public System.Byte[] DownloadFileBytes(string FileName) {
            object[] results = this.Invoke("DownloadFileBytes", new object[] {
                        FileName});
            return ((System.Byte[])(results[0]));
        }

        /// <remarks/>
        public System.IAsyncResult BeginDownloadFileBytes(string FileName, System.AsyncCallback callback, object asyncState) {
            return this.BeginInvoke("DownloadFileBytes", new object[] {
                        FileName}, callback, asyncState);
        }

        /// <remarks/>
        public System.Byte[] EndDownloadFileBytes(System.IAsyncResult asyncResult) {
            object[] results = this.EndInvoke(asyncResult);
            return ((System.Byte[])(results[0]));
        }
    }

    //=======================================================================
    4. UpDownloadClient.cs :
     该程序才是真正实现文件分块多点异步上传的核心代码:

    /*

    通过执行如下命令行编译:
    csc updownloadClient.cs /r:updownloadproxy.dll

    */
    using System;
    using System.IO;

    public class Class1
    {
     static void Main(string[] args)
     {
      //Download(ServerSidepath, ClientSidePath)
      Download(@"e:/test.jpg", @"f:/test_local.jpg");
      System.Console.WriteLine("down End");

      System.Console.WriteLine("同步 up file exec ...");
      UploadFile(@"e:/Northwind.mdb");
      System.Console.WriteLine("同步 up file End/n");

      System.Console.WriteLine("异步 up chunks exec ...");
      UploadFileChunks(@"e:/test.rar", 64);
      System.Console.ReadLine();
     }

     public static void UploadFile(string LocalFileName)
     {
      Service1 xx = new Service1();
      FileStream fs = new FileStream(LocalFileName, FileMode.Open); //Client Side Path
      byte[] buffer = new byte[fs.Length];
      fs.Read(buffer, 0, buffer.Length);
      //调用 "同步执行" 的本地 Web Sevices 代理类的 方法,相当于同步调用了 Web Method !
      xx.UploadFileBytes(buffer, System.IO.Path.GetFileName(LocalFileName));
     }

     //指定要上传的本地文件的路径,及每次上传文件块的大小
     public static void UploadFileChunks(string LocalFileName,int ChunkSize)
     {
      Service1 xx = new Service1();
      string filename = System.IO.Path.GetFileName(LocalFileName);

      FileStream fs = new FileStream(LocalFileName, FileMode.Open); //Client Side Path
      //fs = File.OpenRead(LocalFileName);

      int r = (int) fs.Length; //用于记录剩余还未上传的字节数,初值是文件的大小

      //调用 "同步执行" 的本地 Web Sevices 代理类的 方法,相当于同步调用了 Web Method !
      //预定服务器端空间
      xx.CreateBlankFile(filename,r);
      int size = ChunkSize * 1024;
      int k = 0; //用于记录已经上传的字节数
      i++; //用于记录上传的文件块数
      while (r >= size)
      {
       byte[] buffer = new byte[size];
       fs.Read(buffer,0,buffer.Length);
       //调用 "异步执行" 的本地 Web Sevices 代理类的 方法,相当于异步调用了 Web Method !
       //该 buffer 的字节要写到 服务器端 相应文件的从 Position = k 开始的字节
       xx.BeginUploadFileChunkBytes(buffer,k,filename,new AsyncCallback(UploadFileChunkCallback),xx);
       k += size;
       r -= size;
       i++;
      }
      if (r > 0) //剩余的零头
      {
       byte[] buffer = new byte[r];
       fs.Read(buffer,0,buffer.Length);
       //调用 "异步执行" 的本地 Web Sevices 代理类的 方法,相当于异步调用了 Web Method !
       //该 buffer 的字节要写到 服务器端 相应文件的从 Position = k 开始的字节
       xx.BeginUploadFileChunkBytes(buffer,k,filename,new AsyncCallback(UploadFileChunkCallback),xx);
       i++;
      }
      fs.Close();

     }

     private static int i = -1; //用于记录上传的文件块数

     private static void UploadFileChunkCallback(IAsyncResult ar)
     {
      Service1 x = (Service1) ar.AsyncState;
      Console.WriteLine(x.EndUploadFileChunkBytes(ar));
      if ( --i == 0)
      {
       Console.WriteLine("异步 up all chunks end");
      }
     }

     public static void Download(string ServerSideFileName,string LocalFileName)
     {
      Service1 xx = new Service1();
      byte[] ba = xx.DownloadFileBytes(ServerSideFileName); //Server Side Path

      FileStream fs = new FileStream(LocalFileName, FileMode.Create); //Client Side Path
      fs.Write(ba,0,ba.Length);
      fs.Close();
     }
    }


    //===========================================================================
    至此我们通过纯手工的方式完成了任务,之所以不用 VS 就是为了让码子简洁明了!
    Microshaoft .Night 就是这么平易近人! (PMPMP to MS)
    通过 Web Sevices 上传文件非常简单,甚至比传统的 http Web 上传还简单!
    同时较轻松地就实现了文件分块多点异步上传:
    Server 端代码没啥特殊的!
    Client 端代码稍微复杂些!

    一起学吧部分文章转载自互联网,供读者交流和学习,若有涉及作者版权等问题请及时与我们联系,以便更正、删除或按规定办理。感谢所有提供资讯的网站,欢迎各类媒体与一起学吧进行文章共享合作。

    广告
    广告
    广告