我尝试将插件blueimp放到我的Asp.Net MVC应用程序中。 我的上传目标大约是1GB。 如何处理服务器端的块文件上传文件?
I try to put the plugin blueimp to my Asp.Net MVC application. My upload target is about 1GB. How to handle chunk file upload fle in server side?
最满意答案
我想你的意思是来自blueimp的FileUpload jquery模块。 这就是我在项目中处理它的方式。 我上传的图片不超过30MB。 所以这个例子只是关于代码,而不是你需要处理1GB文件的事实。
这是javascript代码的一部分。 没什么特别的。 我只关注FileUpload文档和示例。 我只发送了几个属性(包括AntiforgeryToken) - 这些都不是正确行为所必需的。
$("#file-upload").fileupload({ url: 'upload-file', dataType: 'json', autoUpload: false, maxChunkSize: 5000000, progressInterval: 1000, bitrateInterval: 1000 }).on('fileuploadadd', function (e, data) { fileData = data; // save data to be able to submit them later if (window.File && window.Blob) { // update form data data.formData = { uploadFolder: '/upload-folder/some-guid', __RequestVerificationToken: $("#upload-form").find('input[name=__RequestVerificationToken]').val() }; } else { // chunk upload not supported } }); $("#file-submit").on('click', function (e) { e.preventDefault(); fileData.submit(); });在服务器端,我有一个模型类:
public class UploadViewRequest { public Guid UploadFolder { get; set; } public bool IsChunk { get; set; } public int ChunkNumber { get; set; } public bool IsFirst { get; set; } public bool IsLast { get; set; } public HttpPostedFileBase OriginalFile { get; set; } public bool JsonAccepted { get; set; } }我为这个类编写了一个自定义模型绑定器,这样我就可以看到它是整个文件还是只是一个块,如果是,那么我将要处理的文件的哪一部分:
public class UploadViewRequestBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { UploadViewRequest model = base.BindModel(controllerContext, bindingContext) as UploadViewRequest; string rangeHeader = controllerContext.HttpContext.Request.Headers["Content-Range"]; if (string.IsNullOrEmpty(rangeHeader)) model.IsChunk = false; else { model.IsChunk = true; Match match = Regex.Match(rangeHeader, "^bytes ([\\d]+)-([\\d]+)\\/([\\d]+)$", RegexOptions.IgnoreCase); int bytesFrom = int.Parse(match.Groups[1].Value); int bytesTo = int.Parse(match.Groups[2].Value); int bytesFull = int.Parse(match.Groups[3].Value); if (bytesTo == bytesFull) model.IsLast = true; else model.IsLast = false; if (bytesFrom == 0) { model.ChunkNumber = 1; model.IsFirst = true; } else { int bytesSize = bytesTo - bytesFrom + 1; model.ChunkNumber = (bytesFrom / bytesSize) + 1; model.IsFirst = false; } } if (controllerContext.HttpContext.Request["HTTP_ACCEPT"] != null && controllerContext.HttpContext.Request["HTTP_ACCEPT"].Contains("application/json")) model.JsonAccepted = true; else model.JsonAccepted = false; return model; } }这是控制器动作方法:
public ActionResult Upload(UploadViewRequest request) { var path = ''; // create path FileStatus status = null; try { if (request.IsChunk) { if (request.IsFirst ) { // do some stuff that has to be done before the file starts uploading } var inputStream = request.OriginalFile.InputStream; using (var fs = new FileStream(path, FileMode.Append, FileAccess.Write)) { var buffer = new byte[1024]; var l = inputStream.Read(buffer, 0, 1024); while (l > 0) { fs.Write(buffer, 0, l); l = inputStream.Read(buffer, 0, 1024); } fs.Flush(); fs.Close(); } status = new FileStatus(new FileInfo(path)); if (request.IsLast) { // do some stuff that has to be done after the file is uploaded } } else { file.SaveAs(path); status = new FileStatus(new FileInfo(path)); } } catch { status = new FileStatus { error = "Something went wrong" }; } // this is just a browser json support/compatibility workaround if (request.JsonAccepted) return Json(status); else return Json(status, "text/plain"); }FileStatus类我用作返回值并将其转换为json(对于UploadFile jquery模块):
public class FileStatus { public const string HandlerPath = "/"; public string group { get; set; } public string name { get; set; } public string type { get; set; } public int size { get; set; } public string progress { get; set; } public string url { get; set; } public string thumbnail_url { get; set; } public string delete_url { get; set; } public string delete_type { get; set; } public string error { get; set; } public FileStatus() { } public FileStatus(FileInfo fileInfo) { SetValues(fileInfo.Name, (int)fileInfo.Length, fileInfo.FullName); } public FileStatus(string fileName, int fileLength, string fullPath) { SetValues(fileName, fileLength, fullPath); } private void SetValues(string fileName, int fileLength, string fullPath) { name = fileName; type = "image/png"; size = fileLength; progress = "1.0"; url = HandlerPath + "/file/upload?f=" + fileName; delete_url = HandlerPath + "/file/delete?f=" + fileName; delete_type = "DELETE"; thumbnail_url = "/Content/img/generalFile.png"; } }I suppose you mean FileUpload jquery module from blueimp. This is how I handle it in my project. I upload large images that don't go over 30MB. So this example is merely about the code, not the fact that you need to handle 1GB files.
This is part of the javascript code. There's nothing special. I just follow the FileUpload documentation and example. I just send couple more properties (inlcuding AntiforgeryToken) - that are not required for the correct behavior.
$("#file-upload").fileupload({ url: 'upload-file', dataType: 'json', autoUpload: false, maxChunkSize: 5000000, progressInterval: 1000, bitrateInterval: 1000 }).on('fileuploadadd', function (e, data) { fileData = data; // save data to be able to submit them later if (window.File && window.Blob) { // update form data data.formData = { uploadFolder: '/upload-folder/some-guid', __RequestVerificationToken: $("#upload-form").find('input[name=__RequestVerificationToken]').val() }; } else { // chunk upload not supported } }); $("#file-submit").on('click', function (e) { e.preventDefault(); fileData.submit(); });On the server side I have a model class:
public class UploadViewRequest { public Guid UploadFolder { get; set; } public bool IsChunk { get; set; } public int ChunkNumber { get; set; } public bool IsFirst { get; set; } public bool IsLast { get; set; } public HttpPostedFileBase OriginalFile { get; set; } public bool JsonAccepted { get; set; } }And I wrote a custom model binder for this class, so that I can see if it's whole file or just a chunk and if yes, that what part of the file I'm going to process:
public class UploadViewRequestBinder : DefaultModelBinder { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { UploadViewRequest model = base.BindModel(controllerContext, bindingContext) as UploadViewRequest; string rangeHeader = controllerContext.HttpContext.Request.Headers["Content-Range"]; if (string.IsNullOrEmpty(rangeHeader)) model.IsChunk = false; else { model.IsChunk = true; Match match = Regex.Match(rangeHeader, "^bytes ([\\d]+)-([\\d]+)\\/([\\d]+)$", RegexOptions.IgnoreCase); int bytesFrom = int.Parse(match.Groups[1].Value); int bytesTo = int.Parse(match.Groups[2].Value); int bytesFull = int.Parse(match.Groups[3].Value); if (bytesTo == bytesFull) model.IsLast = true; else model.IsLast = false; if (bytesFrom == 0) { model.ChunkNumber = 1; model.IsFirst = true; } else { int bytesSize = bytesTo - bytesFrom + 1; model.ChunkNumber = (bytesFrom / bytesSize) + 1; model.IsFirst = false; } } if (controllerContext.HttpContext.Request["HTTP_ACCEPT"] != null && controllerContext.HttpContext.Request["HTTP_ACCEPT"].Contains("application/json")) model.JsonAccepted = true; else model.JsonAccepted = false; return model; } }and this is the controller action method:
public ActionResult Upload(UploadViewRequest request) { var path = ''; // create path FileStatus status = null; try { if (request.IsChunk) { if (request.IsFirst ) { // do some stuff that has to be done before the file starts uploading } var inputStream = request.OriginalFile.InputStream; using (var fs = new FileStream(path, FileMode.Append, FileAccess.Write)) { var buffer = new byte[1024]; var l = inputStream.Read(buffer, 0, 1024); while (l > 0) { fs.Write(buffer, 0, l); l = inputStream.Read(buffer, 0, 1024); } fs.Flush(); fs.Close(); } status = new FileStatus(new FileInfo(path)); if (request.IsLast) { // do some stuff that has to be done after the file is uploaded } } else { file.SaveAs(path); status = new FileStatus(new FileInfo(path)); } } catch { status = new FileStatus { error = "Something went wrong" }; } // this is just a browser json support/compatibility workaround if (request.JsonAccepted) return Json(status); else return Json(status, "text/plain"); }The FileStatus class I use as a return value and transform it into json (for the UploadFile jquery module):
public class FileStatus { public const string HandlerPath = "/"; public string group { get; set; } public string name { get; set; } public string type { get; set; } public int size { get; set; } public string progress { get; set; } public string url { get; set; } public string thumbnail_url { get; set; } public string delete_url { get; set; } public string delete_type { get; set; } public string error { get; set; } public FileStatus() { } public FileStatus(FileInfo fileInfo) { SetValues(fileInfo.Name, (int)fileInfo.Length, fileInfo.FullName); } public FileStatus(string fileName, int fileLength, string fullPath) { SetValues(fileName, fileLength, fullPath); } private void SetValues(string fileName, int fileLength, string fullPath) { name = fileName; type = "image/png"; size = fileLength; progress = "1.0"; url = HandlerPath + "/file/upload?f=" + fileName; delete_url = HandlerPath + "/file/delete?f=" + fileName; delete_type = "DELETE"; thumbnail_url = "/Content/img/generalFile.png"; } }更多推荐
发布评论