zoukankan      html  css  js  c++  java
  • [导入]SunriseUpload.0.9.1的源码分析(一)

    今天正式开始研究SunriseUpload.0.9.1的源码。

    先看web.config里的内容:
      <!-- Settings of SunriseUpload -->
      <httpRuntime useFullyQualifiedRedirectUrl="true" maxRequestLength="100819200" executionTimeout="900" />
      <httpModules>
       <add name="HttpUploadModule" type="Sunrise.Web.Upload.HttpUploadModule, Sunrise.Web.Upload" />
      </httpModules>
      <httpHandlers>
       <add verb="*" path="progress.ashx" type="Sunrise.Web.Upload.HttpUploadHandler, Sunrise.Web.Upload" />
      </httpHandlers>
      <!-- ========================= -->
    第一个设定是上传文件的最大长度和执行时间。我不知道其它的组件里是怎样处理的,像没有这些设定。
    关键的还是第二个,它表示所有的上传请求都将映射到Sunrise.Web.Upload.HttpUploadModule模块上,这样使得我们自己的上传请求都将失败。所以如果想自己

    测试上传的时候,请注释掉这一设定。
    第三个设定是对进度条的请求,由于ashx的扩展各被IIS映射在aspnet.dll上,所以可以通过httpHeadler将请求拦截,这一功能比httpMoudle小一些,它只对

    progress.ashx的请求进行拦截,当然是里可以用通配符。

    SingleUpload的示例:
    很简单的一些设定:只有一个上传的input(type=file,注意它的value属性是只读的)
    然后一个button,最后是一个表格显示上传后的数据。
      protected Table tbFileList;
      protected Button btnUpload;
      private void btnUpload_Click(object sender, EventArgs e)
      {
       string path = Path.Combine(Server.MapPath("."), "UploadFile");
       if (!Directory.Exists(path))
       {
        Directory.CreateDirectory(path);
       }

       //获取上传文件,"files"是<input type=file>的name属性
       UploadFile uploadFile = UploadHelper.GetUploadFile("file1");

       if(uploadFile != null)
       {
        TableRow tr = new TableRow();
        TableCell[] tc = new TableCell[2] {new TableCell(), new TableCell()};

        tc[0].Text = Path.GetFileName(uploadFile.FileName);
        tc[1].Text = uploadFile.ContentLength.ToString("###,###") + " K bytes";
        tr.Cells.AddRange(tc);
        tbFileList.Rows.Add(tr);

        //Save file
        uploadFile.SaveAs(Path.Combine(path, Path.GetFileName(uploadFile.FileName)));
       }
      }
    去掉细节,可以简化到:
      private void btnUpload_Click(object sender, EventArgs e)
      {
       string path = Path.Combine(Server.MapPath("."), "UploadFile");
       //获取上传文件,"files"是<input type=file>的name属性
       UploadFile uploadFile = UploadHelper.GetUploadFile("file1");
       if(uploadFile != null)
       {
        uploadFile.SaveAs(Path.Combine(path, Path.GetFileName(uploadFile.FileName)));
       }
      }
    这里使用用了UploadHelper的静态成员函数,GetUpladFile,我觉得这不是一个好的做法,所以其它的组件里都改掉了这一做法。
    下面我们就去看看UploadHelper类。

    UploadHelper类有点长,近500行的代码。先看看核心函数:GetUploadFile()
      public static UploadFile GetUploadFile(string name)
      {
       UploadFile uploadFile = new UploadFile(name);

       return (uploadFile.FilePath == string.Empty) ? null : uploadFile;
      }
    呵呵,比想像的简单得多吧!!!接下来就又要看UploadFile类了!

    UploadFile类代码不长,200多行,但都不好理解,要对HTTP协议有所了解。
    先看看构造函数:
      public UploadFile(string name)
      {
       if ((name == null) || (name == string.Empty))
       {
        throw new ArgumentNullException("Name", "Name can not be null!");
       }

       string content = String.Empty; 

       this.filename = string.Empty;
       this.filepath = string.Empty;
       this.contenttype = string.Empty;
       this.filelength = 0;

    前面的是初始化变量,直接从这里开始分析:看后面的解释  
       if (IsContentHeader(name))
       {
        content = name;
       }
       else if (IsContentHeader(Utils.GetContext().Request[name]))
       {
        content = Utils.GetContext().Request[name];
       }

       if ((content == null) || (content == string.Empty))
       {
        return;
       }

       //Get file info from content.
       string[] contentArray = content.Split(';');

       this.contenttype = contentArray[0];
       this.contenttype = this.contenttype.Substring(14, (this.contenttype.Length - 14));
       this.filename = contentArray[1];
       this.filename = this.filename.Substring(10, (this.filename.Length - 11));
       this.filepath = contentArray[2];
       this.filepath = this.filepath.Substring(10, (this.filepath.Length - 11));

       string uploadFolder = Utils.GetUploadFolder();
       this.filepath = Path.Combine(uploadFolder, this.filepath);

       try
       {
        this.filelength = new FileInfo(this.filepath).Length;
       }
       catch (Exception exception)
       {
        string uploadGuid = Utils.GetContext().Request["Sunrise_Web_Upload_UploadGUID"];

        if (uploadGuid != null)
        {
         Utils.GetContext().Application.Remove(("_UploadGUID_" + uploadGuid));
        }

        throw exception;
       }
      }
    //
    研究说明:
       if (IsContentHeader(name))
       {
        content = name;
       }
       else if (IsContentHeader(Utils.GetContext().Request[name]))
       {
        content = Utils.GetContext().Request[name];
       }
    这里又用name(上传文件的名字)参数调用了IsContentHeader函数,开始我不大明白,后面的分隔数组是怎么回事?上传的控件名不就是个字符串吗?实际上这

    个函数在一次上传过程中被调用了两次,其中后面的分隔就是为了下次调用时做准备的,这是我的输出日志:
    11/1/2005 4:58:04 PM file1
    11/1/2005 4:58:04 PM Content-Type: video/x-ms-wmv;filename="D:\video\Defense.wmv";filepath="ec2f062d-21ab-4591-ada0-892a32a05625.wmv"
    可以看到,第二次调用的时候,是以文件的上传信息来调用的,我们先不管它。往后看。
      private bool IsContentHeader(string line)
      {
       if((line == null)||(line == String.Empty))
       {
        return false;
       }
       string[] contentArray = line.Split(';');
       if (((contentArray.Length == 3)
        && contentArray[0].StartsWith("Content-Type:"))
        && (contentArray[1].StartsWith("filename=\"")
        && contentArray[2].StartsWith("filepath=\"")))
       {
        return true;
       }
       return false;
      }
    显然第一次调用是返回false;
    第二次调用是在
    else if (IsContentHeader(Utils.GetContext().Request[name]))
    那么我们又要看看Utils类了。
      public static HttpContext GetContext()
      {
       HttpContext context = HttpContext.Current;
       if (context == null)
       {
        throw new Exception("HttpContext not found");
       }

       return context;
      }
    它返回当前HTTP请求的所有信息,里面就包含了文件上传的源信息。关于HttpContext类,可以查看MSDN里的帮助。也就是说,我们在HttpContext里取得数据的时

    候,所得到的信息是完整的,所以我们可以得到上传文件的文件路径以文件类型。我们可以自己试一下:
    1、建立一个新的Web Application,
    2、创建一个类,
    using System;
    using System.Collections;
    using System.IO;
    using System.Reflection;
    using System.Text;
    using System.Web;
    using System.Xml;

    namespace WebbTest
    {
     /// <summary>
     /// Summary description for UploadTest.
     /// </summary>
     public class HttpModuleTest : IHttpModule
     {
      public HttpModuleTest()
      {
       //
       // TODO: Add constructor logic here
       //这里只是一个测试的调试输出,看看这个类为我们都做了些什么?
       WebbSystem.TraceMsg("Construct the HttpModule.");
      }

      public void Dispose()
      {
      }

      public void Init(System.Web.HttpApplication m_application)
      {
      }
     }
    }
    3、添加到Web.config里,让所有的请求都要经过HttpModuleTest。
      <httpModules>
       <add name="WebbTest" type="WebbTest.HttpModuleTest, WebbTest"/>
      </httpModules> 
    4、然后测试页面,可以得到结果:
    11/1/2005 5:22:36 PM Construct the HttpModule.
    11/2/2005 8:32:55 AM Construct the HttpModule.
    (呵呵,我才发现一个问题,第二个时间上的信息是VS.net打开项目的时候产生的,因为VS.net在打开项目的时候对服务器做了一次请求。所以被记录下了。)
    利用这个原理,我们是不是可以自己做一个网站统计系统呢?

    好了,继续向下分析代码。


    文章来源:http://computer.mblogger.cn/wucountry/posts/48478.aspx
    ================================
      /\_/\                        
     (=^o^=)  Wu.Country@侠缘      
     (~)@(~)  一辈子,用心做一件事!
    --------------------------------
      学而不思则罔,思而不学则怠!  
    ================================
  • 相关阅读:
    2017博普杯 东北大学邀请赛(B. Drink too much water)(贪心+树链剖分)
    AGC018D Tree and Hamilton Path(树+树的重心)
    BZOJ2843:极地旅行社
    P++ 1.0.5
    BZOJ1052:[HAOI2007]覆盖问题
    BZOJ3098:Hash Killer II
    BZOJ2784:[JLOI2012]时间流逝
    BZOJ2282:[SDOI2011]消防
    BZOJ1875:[SDOI2009]HH去散步
    Codeforces 504 A (Round #285 div.1 A) Misha and Forest
  • 原文地址:https://www.cnblogs.com/WuCountry/p/305670.html
Copyright © 2011-2022 走看看