Update ChunkUploadController.cs
This commit is contained in:
Родитель
8d6221185b
Коммит
f38ab4017e
|
@ -1,59 +1,23 @@
|
|||
using System;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Json;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace aspnetcore_upload.Controllers
|
||||
{
|
||||
|
||||
public class ChunkUploadController : Controller
|
||||
{
|
||||
|
||||
private readonly string _root;
|
||||
private readonly IWebHostEnvironment _webHhostingEnvironment;
|
||||
|
||||
public ChunkUploadController(IWebHostEnvironment webHostingEnvironment)
|
||||
{
|
||||
_webHhostingEnvironment = webHostingEnvironment;
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class ChunkMetaData
|
||||
{
|
||||
[DataMember(Name = "uploadUid")]
|
||||
public string UploadUid { get; set; }
|
||||
[DataMember(Name = "fileName")]
|
||||
public string FileName { get; set; }
|
||||
[DataMember(Name = "contentType")]
|
||||
public string ContentType { get; set; }
|
||||
[DataMember(Name = "chunkIndex")]
|
||||
public long ChunkIndex { get; set; }
|
||||
[DataMember(Name = "totalChunks")]
|
||||
public long TotalChunks { get; set; }
|
||||
[DataMember(Name = "totalFileSize")]
|
||||
public long TotalFileSize { get; set; }
|
||||
}
|
||||
|
||||
public void AppendToFile(string fullPath, Stream content)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (FileStream stream = new FileStream(fullPath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
|
||||
{
|
||||
using (content)
|
||||
{
|
||||
content.CopyTo(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
_root = Path.Combine(_webHhostingEnvironment.WebRootPath, "Upload_Directory");
|
||||
}
|
||||
|
||||
public ActionResult Save(List<IFormFile> files)
|
||||
|
@ -63,47 +27,77 @@ namespace aspnetcore_upload.Controllers
|
|||
foreach (var file in files)
|
||||
{
|
||||
// Some browsers send file names with full path. This needs to be stripped.
|
||||
//var fileName = Path.GetFileName(file.FileName);
|
||||
//var physicalPath = Path.Combine(_webHhostingEnvironment.WebRootPath, "Upload_Directory", fileName);
|
||||
|
||||
// The files are not actually saved in this demo
|
||||
// file.SaveAs(physicalPath);
|
||||
var fileName = Path.GetFileName(file.FileName);
|
||||
var physicalPath = Path.Combine(_root, fileName);
|
||||
|
||||
using(var uploadedFile = file.OpenReadStream())
|
||||
using (var stream = new FileStream(physicalPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
|
||||
{
|
||||
uploadedFile.CopyTo(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return an empty string to signify success
|
||||
return Content("");
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Route("api/Chunk/Upload")]
|
||||
[HttpPost]
|
||||
public ActionResult ChunkSave(List<IFormFile> files, string metaData)
|
||||
{
|
||||
// This is not a chunk upload, pass it off to the normal Save method
|
||||
if (metaData == null)
|
||||
{
|
||||
return Save(files);
|
||||
}
|
||||
|
||||
MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(metaData));
|
||||
var ms = new MemoryStream(Encoding.UTF8.GetBytes(metaData));
|
||||
var serializer = new DataContractJsonSerializer(typeof(ChunkMetaData));
|
||||
ChunkMetaData somemetaData = serializer.ReadObject(ms) as ChunkMetaData;
|
||||
string path = String.Empty;
|
||||
var somemetaData = serializer.ReadObject(ms) as ChunkMetaData;
|
||||
|
||||
// The Name of the Upload component is "files"
|
||||
if (files != null)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
//path = Path.Combine(_webHhostingEnvironment.WebRootPath, "Upload_Directory", somemetaData.FileName);
|
||||
// ********************************** //
|
||||
// ********** Scenario 1 ************ //
|
||||
// ********************************** //
|
||||
// If the upload is in sequential order, you can just appends the chunks to what has already been written to disk
|
||||
//var path = Path.Combine(_root, somemetaData.FileName);
|
||||
//using (var uploadedChunkStream = file.OpenReadStream())
|
||||
//using(var stream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
|
||||
//{
|
||||
// uploadedChunkStream.CopyTo(stream);
|
||||
//}
|
||||
|
||||
//AppendToFile(path, file.InputStream);
|
||||
|
||||
// ********************************** //
|
||||
// ********** Scenario 2 ************ //
|
||||
// ********************************** //
|
||||
// Un-sequential means you will need to develop a system to keep track of each chunks and assembly them
|
||||
// together when all the chunks have been uploaded.
|
||||
// The ChunkMetaData gives you all the information you need to keep track and reassemble
|
||||
|
||||
// step 1. Save the chunk
|
||||
var tempChunkFilePath = Path.Combine(_webHhostingEnvironment.WebRootPath, "Upload_Directory", $"{somemetaData.UploadUid}_{somemetaData.ChunkIndex}");
|
||||
using (var uploadedChunkStream = file.OpenReadStream())
|
||||
using (var chunkFileStream = System.IO.File.OpenWrite(tempChunkFilePath))
|
||||
{
|
||||
uploadedChunkStream.CopyTo(chunkFileStream);
|
||||
}
|
||||
|
||||
// Step 2. Try to assemble the final file
|
||||
// In this highly unoptimized implementation, only the lats attempt will have the finished file
|
||||
TryAssembleFile(somemetaData.UploadUid, somemetaData.TotalChunks, somemetaData.FileName);
|
||||
}
|
||||
}
|
||||
|
||||
// Return an empty string to signify success
|
||||
return Content("");
|
||||
}
|
||||
|
||||
|
||||
[Route("api/Chunk/Remove")]
|
||||
[HttpPost]
|
||||
public ActionResult Async_Remove(string[] fileNames)
|
||||
|
@ -127,5 +121,82 @@ namespace aspnetcore_upload.Controllers
|
|||
// Return an empty string to signify success
|
||||
return Content("");
|
||||
}
|
||||
|
||||
|
||||
private void TryAssembleFile(string uuid, long totalChunks, string filename)
|
||||
{
|
||||
// PHASE 1 - VERIFYING
|
||||
for (var chunkIndex = 0; chunkIndex <= totalChunks - 1; chunkIndex++)
|
||||
{
|
||||
var chunkFilePath = Path.Combine(_webHhostingEnvironment.WebRootPath, "Upload_Directory", $"{uuid}_{chunkIndex}");
|
||||
|
||||
// If any of these chunk files are missing, then we know we're not done, break and exit.
|
||||
if (!System.IO.File.Exists(chunkFilePath))
|
||||
{
|
||||
// Exit the method entirely
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// PHASE 2 - COMBINING
|
||||
// Create a single file to combine everything
|
||||
var tempFinalFilePath = Path.Combine(_webHhostingEnvironment.WebRootPath, "Upload_Directory", $"{uuid}");
|
||||
|
||||
// Open a file stream
|
||||
using (var destStream = System.IO.File.Create(tempFinalFilePath))
|
||||
{
|
||||
// iterate over each chunk, in the order of the ChunkIndex
|
||||
for (var chunkIndex = 0; chunkIndex <= totalChunks - 1; chunkIndex++)
|
||||
{
|
||||
var chunkFileName = Path.Combine(_webHhostingEnvironment.WebRootPath, "Upload_Directory", $"{uuid}_{chunkIndex}");
|
||||
|
||||
// Open the chunk's filestream
|
||||
using var sourceStream = System.IO.File.OpenRead(chunkFileName);
|
||||
|
||||
// Copy the chunk to the end of the main file stream
|
||||
sourceStream.CopyTo(destStream);
|
||||
}
|
||||
}
|
||||
|
||||
// PHASE 3 - FINALIZING
|
||||
|
||||
// Now that we have a combined file, lets move it to the final destination
|
||||
// Some browsers send file names with full path. This needs to be stripped.
|
||||
var cleanFileName = Path.GetFileName(filename);
|
||||
var filePath = Path.Combine(_root, cleanFileName);
|
||||
|
||||
if (System.IO.File.Exists(filePath))
|
||||
System.IO.File.Delete(filePath);
|
||||
|
||||
System.IO.File.Move(tempFinalFilePath, filePath);
|
||||
|
||||
|
||||
// PHASE 4 - CLEANUP
|
||||
// Delete temp chunk files
|
||||
for (var chunkIndex = 0; chunkIndex <= totalChunks - 1; chunkIndex++)
|
||||
{
|
||||
var chunkFileName = Path.Combine(_webHhostingEnvironment.WebRootPath, "Upload_Directory", $"{uuid}_{chunkIndex}");
|
||||
|
||||
if (System.IO.File.Exists(chunkFileName))
|
||||
System.IO.File.Delete(chunkFileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class ChunkMetaData
|
||||
{
|
||||
[DataMember(Name = "uploadUid")]
|
||||
public string UploadUid { get; set; }
|
||||
[DataMember(Name = "fileName")]
|
||||
public string FileName { get; set; }
|
||||
[DataMember(Name = "contentType")]
|
||||
public string ContentType { get; set; }
|
||||
[DataMember(Name = "chunkIndex")]
|
||||
public long ChunkIndex { get; set; }
|
||||
[DataMember(Name = "totalChunks")]
|
||||
public long TotalChunks { get; set; }
|
||||
[DataMember(Name = "totalFileSize")]
|
||||
public long TotalFileSize { get; set; }
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче