Не удается загрузить файл, если файл слишком большой - PullRequest
0 голосов
/ 26 декабря 2018

Я пытаюсь поймать ошибку при загрузке файла, который слишком велик.

На сервере средство чтения многокомпонентных разделов выдает, что я перехватываю и возвращаю как BadRequest (также пытался InternalError):

  try
  {
    var section = await reader.ReadNextSectionAsync();
    while (section != null)
    {
       ...
    }
  }
  catch (Exception ex)
  {
    return StatusCode((int)HttpStatusCode.BadRequest, ProblemFactory.Shared.BadRequestProblem("Could not upload file", ex.Message));
  }

Чтобы загрузить, у меня есть следующее (в настоящее время используется RestSharp, но тот же результат с HttpClient через HttpClientFactory):

  var request = new RestRequest(REQ_UPLOADFILE, Method.POST, DataFormat.Json);
  var token = await _agentTokenService.GetToken();
  AddTokenHeader(request, token.AccessToken);

  request.AddFile("file", path);
  request.AddParameter("externalFileType", fileType, ParameterType.GetOrPost);
  request.AddParameter("subType", subType, ParameterType.GetOrPost);

  var resp = await _client.ExecuteTaskAsync(request);

  if (resp.IsSuccessful)
  {
    return JsonConvert.DeserializeObject<ExternalFileResponse>(resp.Content);
  }
  else
  {
    string reason = "unknown error";
    //switch(resp.StatusCode)
    //{
    //  case HttpStatusCode.???
    //}
    throw new Exception($"Could not upload file: {reason}");
  }

Ответ от поста - код состояния 0 с сообщением:

Поток не поддерживает одновременные операции чтения или записи ввода-вывода

Загрузка выполняется в задаче, поэтому я думаю, что это как-то связано с этим, но есть толькоОднократная загрузка выполняется, и если файл меньше, он работает без проблем.

Я могу только думать, что что-то в обработке ответов как-то ломается.

У кого-нибудь есть подсказка ??

Спасибо и с Рождеством :):

PS: я использую только Kestrel - без IIS или nginx - с такими опциями:

 .UseKestrel(options =>
    {
      options.AddServerHeader = false;
      options.Limits.MaxRequestBodySize = 100 * 1024 * 1024; // 100 MB
    })

ОБНОВЛЕНИЕ Я этоЯ понимаю, теперь это лучше.Сервер прерывает соединение, когда считывает байты из потока.
Клиент, асинхронно пишущий, продолжает работать немного, но затем я пытаюсь прочитать ответ - отсюда и сообщение об ошибке.

ОБНОВЛЕНИЕ HttpClient на самом деле реагирует немного по-другому - я получил мой плохой запрос, и сообщение о том, что поток был закрыт.

1 Ответ

0 голосов
/ 06 января 2019

Вот простой способ загрузки большого файла с использованием ASP.NET.

(1) загрузка и загрузка из web * https://github.com/fex-team/webuploader

(2) загрузка через Интернет большого файла в файл чанка,создать веб-форму

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title> 
    <script src="../Javascript/jquery-1.9.1.min.js"></script> 
    <link href="../javascript/webuploader/webuploader.css" rel="stylesheet" />
    <script src="../javascript/webuploader/webuploader.js"></script>

</head>
<body  >


    <form>

    <br /><br />


    <div id="uploader" class="wu-example">


<div class="btns">
<div id="picker"  style="display:inline-block">Select a File</div>  

    <input id="ctlBtn" type="button" value="Upload" class="btn  btn-primary"  style="border-radius:0px;  position:relative; top:-13px"/>
</div>




        <div id="thelist" class="uploader-list"></div>
</div>




     <script>
         _extensions = '3gp,mp4,rmvb,mov,avi,m4v';
         _mimeTypes = 'video/*,audio/*,application/*';


         var GUID = WebUploader.Base.guid();//一个GUID
         // alert(GUID);

         uploader = WebUploader.create({
             auto: false,
             // swf path
             swf: '../javascript/webuploader/Uploader.swf',
             //server receive data
             server: '_uploadVideo.aspx',
             pick: {
                 id: '#picker',
                 label: 'Select a File',
                 innerHTML: 'Select a File',
                 multiple: false
             },

             fileNumLimit: 1,
             fileSingleSizeLimit: 1024 * 1024 * 120,


             accept: {
                 title: 'large file',   
                 extensions: _extensions,     
                 mimeTypes: _mimeTypes,      // eg. image/*,
             },


             chunked: true,//split large into small file
             chunkSize: 1024 * 1024 * 2, //every small file size,this is 2M
             formData: {
                 guid: GUID, 
                 types:"upload"
             }
         });

         uploader.on('fileQueued', function (file) {

             $("#thelist").append('<div id="' + file.id + '" class="item">' +
 '<b class="info">' + file.name + '</b> ' +
 '<p class="state">wait...</p>' + '</div>');
         });




         uploader.on('uploadSuccess', function (file, response) {
             //merge small into a large file
             $('#' + file.id).find('p.state').html('<font color=green>upload success</font>');
             $.post('_uploadVideo.aspx', { guid: GUID, fileName: file.name, types: "merge" ,r:Math.random(),itemid:<%=Request.QueryString["itemid"]%> }, 
                 function (data) {
                 if (data == 1) {
                     alert("success");

                 }
                 else {
                    alert("fail");
                 }
             });
         });







         uploader.on("error", function (type, handler) {

             if (type == "Q_TYPE_DENIED") {
                 alert("format error");

             } else if (type == "F_EXCEED_SIZE") {
                alert("size too large");

             }
         });





         uploader.on('uploadProgress', function (file, percentage) {
             var $li = $('#' + file.id),
                 $percent = $li.find('.progress .progress-bar');

             // stop re-upload
             if (!$percent.length) {
                 $percent = $('<div class="progress progress-striped active">' +
                   '<div class="progress-bar" role="progressbar" style="width: 0%">' +
                   '</div>' +
                 '</div>').appendTo($li).find('.progress-bar');
             }

             $li.find('p.state').text('uploading');

             $percent.css('width', percentage * 100 + '%');
         });



         $("#ctlBtn").click(
             function () {

                 uploader.upload();
             }
             );

     </script>

    </form>
