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

本文的客户端应用程序不包括 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 端代码稍微复杂些!

(0)

相关推荐

  • asp.net 未能加载文件或程序集“XXX”或它的某一个依赖项。试图加载格式不正确的程序。

    说明: 执行当前 Web 请求期间,出现未处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 异常详细信息: System.BadImageFormatException: 未能加载文件或程序集"XXX"或它的某一个依赖项.试图加载格式不正确的程序. 源错误: 执行当前 Web 请求期间生成了未处理的异常.可以使用下面的异常堆栈跟踪信息确定有关异常原因和发生位置的信息. 程序集加载跟踪: 下列信息有助于确定程序集"XXX"无法加载的

  • asp.net jquery+ajax异步刷新实现示例

    复制代码 代码如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title

  • Asp.net利用JQuery弹出层加载数据代码

    首先我们新建一个网站,在网站里面新增一般处理程序,命名为ReadData.ashx.然后在里面输入如下代码: 复制代码 代码如下: using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Services; using System.Data.SqlClient; //引入命名空间 using System.Data; namespace 加载层 {

  • ASP.NET之自定义异步HTTP处理程序(图文教程)

    一.前言 1.对读者想说的话:(可跳过) 在此我感谢那些看了<ASP.NET之自定义同步HTTP处理程序>这篇文章以及看到了这篇<ASP.NET 之 自定义 异步HTTP处理程序>的亲们.前面的那篇可能看过MSDN的亲们一定会发现很多熟悉的地方.而我其实就是比较详细的介绍了一下,让大家更好的理解 PS:MSDN从头到尾都是文字且文字很统一,恐怕很多人都感觉畏惧,懒的去看,所以我将其重要的部分提取出来,使用易懂的例子和简洁的语言来叙述.当然其中也免不了错误,希望各位亲们可以指出. 2

  • JQuery FlexiGrid的asp.net完美解决方案 dotNetFlexGrid-.Net原生的异步表格控件

    dotNetFlexGrid是一款asp.net原生的异步表格控件,他的前身是Jquery FlexiGrid插件,我们重构了FlexiGrid的大部分Javascript代码,使其工作的更有效率,BUG更少:同时将其封装为dotNet控件,提供了简单易用的使用方式. dotNetFlexGrid扩展和优化了FlexiGrid原有的功能,并提供了更多具有针对性的功能,使用dotNetFlexGrid,您的用户可以轻松拥有如下功能 提供简易的方式自行调整表格列宽 根据实际情况调整表格的大小 针对合

  • asp.net动态加载用户控件,关于后台添加、修改的思考

    看下下面这个典型的后台(比较粗糙):说实在,我很厌倦全部用.aspx文件去做,比如"友情连接"这个模块,就有"添加友情连接""修改友情连接""友情连接列表",简单的话,可以把"添加""修改"合成一个文件.每次都去建立一个.aspx文件.我现在的想法是用"用户控件+配置文件"去实现,虽然文件数目可能不会少很多.但在编程到一定地步,我想大家会有跟我一样的想法. 首先需要涉

  • asp.net+ajaxfileupload.js 实现文件异步上传代码分享

    由于代码很简单,这里就闲话不多说了,直接上代码,小伙伴们自己研读代码就明白了. 前台代码: 复制代码 代码如下: /*修改头像*/      //上传      function _sc() {          $(".ckfile").html("").css("color", "#535353");          $("#_userImgPath").val("");     

  • asp.net+jquery滚动滚动条加载数据的下拉控件

    这样的需求貌似自己感觉不是很合理,因为数据多了如此下拉无论从人还是机器操作都比较痛苦. 没办法由于需求下来了,只能按需求操作.网上找了很多相关控件都感觉有点庞大,占资源比较多.没办法自己花半天时间弄出个半成品自定义控件,拿出来分享下,如有高手看了请多指点. 需求:AJAX滚动滚动条加载数据的下拉列表 控件名称:Webcombo 所用技术:ASP.NET(C#),jQuery,ASP.NET一般处理文件(.ashx) 下拉列表具体实现:用DIV模拟下拉列表,input和图片模拟下拉框.最终结果如下

  • jquery异步调用页面后台方法&#8207;(asp.net)

    复制代码 代码如下: <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="JqueryCSMethodForm.aspx.cs" Inherits="JQuerWeb.JqueryCSMethodForm" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&

  • asp.net下的异步加载

    具体我本身大概用的就有两种,需配合JQ. 第一种,直接通过AJAX去请求页面:例如, 1:dataType必须是html或者Text格式, 2:Type:必须是'Post'请求 3:后台Load事件必须判断是否为Post请求 后台代码如下: 测试结果如下: 第二种:类似于.net MVC直接请求方法. 1:后台代码中,引入using System.Web.Services; 2:方法必须是静态修饰,且方法上面打上特性 [WebMethod] 3:在JQ中返回成功回调函数内获取数据必须是 返回名字

随机推荐