[Memo]ASP.NET上傳檔案超過限制大小時,導至特定頁面(by Global.asax)

  • 27972
  • 0
  • 2010-01-15

[Memo]ASP.NET上傳檔案超過限制大小時,導至特定頁面(by Global.asax)

前言

ASP.NET上傳檔案時,最大限制大小是2GB,預設是4MB。

要調整的話,可以在web.config上加上

<system.web>
        <httpRuntime maxRequestLength="4096" executionTimeout="43200"/>
</system.web>

如果都沒做任何處理,當使用ASP.NET的FileUpload控制項時,
當上傳檔案超過config限制大小時,將無法顯示自訂錯誤網頁。
Microsoft Internet Explorer 會顯示「找不到伺服器或 DNS」錯誤訊息作為替代。
defaultError


Survey Solution

網路上有許多相對應的解法,可以參考:

  1. 黃忠成老師:ASP.NET 檔案上傳處理—檔案大小超過限制之處理
  2. 邱英瑞(Jacky)老師:ASP.NET 無法上載大型檔案(大於 4MB)
  3. MSDN forum:如何檢查上傳檔案大小?? (包括使用javascript裡用ActiveX檢查)


不過黃忠成老師的方式,不知道為什麼我試不出來,程式都有進入中斷點跑過,
甚至也已經可以導到我自訂的頁面裡面的PageLoad事件,
但是最後呈現出來的頁面,仍然是FileUpload那一頁的網址,錯誤頁面仍如上面所述。

黃老師的方法應該是沒錯,當我把config設定到2GB的時候,在程式裡面則是控制不可以上傳超過4MB,
那黃老師的方法就可以正常work,但假設上傳的檔案超過config的限制時,
程式一樣會跑,但錯誤頁面就不是自訂的了。


加上老師的作法,是給UpdatePanel+iFrame+FileUpload使用,
小的這邊的需求則是希望可以直接在Global就解決掉。

所以就找到了另一個參考:ASP Net - How to handle "Maximum request length exceeded" exception
 

Play it

這邊順便記錄一下,方便以後還有其他人可以直接使用。

在Global.asax裡面覆寫Application_BeginRequest()的方法:

    protected void Application_BeginRequest(Object sender, EventArgs e)
    {

        System.Web.Configuration.HttpRuntimeSection runTime = (System.Web.Configuration.HttpRuntimeSection)System.Web.Configuration.WebConfigurationManager.GetSection("system.web/httpRuntime");
        //Approx 100 Kb(for page content) size has been deducted because the maxRequestLength proprty is the page size, not only the file upload size
        int maxRequestLength = (runTime.MaxRequestLength - 100) * 1024;

        //This code is used to check the request length of the page and if the request length is greater than
        //MaxRequestLength then retrun to the same page with extra query string value action=exception

        HttpContext context = ((HttpApplication)sender).Context;
        if (context.Request.ContentLength > maxRequestLength)
        {
            IServiceProvider provider = (IServiceProvider)context;
            HttpWorkerRequest workerRequest = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));

            // Check if body contains data
            if (workerRequest.HasEntityBody())
            {
                // get the total body length
                int requestLength = workerRequest.GetTotalEntityBodyLength();
                // Get the initial bytes loaded
                int initialBytes = 0;

                if (workerRequest.GetPreloadedEntityBody() != null)
                    initialBytes = workerRequest.GetPreloadedEntityBody().Length;

                if (!workerRequest.IsEntireEntityBodyIsPreloaded())
                {
                    byte[] buffer = new byte[512000];
                    // Set the received bytes to initial bytes before start reading
                    int receivedBytes = initialBytes;
                    while (requestLength - receivedBytes >= initialBytes)
                    {
                        // Read another set of bytes
                        initialBytes = workerRequest.ReadEntityBody(buffer, buffer.Length);

                        // Update the received bytes
                        receivedBytes += initialBytes;
                    }

                    initialBytes = workerRequest.ReadEntityBody(buffer, requestLength - receivedBytes);
                }
            }
            // Redirect the user to the same page with querystring action=exception.
            context.Response.Redirect(this.Request.Url.LocalPath + "?action=exception");            
        }
    }


結論

雖說這個方式可以work,但是當上傳的檔案太大時,
等待導頁的時間,仍然相當漫長,這一點要特別注意。

[註]2010/01/15,補充一下bauann與小朱大推薦的silverlight fileupload,相當相當不錯用:Silverlight File Upload


blog 與課程更新內容,請前往新站位置:http://tdd.best/