ASP.NET 上传大文件(原创)

问题描述

需要在网站中上传文件,但是当文件大小太大的时候IIS会拒绝连接,导致用户看到不友好的错误界面。

解决方法

1.服务器端处理

  在globle.asax中的protected void Application_Error(object sender, EventArgs e)函数中处理错误

  

    public class Global : System.Web.HttpApplication
    {
        static List<string[]> options;
        static Global(){
            var mlstr = WebConfigurationManager.AppSettings.Get("MaxRequestLength");
            if (string.IsNullOrEmpty(mlstr)) options = null;
            else
            {
                try
                {
                    var optionstr = mlstr.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
                    options = new List<string[]>();
                    optionstr.ToList().ForEach(e => options.Add(e.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries)));
                }
                catch(Exception e) { options = null; }
            }
        }
...
        protected void Application_Error(object sender, EventArgs e)
        {
            
            if (Server.GetLastError().GetType() != typeof(HttpException)) return;
            if (options == null) return;
            var item = options.Find(i => i[0] == this.Request.Url.LocalPath);
            if (item == null) return;

            int maxRequestLength = 0;
            Int32.TryParse(item[1], out maxRequestLength);

            //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.
                //Response.ClearContent();
                //context.Server.ClearError();
                context.Response.Redirect(this.Request.Url.LocalPath + "?" + item[2]);
            }
        }
...
}
View Code
<appSettings>
    <add key="MaxRequestLength" value="/upload.ashx,100,errorcallback=upCallback"/>
  </appSettings>

2.前端处理

  上传方式采用的是iframe仿ajax。因此考虑截获iframe的onload事件从而进行友好提示。

  但是经过测试:当服务器因连接长度过长断开连接时,firefox不会触发iframe的onload事件,因此该方法失败。

  http://src.chromium.org/svn/trunk/src/tools/measure_page_load_time/ff_ext/content/measure_page_load_time.js

  中第156行附近也说明了firefox没有好的截获connection reset事件的方式。

3.其他

其他诸如改变默认大小的方法不可取,因为无论多大,用户都可能选择超过你的设定。

结论

暂时采用方法一。如果firefox中可以截获connection reset事件,方法2明显优于方法1.

因为在方法一种会将上传文件全部读取(并不保存),消耗服务器资源。

原创于:http://www.cnblogs.com/errorx/

转载请注明

原文地址:https://www.cnblogs.com/errorx/p/3161773.html