如何使用MVC 4上传大文件?

pun*_*ter 43 c# asp.net-mvc jquery file-upload plupload

我有它工作..但我注意到,一旦我上传的文件变大(约4000k)控制器将不会被调用..

所以我在chunking中添加了哪个修复了这个问题..但是现在当我打开文件时它充满了垃圾字符......

那么使用plupload/MVC 4上传大文件的正确方法是什么?

这是我目前的代码

  $(document).ready(function () {

    var uploader = new plupload.Uploader({
        runtimes: 'html5',
        browse_button: 'pickfiles',
        container: 'container',
     //   max_file_size: '20000mb',
        url: '@Url.Action("Upload", "Home")',
        chunk_size: '4mb',
        //filters: [
        //    { title: "Excel files", extensions: "xls,xlsx" },
        //    { title: "Text files", extensions: "txt" }
        //],
        multiple_queues: true,
        multipart: true,
        multipart_params: { taskId: '' }
    });
Run Code Online (Sandbox Code Playgroud)

和控制器

  [HttpPost]
    public ActionResult Upload(int? chunk, string name, string taskId)
    {
        string filePath = "";
        var fileUpload = Request.Files[0];
        var uploadPath = Server.MapPath("~/App_Data/Uploads");
        chunk = chunk ?? 0;
        string uploadedFilePath = Path.Combine(uploadPath, name);
        var fileName = Path.GetFileName(uploadedFilePath);

 try
        {
            using (var fs = new FileStream(filePath, chunk == 0 ? FileMode.Create : FileMode.Append))
            {
                var buffer = new byte[fileUpload.InputStream.Length];
                fileUpload.InputStream.Read(buffer, 0, buffer.Length);
                fs.Write(buffer, 0, buffer.Length);
            }

            //Log to DB for future processing
            InstanceExpert.AddProcessStart(filePath, Int32.Parse(taskId));
        }
Run Code Online (Sandbox Code Playgroud)

Sha*_*eKm 64

在web.config中你需要这些(2GB全部):

<system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" maxRequestLength="2147483647" executionTimeout="1600" requestLengthDiskThreshold="2147483647" />
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="2147483647" />
      </requestFiltering>
    </security>
    ...
</system.web>
Run Code Online (Sandbox Code Playgroud)

  • 编译和httpRuntime进入system.web - security进入system.webserver.maxRequestLength也以千字节为单位,而maxAllowedContentLenght和requestLengthDiskThreshold以字节为单位 (14认同)
  • 这非常糟糕!如果我的文件在1.8GB ...重启时失败会发生什么.此外,它对DDoS攻击开放,启动100+(它很容易通过客户端脚本在一秒钟内启动10000次上传)上传,你的服务器被砖砌了!不要这样做!实施适当的分块.这也允许你加价限制,加上恢复上传.-1 (6认同)
  • 我认为你的意思是<system.webServer>而不是<system.web>.也许它在不同版本中有所不同. (4认同)

Pri*_*kay 15

当前版本

根据IIS 8.0的详细错误描述,这是我在编写本答案时使用的版本,您需要在ApplicationHost.configWeb中验证配置/ system.webServer/security/requestFiltering/requestLimits @maxAllowedContentLength设置.config文件.这意味着你需要包括:

<requestLimits maxAllowedContentLength="20971520000"></requestLimits>
Run Code Online (Sandbox Code Playgroud)

内部配置/ system.webServer/security/requestFiltering标签树.万一你缺乏想象力来想象它的去向,完整的代码块如下所示:

<configuration>
    <system.webServer>
        <security>
            <requestFiltering>
                <requestLimits maxAllowedContentLength="20971520000"></requestLimits>
            </requestFiltering>
        </security>
    </system.webServer>
</configuration>
Run Code Online (Sandbox Code Playgroud)

Visual Studio 2010/.Net Framework 4和之前版本

使用VS2008/10和/或.Net Framework 3.5/4创建的旧版Web应用程序也可能仍在通过configuration/system.web/httpRuntime @maxRequestLength 查找此配置,但是如链接页面所示,它是虽然不适用于此场景的HttpRuntime Class自.Net Framework 1.1以来仍然存在,但已不再可用.如果是这种情况,您需要包括:

<httpRuntime maxRequestLength="20971520000" />
Run Code Online (Sandbox Code Playgroud)

内部配置/ system.web/httpRuntime标签树.再一次,为了防止您无法理解它的插入位置,完整的代码块看起来如下所示:

<configuration>
    <system.web>
        <httpRuntime maxRequestLength="20971520000" />
    </system.web>
</configuration>
Run Code Online (Sandbox Code Playgroud)

文件大小编号只是一个任意数字(20,000 MB - 而不是20 GB,而不是21,474,836,480)作为演示显示.除非您为需要上传大文件的严密安全组编码网站,否则不应允许将这么大的文件大小上传到您的Web服务器.


Ary*_*ian 11

我遇到了这个问题,并在此处找到了基于Jonathan代码的解决方案.如果你想上传一个大文件,比如1Gbyte视频文件,你必须扔掉文件并通过几个请求发送它(一个请求给出超时).首先在Web.config中设置客户端和服务器端的最大限制,如其他答案中所述.

<system.webServer>
 <security>
  <requestFiltering>
    <requestLimits maxAllowedContentLength="2147483647" />
  </requestFiltering>
 </security>
<system.webServer>
Run Code Online (Sandbox Code Playgroud)

<system.web>
  <httpRuntime targetFramework="4.5" maxRequestLength="2147483647" />
</system.web>
Run Code Online (Sandbox Code Playgroud)

然后将文件分块,并发送每个chuck,等待响应并发送下一个块.这里是html(VideoDiv工作为上传面板),javascript(jQuery)和控制器代码.

    <div id="VideoDiv">
        <label>Filename:</label>
        <input type="file" id="fileInput" /><br/><br/>
        <input type="button" id="btnUpload" value="Upload a presentation"/><br/><br/>
        <div id="progressbar_container" style="width: 100%; height: 30px; position: relative; background-color: grey; display: none">
            <div id="progressbar" style="width: 0%; height: 100%; position: absolute; background-color: green"></div>
            <span id="progressbar_label" style="position: absolute; left: 35%; top: 20%">Uploading...</span>
        </div>
    </div>
Run Code Online (Sandbox Code Playgroud)

用于查询,调用控制器和更新进度条的Javascript代码:

        var progressBarStart = function() {
            $("#progressbar_container").show();
        }

        var progressBarUpdate = function (percentage) {
            $('#progressbar_label').html(percentage + "%");
            $("#progressbar").width(percentage + "%");
        }

        var progressBarComplete = function() {
            $("#progressbar_container").fadeOut(500);
        }

        var file;

        $('#fileInput').change(function(e) {
            file = e.target.files[0];
        });

        var uploadCompleted = function() {
            var formData = new FormData();
            formData.append('fileName', file.name);
            formData.append('completed', true);

            var xhr2 = new XMLHttpRequest();
            xhr2.onload = function() {
                progressBarUpdate(100);
                progressBarComplete();
            }
            xhr2.open("POST", "/Upload/UploadComplete?fileName=" + file.name + "&complete=" + 1, true);
            xhr2.send(formData);
        }

        var multiUpload = function(count, counter, blob, completed, start, end, bytesPerChunk) {
            counter = counter + 1;
            if (counter <= count) {
                var chunk = blob.slice(start, end);
                var xhr = new XMLHttpRequest();
                xhr.onload = function() {
                    start = end;
                    end = start + bytesPerChunk;
                    if (count == counter) {
                        uploadCompleted();
                    } else {
                        var percentage = (counter / count) * 100;
                        progressBarUpdate(percentage);
                        multiUpload(count, counter, blob, completed, start, end, bytesPerChunk);
                    }
                }
                xhr.open("POST", "/Upload/MultiUpload?id=" + counter.toString() + "&fileName=" + file.name, true);
                xhr.send(chunk);
            }
        }

        $("#VideoDiv").on("click", "#btnUpload", function() {
            var blob = file;
            var bytesPerChunk = 3757000;
            var size = blob.size;

            var start = 0;
            var end = bytesPerChunk;
            var completed = 0;
            var count = size % bytesPerChunk == 0 ? size / bytesPerChunk : Math.floor(size / bytesPerChunk) + 1;
            var counter = 0;
            progressBarStart();
            multiUpload(count, counter, blob, completed, start, end, bytesPerChunk);
        });
Run Code Online (Sandbox Code Playgroud)

这里是上传控制器,用于存储chucnk("App_Data/Videos/Temp"),然后合并它们并存储在("App_Data/Videos")中:

public class UploadController : Controller
{
    private string videoAddress = "~/App_Data/Videos";

    [HttpPost]
    public string MultiUpload(string id, string fileName)
    {
        var chunkNumber = id;
        var chunks = Request.InputStream;
        string path = Server.MapPath(videoAddress+"/Temp");
        string newpath = Path.Combine(path, fileName+chunkNumber);
        using (FileStream fs = System.IO.File.Create(newpath))
        {
            byte[] bytes = new byte[3757000];
            int bytesRead;
            while ((bytesRead=Request.InputStream.Read(bytes,0,bytes.Length))>0)
            {
                fs.Write(bytes,0,bytesRead);
            }
        }
        return "done";
    }

    [HttpPost]
    public string UploadComplete(string fileName, string complete)
    {
        string tempPath = Server.MapPath(videoAddress + "/Temp");
        string videoPath = Server.MapPath(videoAddress);
        string newPath = Path.Combine(tempPath, fileName);
        if (complete=="1")
        {
            string[] filePaths = Directory.GetFiles(tempPath).Where(p=>p.Contains(fileName)).OrderBy(p => Int32.Parse(p.Replace(fileName, "$").Split('$')[1])).ToArray();
            foreach (string filePath in filePaths)
            {
                MergeFiles(newPath, filePath);
            }
        }
        System.IO.File.Move(Path.Combine(tempPath, fileName),Path.Combine(videoPath,fileName));
        return "success";
    }

    private static void MergeFiles(string file1, string file2)
    {
        FileStream fs1 = null;
        FileStream fs2 = null;
        try
        {
            fs1 = System.IO.File.Open(file1, FileMode.Append);
            fs2 = System.IO.File.Open(file2, FileMode.Open);
            byte[] fs2Content = new byte[fs2.Length];
            fs2.Read(fs2Content, 0, (int) fs2.Length);
            fs1.Write(fs2Content, 0, (int) fs2.Length);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message + " : " + ex.StackTrace);
        }
        finally
        {
            if (fs1 != null) fs1.Close();
            if (fs2 != null) fs2.Close();
            System.IO.File.Delete(file2);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果两个用户同时上传具有相同名称的文件,则会出现一些问题,您必须处理此问题.通过读取responseText,您可以捕获一些错误和异常并修剪它.