none
上传大文件问题 RRS feed

  • 问题

  • 在网上找到一个上传大文件的方法,有些不明白的地方,请大家指教:

    public void Application_BeginRequest(object sender, EventArgs e)
            {
                HttpApplication application = sender as HttpApplication;
                HttpWorkerRequest workRequest = GetWorkerRequest(application.Context);

                if (workRequest != null)
                {
                    HttpRequest request = application.Request;
                    byte[] tempBuffer;

                    //tempBuffer为何总是为null?
                    tempBuffer = workRequest.GetPreloadedEntityBody();

                    if (IsUploadRequest(request))
                    {
                        Encoding encode = request.ContentEncoding;
                       

                        int bytesRead = 0;
                        int read = 0;
                        int count = 8192;
                        byte[] buffer;
                        //为何当上传的文件很大的时候(我用了几百M、1.+G、3.+G的做测试,当用3.+G做测试时)length为负
                        long length = long.Parse(workRequest.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
                        tempBuffer = tempBuffer == null ? new byte[count] : tempBuffer;

                        buffer = new byte[length];
                        count = tempBuffer.Length;

                        bytesRead = tempBuffer.Length;

                        while (workRequest.IsClientConnected() && !workRequest.IsEntireEntityBodyIsPreloaded() && bytesRead < length)
                        {
                            if (bytesRead + count > length)
                            {
                                count = (int)(length - bytesRead);
                                tempBuffer = new byte[count];
                            }

                            read = workRequest.ReadEntityBody(tempBuffer, count);

                            Buffer.BlockCopy(tempBuffer, 0, buffer, bytesRead, read);

                            bytesRead += read;
                        }

                        if (workRequest.IsClientConnected() && !workRequest.IsEntireEntityBodyIsPreloaded())
                        {
                            // 传入已上传完的数据
                            //
                            InjectTextParts(workRequest, buffer);
                        }
                    }
                }
            }

    public HttpWorkerRequest GetWorkerRequest(HttpContext context)
            {
                IServiceProvider provider = (IServiceProvider)HttpContext.Current;
                return (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest));
            }

            /// <summary>
            /// 是否为附件上传
            /// 判断的根据是ContentType中有无multipart/form-data
            /// </summary>
            /// <param name="request"></param>
            /// <returns></returns>
            public bool IsUploadRequest(HttpRequest request)
            {
                string s1 = request.ContentType, s2 = "multipart/form-data";
                return (string.Compare(s1, 0, s2, 0, s2.Length, true, CultureInfo.InvariantCulture) == 0);
            }

            /// <summary>
            /// 传入已上传完的数据
            /// </summary>
            /// <param name="request"></param>
            /// <param name="textParts"></param>
            public 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);
                }
            }

     主要有以下三个问题:
    1、tempBuffer = workRequest.GetPreloadedEntityBody();----tempBuffer为何总是为null?
    2、long length = long.Parse(workRequest.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));为何当上传的文件很大的时候(我用了几百M、1.+G、3.+G的做测试,当用3.+G做测试时)length为负
    3、这样上传能上传多大的文件,我只上传了几十M就上传不了了,长度太大

    关于第一个问题,网上有人说要用IIS,不用vs自带的服务器,我IIS7还是不行
    希望大家不吝赐教

    2010年3月30日 7:52

答案

  • Please try the following coding:

      protected void Application_BeginRequest(object sender, EventArgs e)
            {
                HttpRequest request = HttpContext.Current.Request;
                if (request.ContentType.Contains("multipart/form-data") && request.ContentLength > 4194304)//4096000 is maxRequestLength
                {
                    HttpApplication app = sender as HttpApplication;
                    HttpContext context = app.Context;

                    //HttpWorkerRequest workerRequest = (HttpWorkerRequest)(context.GetType().GetProperty("WorkerRequest", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(context, null));

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


                    if (workerRequest.HasEntityBody())
                    {

                        //int contentlen = Convert.ToInt32(wr.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
                        //buffer = wr.GetPreloadedEntityBody();
                        //int received = buffer.Length;
                        //int totalrecv = received;


                        // 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[52000];
                            // 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);
                        }
                    }

                    context.Response.Redirect("../UploadError.aspx");//Redirect to custom error page.
                }
            }

    • 已标记为答案 Alan.Deng 2010年4月1日 2:48
    2010年3月31日 9:14

全部回复

  • Please try the following coding:

      protected void Application_BeginRequest(object sender, EventArgs e)
            {
                HttpRequest request = HttpContext.Current.Request;
                if (request.ContentType.Contains("multipart/form-data") && request.ContentLength > 4194304)//4096000 is maxRequestLength
                {
                    HttpApplication app = sender as HttpApplication;
                    HttpContext context = app.Context;

                    //HttpWorkerRequest workerRequest = (HttpWorkerRequest)(context.GetType().GetProperty("WorkerRequest", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(context, null));

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


                    if (workerRequest.HasEntityBody())
                    {

                        //int contentlen = Convert.ToInt32(wr.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength));
                        //buffer = wr.GetPreloadedEntityBody();
                        //int received = buffer.Length;
                        //int totalrecv = received;


                        // 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[52000];
                            // 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);
                        }
                    }

                    context.Response.Redirect("../UploadError.aspx");//Redirect to custom error page.
                }
            }

    • 已标记为答案 Alan.Deng 2010年4月1日 2:48
    2010年3月31日 9:14
  • 你好,

    一般上述代码用来避免上传大文件时出现一些不可预测的错误的。

    比如我们在web.config中配置了上传的最大限制,如果你超过了这个限制,你会看到一个似乎服务器没响应的页面,什么连接有问题的页面。

    这时我们可以自定义一个HttpModule,调用花雨透提供的代码,对传过来的数据进行预处理,以避免出现上述情况。

    在上面代码中,你可以选择保存该数据,也可以忽略它,但是必须要把传过来的数据过一遍,否则还是会报错。

    即必须要至少要有下面这段代码:

    while (requestLength - receivedBytes >= initialBytes)
                            {
                                // Read another set of bytes
                                initialBytes = workerRequest.ReadEntityBody(buffer, buffer.Length);
    
                                // Update the received bytes
                                receivedBytes += initialBytes;
                            }
    
    

    你可以在上面的代码中保存数据。

     建议你用花雨透 的方法试试。

     


    Microsoft Online Community Support
    2010年4月1日 3:36