现如今,世面上流行着许多前端上传组件,例如:Uploadify(
http://www.uploadify.com/),Fine Uploader,等等。这篇博客从头开始,介绍如何在ASP.NET MVC中使用Fine Uploader。
Fine Uploader官网:
https://fineuploader.com/demos.html
代码结果如下图所示,可以选择本地文件之后点击上传,文件会被传输到服务器根目录下的Upload文件夹中(文件夹的名称是代码中定义的)。
![](https://i-blog.csdnimg.cn/blog_migrate/a6c6323b16aab53a7678acbb205d1d1b.png)
Step By Step Process:
1. 在官网的下载页面下载Fine Uploader压缩包。
https://fineuploader.com/customize.html
![](https://i-blog.csdnimg.cn/blog_migrate/684b0a19359005e10c6fc1af097c51b0.png)
2. 新建MVC工程并将刚刚下载之后的解压文件夹添加到项目中。
![](https://i-blog.csdnimg.cn/blog_migrate/4886207b48b2af12056366a57c4f186c.png)
3.在Models中添加类文件 FineUpload.cs 和 FineUploadResult.cs,Controller中添加UploaderController。
(这里参考了Github上的Server样例
https://github.com/FineUploader/server-examples,至于这两个类文件是否应该放在Models文件夹下有待商榷。)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System.IO; 2 using System.Web.Mvc; 3 4 namespace FineUploaderTest.Web.Model 5 { 6 [ModelBinder(typeof(ModelBinder))] 7 public class FineUpload 8 { 9 public string Filename { get; set; } 10 public Stream InputStream { get; set; } 11 12 public void SaveAs(string destination, bool overwrite = false, bool autoCreateDirectory = true) 13 { 14 if (autoCreateDirectory) 15 { 16 var directory = new FileInfo(destination).Directory; 17 if (directory != null) directory.Create(); 18 } 19 20 using (var file = new FileStream(destination, overwrite ? FileMode.Create : FileMode.CreateNew)) 21 InputStream.CopyTo(file); 22 } 23 24 public class ModelBinder : IModelBinder 25 { 26 public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 27 { 28 var request = controllerContext.RequestContext.HttpContext.Request; 29 var formUpload = request.Files.Count > 0; 30 31 // find filename 32 var xFileName = request.Headers["X-File-Name"]; 33 var qqFile = request["qqfile"]; 34 var formFilename = formUpload ? request.Files[0].FileName : null; 35 36 var upload = new FineUpload 37 { 38 Filename = xFileName ?? qqFile ?? formFilename, 39 InputStream = formUpload ? request.Files[0].InputStream : request.InputStream 40 }; 41 42 return upload; 43 } 44 } 45 46 } 47 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using System.Web.Mvc; 2 using Newtonsoft.Json.Linq; 3 4 namespace FineUploaderTest.Web.Model 5 { 6 /// <remarks> 7 /// Docs at https://github.com/Widen/fine-uploader/blob/master/server/readme.md 8 /// </remarks> 9 public class FineUploaderResult : ActionResult 10 { 11 public const string ResponseContentType = "text/plain"; 12 13 private readonly bool _success; 14 private readonly string _error; 15 private readonly bool? _preventRetry; 16 private readonly JObject _otherData; 17 18 public FineUploaderResult(bool success, object otherData = null, string error = null, bool? preventRetry = null) 19 { 20 _success = success; 21 _error = error; 22 _preventRetry = preventRetry; 23 24 if (otherData != null) 25 _otherData = JObject.FromObject(otherData); 26 } 27 28 public override void ExecuteResult(ControllerContext context) 29 { 30 var response = context.HttpContext.Response; 31 response.ContentType = ResponseContentType; 32 33 response.Write(BuildResponse()); 34 } 35 36 public string BuildResponse() 37 { 38 var response = _otherData ?? new JObject(); 39 response["success"] = _success; 40 41 if (!string.IsNullOrWhiteSpace(_error)) 42 response["error"] = _error; 43 44 if (_preventRetry.HasValue) 45 response["preventRetry"] = _preventRetry.Value; 46 47 return response.ToString(); 48 } 49 } 50 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 using FineUploaderTest.Web.Model; 2 using System; 3 using System.Collections.Generic; 4 using System.IO; 5 using System.Linq; 6 using System.Web; 7 using System.Web.Mvc; 8 9 namespace FineUploaderTest.Web.Controllers 10 { 11 public class UploaderController : Controller 12 { 13 // GET: Uploader 14 public ActionResult Index() 15 { 16 return View(); 17 } 18 19 [HttpPost] 20 public FineUploaderResult UploadFile(FineUpload upload) 21 { 22 var dir = Server.MapPath("~/Upload"); 23 int pos1 = upload.Filename.LastIndexOf("\\"); 24 string fileName = pos1 == -1 ? upload.Filename : upload.Filename.Substring(pos1 + 1, upload.Filename.Length - pos1 - 1); 25 string storeName = Guid.NewGuid() + fileName; 26 var filePath = Path.Combine(dir, storeName); 27 try 28 { 29 upload.SaveAs(filePath); 30 ViewBag.SourcePath = filePath; 31 } 32 catch (Exception ex) 33 { 34 return new FineUploaderResult(false, error: ex.Message); 35 } 36 // the anonymous object in the result below will be convert to json and set back to the browser 37 return new FineUploaderResult(true, new { extraInformation = filePath }); 38 } 39 } 40 }
添加代码之后的文件夹结构:
![](https://i-blog.csdnimg.cn/blog_migrate/f923fde9e5c81765c1e1b3025700b945.png)
4. 重写Home文件夹下的Index.cshtml页面
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 @{ 2 ViewBag.Title = "Test Fine Upload"; 3 } 4 5 <h3>Test Fine Upload</h3> 6 7 <link href="~/fine-uploader/fine-uploader-new.css" rel="stylesheet" /> 8 9 <style> 10 #trigger-upload { 11 color: white; 12 background-color: #00ABC7; 13 font-size: 14px; 14 padding: 7px 20px; 15 background-image: none; 16 } 17 18 #Query { 19 color: white; 20 background-color: #00ABC7; 21 font-size: 14px; 22 padding: 7px 20px; 23 background-image: none; 24 } 25 26 #fine-uploader-manual-trigger .qq-upload-button { 27 margin-right: 15px; 28 } 29 30 #fine-uploader-manual-trigger .buttons { 31 width: 36%; 32 } 33 34 #fine-uploader-manual-trigger .qq-uploader .qq-total-progress-bar-container { 35 width: 60%; 36 } 37 </style> 38 39 <div id="fine-uploader-manual-trigger"></div> 40 <div id="BeginQuery" style="margin-top:30px;"> 41 <p><a id="Query" class="btn btn-default">Test File Name</a></p> 42 </div> 43 44 </br> 45 <div class="panel panel-default"> 46 <div class="panel-heading"> 47 <h3 class="panel-title">注意事项</h3> 48 </div> 49 <div class="panel-body"> 50 <ul> 51 <li>文件最大支持<strong>20M</strong></li> 52 <li>Some other info.</li> 53 </ul> 54 </div> 55 </div> 56 57 @section Scripts { 58 <script src="~/fine-uploader/jquery.fine-uploader.js"></script> 59 <!-- Fine Uploader Thumbnails template w/ customization 60 ====================================================================== --> 61 <script type="text/template" id="qq-template-manual-trigger"> 62 <div class="qq-uploader-selector qq-uploader" qq-drop-area-text="Drop files here"> 63 <div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container"> 64 <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div> 65 </div> 66 <div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone> 67 <span class="qq-upload-drop-area-text-selector"></span> 68 </div> 69 <div class="buttons"> 70 <div class="qq-upload-button-selector qq-upload-button"> 71 <div>选择文件</div> 72 </div> 73 <button type="button" id="trigger-upload" class="btn btn-primary"> 74 <i class="icon-upload icon-white"></i> 上传 75 </button> 76 </div> 77 <span class="qq-drop-processing-selector qq-drop-processing"> 78 <span>Processing dropped files...</span> 79 <span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span> 80 </span> 81 <ul class="qq-upload-list-selector qq-upload-list" aria-live="polite" aria-relevant="additions removals"> 82 <li> 83 <div class="qq-progress-bar-container-selector"> 84 <div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div> 85 </div> 86 <span class="qq-upload-spinner-selector qq-upload-spinner"></span> 87 <img class="qq-thumbnail-selector" qq-max-size="100" qq-server-scale> 88 <span class="qq-upload-file-selector qq-upload-file"></span> 89 <span class="qq-edit-filename-icon-selector qq-edit-filename-icon" aria-label="Edit filename"></span> 90 <input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text"> 91 <span class="qq-upload-size-selector qq-upload-size"></span> 92 <button type="button" class="qq-btn qq-upload-cancel-selector qq-upload-cancel">Cancel</button> 93 <button type="button" class="qq-btn qq-upload-retry-selector qq-upload-retry">Retry</button> 94 <button type="button" class="qq-btn qq-upload-delete-selector qq-upload-delete">Delete</button> 95 <span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span> 96 </li> 97 </ul> 98 99 <dialog class="qq-alert-dialog-selector"> 100 <div class="qq-dialog-message-selector"></div> 101 <div class="qq-dialog-buttons"> 102 <button type="button" class="qq-cancel-button-selector">Close</button> 103 </div> 104 </dialog> 105 106 <dialog class="qq-confirm-dialog-selector"> 107 <div class="qq-dialog-message-selector"></div> 108 <div class="qq-dialog-buttons"> 109 <button type="button" class="qq-cancel-button-selector">No</button> 110 <button type="button" class="qq-ok-button-selector">Yes</button> 111 </div> 112 </dialog> 113 114 <dialog class="qq-prompt-dialog-selector"> 115 <div class="qq-dialog-message-selector"></div> 116 <input type="text"> 117 <div class="qq-dialog-buttons"> 118 <button type="button" class="qq-cancel-button-selector">Cancel</button> 119 <button type="button" class="qq-ok-button-selector">Ok</button> 120 </div> 121 </dialog> 122 </div> 123 </script> 124 <script> 125 var filePath; 126 $('#fine-uploader-manual-trigger').fineUploader({ 127 template: 'qq-template-manual-trigger', 128 request: { 129 endpoint: '/Uploader/UploadFile' 130 }, 131 thumbnails: { 132 placeholders: { 133 waitingPath: '/source/placeholders/waiting-generic.png', 134 notAvailablePath: '/source/placeholders/not_available-generic.png' 135 } 136 }, 137 autoUpload: false, 138 deleteFile: { 139 enabled: false, // if want to delete, make this true 140 forceConfirm: true, 141 endpoint: '/Home/DeleteFile' 142 }, 143 validation: { 144 allowedExtensions: ['txt', 'csv'], 145 itemLimit: 1, 146 sizeLimit: 51200000 // 50 kB = 50 * 1024 bytes 147 }, 148 callbacks: { 149 onComplete: function (id, fileName, responseJSON) { 150 filePath = responseJSON.extraInformation; 151 } 152 } 153 }); 154 155 $('#trigger-upload').click(function () { 156 $('#fine-uploader-manual-trigger').fineUploader('uploadStoredFiles'); 157 }); 158 159 $('#Query').click(function () { 160 alert(filePath); 161 }); 162 </script> 163 }
源代码下载