Extjs+Asp.net实现上传大文件带实时进度条

 主要是为了记录自己的学习过程,整理自己的思路以便以后的学习。

首先先说一下整体的思路。

我门都知道,asp自带的上传文件是先将上传的文件整个读取到内存然后在写入磁盘的。如果文件很大的话,上传时就会出现页面停滞,没有任何反映。用户根本不知道页面在做什么,也不知道是否在上传,上传了多少?这样的用户体验是很差的。

所以我门需要实现一个进度条来反映文件上传的进度,可以反映文件写入的进度。具体的思路是通过asp.net提供的HttpModule(Http模块)中的init方法内订阅各种应用程序事件(如BeginRequest事件和EndRequest事件),而Application.BeginRequest事件始终是http请求处理期间第一个发生的事件。我门要做的就是在BefionRequest事件中截取上传请求,然后做文件分块上传,就可以获得文件上传的进度了。

然后我们建一步一步来完成这个功能吧。

1.要写module类必须先配置web.config。注册模块

  在web.config中的<System.Web>节中添加模块:

格式为

<httpModules>   
          <add name="modulename" type="classname,assemblyname" />      
    </httpModules>   

  根据上面的格式我配置的节:

  <httpModules>   
         <add name="MyHttpModule1" type="MyHttpModule" />      
  </httpModules>

2.然后根据配置的模块创建一个相同的类MyHttpModule.

     注意这个类必须实现IHttpModule接口,这样才能实现HttpModule的基本功能。然后在类中添加模块的初始化事件和处理事件。

public void Dispose()
{
  }

public void Init(HttpApplication application)
{

//订阅我门需要的事件

//订阅BeginRequest事件

application.BegionRequest+=new EventHandler(this.Aplication_BeginRequest);
   }

3.添加事件void Application_BeginRequest(object sender, EventArgs e)

  //在这写代码实现我门需要的功能

1. 首先先要判断是否为上传文件

  因为需要上传文件的FORM表单都必须设置FORM表彰中的enctype属性为multipart/form-data(如果我们使用 FileUpload组件,则会在编译时自动替我们加上这个属性)。所以我们只需要判断HTTP请求头的ContentType值是否为 multipart/form-data即可,如果不是,我们就没必要对该请求进行处理了。
      enctype="multipart/form-data实际上是一种编码规范(默认的话是application/x-www-form- urlencoded,该方式不适合大块二进制数据传输),该编码方式的基本思想就是用分隔符来分隔数据项,分隔符如“-----------------------------7d87d1cc0a88”。

  1. 2.  获取HTTP请求总长度和HttpWorkerRequest对象

通过获取HttpApplication.Request.ContentLength属性便可获取HTTP请求内容的总长度,以便我们后来的使用。再声明一个具体的当前Http请求实例

IServiceProvider provider = (IServiceProvider)HttpContext.Current;

            HttpWorkerRequest request = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));

 4. 分块读取请求并存储数据。

使用HttpWorkerRequest.GetPreloadedEntityBody()方法第一次获取Http请求部分。HttpWorkerRequest.ReadEntityBody()读取剩余数据。

while (iLeave > iReadStepSize && request.IsClientConnected())
//首先判断剩余的请求大小是否大于iReadStepSize

    iRead = request.ReadEntityBody(bReadStepByte, iReadStepSize);   /*读取最大字节数为iReadStepSize的用户请求到bReadStepByte数组中*/     

    对文件内容的处理

      iLeave -= iRead;
    }
    if (iLeave > 0 && request.IsClientConnected())
        {    iRead = request.ReadEntityBody(bReadStepByte, iLeave);

  /*最后还剩一部分,因为小于iReadStepSize,所以写在循环外*/
   
      对文件内容的处理
}

我们真正需要上传的部分是文件内容部分。而第一次读取的内容是包括请求头等内容的。我门需要把文件内容给截取出来。

01 -----------------------------7d87d1cc0a88
 02 Content-Disposition: form-data; name="tbVideoName"
 03
 04 vnm
 05 -----------------------------7d87d1cc0a88
 06 Content-Disposition: form-data; name="file"; filename="C:Documents and Settingsstg609妗岄潰浣冲彞.txt"
 07 Content-Type: text/plain
 08
 09 这里是我上传的文本内容
 10 -----------------------------7d87d1cc0a88
 11 Content-Disposition: form-data; name="__EVENTVALIDATION"
 12
 13 /wEWBgK0g/7JCQLrqYKOBgKj5pr/CAKBmOPQBQLY14yNBQKmmtpNX1cOVXyqN8xEER3ZXbnXzsUwVVo=
 14 -----------------------------7d87d1cc0a88--

(09)行就是我门需要的文件内容。

5.获得上传进度。

   1.首先需要在上传也面声明一个隐藏域保存一个全局唯一的UploadID。这个变量相当于一个标志。只要获得这个标志就可以操作获得上传的进度。

2.写一个类来保存进度。然后将这个类保存到cahce中。以UploadID作为cache的key。

3.使用AJAX的XmlHttpRequest对象来想服务器发送异步请求。