</body>
</html>

(3) создать страницу веб-формы asp.net _uploadVideo.aspx удалить весь контент, aspx должен содержать только 1 строку

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="_uploadVideo.aspx.cs" Inherits="Gallery.Gallery._uploadVideo" %>

(4) в коде_uploadVideo.aspx.cs wirte code ниже:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
using System.Data.SqlClient;
namespace Gallery.Gallery
{
public partial class _uploadVideo : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Request["types"] == "upload")
        { 

            if (Request.Form.AllKeys.Any(m => m == "chunk"))
            {
                int year = DateTime.Now.Year;
                //取得chunk和chunks
                int chunk = Convert.ToInt32(Request["chunk"]); 
                int chunks = Convert.ToInt32(Request["chunks"]); 


                string folder = Server.MapPath("../uploads/video/"+year+"/" + Request["guid"] + "/");
                string path = folder + chunk;

                //建立临时传输文件夹 create teamplate folder
                if (!Directory.Exists(Path.GetDirectoryName(folder)))
                {
                    Directory.CreateDirectory(folder);
                }

                FileStream addFile = new FileStream(path, FileMode.Append, FileAccess.Write);
                BinaryWriter AddWriter = new BinaryWriter(addFile);
                //获得上传的分片数据流 get chunk
                var file = Request.Files[0];
                Stream stream = file.InputStream;

                BinaryReader TempReader = new BinaryReader(stream);
                //将上传的分片追加到临时文件末尾
                AddWriter.Write(TempReader.ReadBytes((int)stream.Length));
                //关闭BinaryReader文件阅读器
                TempReader.Close();
                stream.Close();
                AddWriter.Close();
                addFile.Close();

                TempReader.Dispose();
                stream.Dispose();
                AddWriter.Dispose();
                addFile.Dispose();
                string f_ext = Path.GetExtension(file.FileName);


                string _result = "{\"chunked\" :\"true\",\"hasError\" :\"false\",\"f_ext\" :\"" + f_ext + "\" }";
                System.Web.HttpContext.Current.Response.Write(_result);

            }
        }


        if (Request["types"] == "merge")
        {


            try
            {
                int year = DateTime.Now.Year;
                var guid = Request["guid"];//GUID
                var uploadDir = Server.MapPath("../uploads/video/" + year+"/");//Upload 文件夹


                //建立临时传输文件夹
                if (!Directory.Exists(Path.GetDirectoryName(uploadDir)))
                {
                    Directory.CreateDirectory(uploadDir);
                }



                var dir = Path.Combine(uploadDir, guid);//临时文件夹
                var ext = Path.GetExtension(Request["fileName"]);
                var files = Directory.GetFiles(dir);//获得下面的所有文件
                var name = Guid.NewGuid().ToString("N") + ext;
                var finalPath = Path.Combine(uploadDir, name);//最终的文件名
                var fs = new FileStream(finalPath, FileMode.Create);
                foreach (var part in files.OrderBy(x => x.Length).ThenBy(x => x))//排一下序,保证从0-N Write
                {
                    var bytes = System.IO.File.ReadAllBytes(part);
                    fs.Write(bytes, 0, bytes.Length);
                    bytes = null;
                    System.IO.File.Delete(part);//删除分块
                }
                fs.Flush();
                fs.Close();
                Directory.Delete(dir);//删除文件夹


                //INSERT INTO DB  finalPath

                 SqlParameter[] p = { 
                                   new SqlParameter("@videopath","../uploads/video/" + year+"/"+name)

                                   };

               string sql = @"update portal_photoes  set videopath=@videopath where  id=" + int.Parse(Request["itemid"]);

              //you can exe  SQL to into database



                System.Web.HttpContext.Current.Response.Write("1");

            }
            catch (Exception ex)
            {

                System.Web.HttpContext.Current.Response.Write("0");

            }

        }




    }
    }
}
...