.net - 如何使用 ng-Flow 在 ASP.NET 中分块上传文件

标签 .net file-upload chunks flow-js

我正在尝试实现 ng-flow https://github.com/flowjs/ng-flow用于文件上传。它以块的形式上传文件,我在客户端上成功设置了它,但我不确定如何在 web api 方法中处理后端的文件。

  public void Upload()
        {
            //how to handle file?
        }

请求包含以下信息
enter image description here

最佳答案

这是我想出的用于保存块并组合它们的 ASP.NET Web API Controller 。

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Net;
using System.Net.Http;
using System.IO;
using System.Web;
using System.Web.Http;

namespace Api.Controllers
{
    [RoutePrefix("api")]
    public class FlowUploadController : ApiController
    {

        string root = Path.Combine(Path.GetTempPath(), "FlowUpload");

        [Route("flowupload"), AcceptVerbs("GET")]
        public object Upload(
            int flowChunkNumber,
            string flowIdentifier)
        {
            if (ChunkIsHere(flowChunkNumber, flowIdentifier))
            {
                return Request.CreateResponse(HttpStatusCode.OK);
            }
            else
            {
                return Request.CreateResponse(HttpStatusCode.NotFound);
            }
        }

        [Route("flowupload"), AcceptVerbs("POST")]
        public async Task<object> Upload()
        {
            // Check if the request contains multipart/form-data.
            if (!Request.Content.IsMimeMultipartContent())
            {
                throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
            }
            if (!Directory.Exists(root)) Directory.CreateDirectory(root);
            var provider = new MultipartFormDataStreamProvider(root);
            try
            {
                await Request.Content.ReadAsMultipartAsync(provider);
                int chunkNumber = Convert.ToInt32(provider.FormData["flowChunkNumber"]);
                int totalChunks = Convert.ToInt32(provider.FormData["flowTotalChunks"]);
                string identifier = provider.FormData["flowIdentifier"];
                string filename = provider.FormData["flowFilename"];
                // Rename generated file
                MultipartFileData chunk = provider.FileData[0]; // Only one file in multipart message
                RenameChunk(chunk, chunkNumber, identifier);
                // Assemble chunks into single file if they're all here
                TryAssembleFile(identifier, totalChunks, filename);
                // Success
                return Request.CreateResponse(HttpStatusCode.OK);
            }
            catch (System.Exception e)
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
            }

        }

        private string GetChunkFileName(int chunkNumber, string identifier)
        {
            return Path.Combine(root, string.Format("{0}_{1}", identifier, chunkNumber.ToString()));
        }

        private void RenameChunk(MultipartFileData chunk, int chunkNumber, string identifier)
        {
            string generatedFileName = chunk.LocalFileName;
            string chunkFileName = GetChunkFileName(chunkNumber, identifier);
            if (File.Exists(chunkFileName)) File.Delete(chunkFileName);
            File.Move(generatedFileName, chunkFileName);

        }

        private string GetFileName(string identifier)
        {
            return Path.Combine(root, identifier);
        }

        private bool ChunkIsHere(int chunkNumber, string identifier)
        {
            string fileName = GetChunkFileName(chunkNumber, identifier);
            return File.Exists(fileName);
        }

        private bool AllChunksAreHere(string identifier, int totalChunks)
        {
            for (int chunkNumber = 1; chunkNumber <= totalChunks; chunkNumber++)
                if (!ChunkIsHere(chunkNumber, identifier)) return false;
            return true;
        }

        private void TryAssembleFile(string identifier, int totalChunks, string filename)
        {
            if (AllChunksAreHere(identifier, totalChunks))
            {
                // Create a single file
                var consolidatedFileName = GetFileName(identifier);
                using (var destStream = File.Create(consolidatedFileName, 15000))
                {
                    for (int chunkNumber = 1; chunkNumber <= totalChunks; chunkNumber++)
                    {
                        var chunkFileName = GetChunkFileName(chunkNumber, identifier);
                        using (var sourceStream = File.OpenRead(chunkFileName))
                        {
                            sourceStream.CopyTo(destStream);
                        }
                    }
                    destStream.Close();
                }
                // Rename consolidated with original name of upload
                filename = Path.GetFileName(filename); // Strip to filename if directory is specified (avoid cross-directory attack)
                string realFileName = Path.Combine(root, filename);
                if (File.Exists(filename)) File.Delete(realFileName);
                File.Move(consolidatedFileName, realFileName);
                // Delete chunk files
                for (int chunkNumber = 1; chunkNumber <= totalChunks; chunkNumber++)
                {
                    var chunkFileName = GetChunkFileName(chunkNumber, identifier);
                    File.Delete(chunkFileName);
                }
            }
        }

    }
}

关于.net - 如何使用 ng-Flow 在 ASP.NET 中分块上传文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24475890/

相关文章:

c# - 从 WCF 服务返回的 JSON 数据包含转义字符

tomcat - 长文件上传是否可以由一组 (Tomcat) 服务器处理,其中如果一台服务器在上传过程中失败/崩溃,另一台服务器会接替它

javascript - 使用 HTML5 文件上传 API 的可恢复上传 -

c - 如何通过套接字 : one buffer, 分散/聚集或 readdir 发送数据?

python - Pandas - 是否可以使用 chunk= 参数读取 "rewind"read_csv?

c# - 从 ASP.NET 5 Beta 4 升级到 Beta 5 时出错

c# - 如何在 Visual Studio 2008 中分析 MsTest 的单元测试?

c# - ASP.NET Core Web API - 如何在中间件管道中隐藏 DbContext 事务?

php - CKFinder 3 无法上传文件

spring-batch - 在Spring Batch中如何实现跳过?