1. 程式人生 > >asp.net利用HttpWorkerRequest上傳大檔案

asp.net利用HttpWorkerRequest上傳大檔案

前臺頁面

<form id="form1" runat="server" encType="multipart/form-data" method="post">
    <div>
        <INPUT id="firstFile" type="file" name="firstFile" runat="server"><br />
        &nbsp;<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="上傳" /><br />
        <asp:Label ID="Label1" runat="server"></asp:Label></div>
    </form>

後臺頁面

protected void Page_Load(object sender, EventArgs e)
        {

        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            //要儲存的位置
            string strDesPath = "D:\\";
            string strFileName = this.firstFile.PostedFile.FileName;
            strFileName =strDesPath + strFileName;
            //
            this.firstFile.PostedFile.SaveAs(strFileName);
            this.Label1.Text = "檔案儲存到了:" + strFileName;
        }

配置檔案

<httpModules>
   <add name="HttpUploadModule" type="HttpModelApp.HttpUploadModule, HttpModelApp"/>

</httpModules>

<httpRuntime maxRequestLength="2000000" executionTimeout="300"/>

using System;
using System.Collections;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Text;
using System.Web;

using System.Reflection;

namespace HttpModelApp
{
    //實現IHttpModule介面
    public class HttpUploadModule : IHttpModule
    {
        public HttpUploadModule()
        {

        }

        public void Init(HttpApplication application)
        {
            //訂閱事件
            application.BeginRequest += new EventHandler(this.Application_BeginRequest);
        }

        public void Dispose()
        {
        }

        private void Application_BeginRequest(Object sender, EventArgs e)
        {
            HttpApplication app = sender as HttpApplication;
            HttpWorkerRequest request = GetWorkerRequest(app.Context);
            Encoding encoding = app.Context.Request.ContentEncoding;

            int bytesRead = 0;  // 已讀資料大小
            int read;           // 當前讀取的塊的大小
            int count = 8192;   // 分塊大小
            byte[] buffer;      // 儲存所有上傳的資料

            if (request != null)
            {
                // 返回 HTTP 請求正文已被讀取的部分。
                byte[] tempBuff = request.GetPreloadedEntityBody(); //要上傳的檔案

                // 如果是附件上傳
                if (tempBuff != null && IsUploadRequest(app.Request))    //判斷是不是附件上傳
                {
                    // 獲取上傳大小
                    //
                    long length = long.Parse(request.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
                   
                    buffer = new byte[length];
                    count = tempBuff.Length; // 分塊大小

                    // 將已上傳資料複製過去
                    //
                    Buffer.BlockCopy(tempBuff,  //源資料
                        0,                      //從0開始讀
                        buffer,                 //目標容器
                        bytesRead,              //指定儲存的開始位置
                        count);                 //要複製的位元組數。


                    // 開始記錄已上傳大小
                    bytesRead = tempBuff.Length;

                    // 迴圈分塊讀取,直到所有資料讀取結束
                    while (request.IsClientConnected() &&!request.IsEntireEntityBodyIsPreloaded() && bytesRead < length)
                    {
                        // 如果最後一塊大小小於分塊大小,則重新分塊
                        if (bytesRead + count > length)
                        {
                            count = (int)(length - bytesRead);
                            tempBuff = new byte[count];
                        }

                        // 分塊讀取
                        read = request.ReadEntityBody(tempBuff, count);

                        // 複製已讀資料塊
                        Buffer.BlockCopy(tempBuff, 0, buffer, bytesRead, read);

                        // 記錄已上傳大小
                        bytesRead += read;

                    }
                    if (  request.IsClientConnected() && !request.IsEntireEntityBodyIsPreloaded()  )
                    {
                        // 傳入已上傳完的資料
                        InjectTextParts(request, buffer);
                    }
                }
            }
        }


        HttpWorkerRequest GetWorkerRequest(HttpContext context)
        {

            IServiceProvider provider = (IServiceProvider)HttpContext.Current;
            return (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
        }

        /// <summary>
        /// 傳入已上傳完的資料
        /// </summary>
        /// <param name="request"></param>
        /// <param name="textParts"></param>
        void InjectTextParts(HttpWorkerRequest request, byte[] textParts)
        {
            BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic;

            Type type = request.GetType();

            while ((type != null) && (type.FullName != "System.Web.Hosting.ISAPIWorkerRequest"))
            {
                type = type.BaseType;
            }

            if (type != null)
            {
                type.GetField("_contentAvailLength", bindingFlags).SetValue(request, textParts.Length);
                type.GetField("_contentTotalLength", bindingFlags).SetValue(request, textParts.Length);
                type.GetField("_preloadedContent", bindingFlags).SetValue(request, textParts);
                type.GetField("_preloadedContentRead", bindingFlags).SetValue(request, true);
            }
        }

        private static bool StringStartsWithAnotherIgnoreCase(string s1, string s2)
        {
            return (string.Compare(s1, 0, s2, 0, s2.Length, true, CultureInfo.InvariantCulture) == 0);
        }

        /// <summary>
        /// 是否為附件上傳
        /// 判斷的根據是ContentType中有無multipart/form-data
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        bool IsUploadRequest(HttpRequest request)
        {
            return StringStartsWithAnotherIgnoreCase(request.ContentType, "multipart/form-data");
        }
    }
}

注:需新增引用 HttpModelApp.dll