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/

转载请注明

你可能感兴趣的:(asp.net)