在MVC中的Ajax.BeginForm来上传文件

我试图使用这里提到的一个例子如何做一个ASP.NET MVC Ajax表单发布多部分/表单数据?

但我不断收到“失败”错误消息框

Index.cshtml

<script src="~/Scripts/jquery-1.8.2.min.js"></script> <script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script> <h2>Files Upload</h2> <script type="text/javascript"> $(function() { $("#form0").submit(function(event) { var dataString; event.preventDefault(); var action = $("#form0").attr("action"); if ($("#form0").attr("enctype") == "multipart/form-data") { //this only works in some browsers. //purpose? to submit files over ajax. because screw iframes. //also, we need to call .get(0) on the jQuery element to turn it into a regular DOM element so that FormData can use it. dataString = new FormData($("#form0").get(0)); contentType = false; processData = false; } else { // regular form, do your own thing if you need it } $.ajax({ type: "POST", url: action, data: dataString, dataType: "json", //change to your own, else read my note above on enabling the JsonValueProviderFactory in MVC contentType: contentType, processData: processData, success: function(data) { //BTW, data is one of the worst names you can make for a variable }, error: function(jqXHR, textStatus, errorThrown) { //do your own thing alert("fail"); } }); }); //end .submit() }); </script> <div id="uploadDiv"> @Html.Action("Files", "Home") </div> @using (Ajax.BeginForm("Files", "Home", new AjaxOptions { UpdateTargetId = "uploadDiv", HttpMethod = "Post" }, new { enctype = "multipart/form-data", @id="form0"})) { <div> <div>Upload new file: <input type="file" name="file" /></div> <input type="submit" value="Save" /> </div> } <br /> 

调节器

 public PartialViewResult Files(HttpPostedFileBase file) { IEnumerable<string> files; if ((file != null) && (file.ContentLength > 0)) { string fileName = file.FileName; string saveLocation = @"D:\Files"; string fullFilePath = Path.Combine(saveLocation, fileName); try { file.SaveAs(fullFilePath); FileInfo fileInfo = new FileInfo(fullFilePath); file.InputStream.Read(new byte[fileInfo.Length], 0, file.ContentLength); } catch (Exception e) { TempData["FileUpload"] = e.Message; return PartialView(); } files = Directory.GetFiles(@"D:\Files\"); return PartialView(files); } else { files = Directory.GetFiles(@"D:\Files\"); return PartialView(files); } } 

Files.cshtml

 @model IEnumerable<string> @foreach (string f in Model) { <p>@f</p> } 

Global.asax中

 ValueProviderFactories.Factories.Add(new JsonValueProviderFactory()); 

这是复杂的更好地使用jQuery的forms插件 。

这是样本:

Html.BeginForm

  @using (Html.BeginForm("YourAction", "YourController")) { @Html.AntiForgeryToken() <input type="file" name="files"><br> <input type="submit" value="Upload File to Server"> } 

行动方法

  [HttpPost] [ValidateAntiForgeryToken] public void YourAction(IEnumerable<HttpPostedFileBase> files) { if (files != null) { foreach (var file in files) { // Verify that the user selected a file if (file != null && file.ContentLength > 0) { // extract only the fielname var fileName = Path.GetFileName(file.FileName); // TODO: need to define destination var path = Path.Combine(Server.MapPath("~/Upload"), fileName); file.SaveAs(path); } } } } 

进度条

 <div class="progress progress-striped"> <div class="progress-bar progress-bar-success">0%</div> </div> 

jquery&表单脚本

 <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script> <script src="http://malsup.github.com/jquery.form.js"></script> <script> (function() { var bar = $('.progress-bar'); var percent = $('.progress-bar'); var status = $('#status'); $('form').ajaxForm({ beforeSend: function() { status.empty(); var percentVal = '0%'; bar.width(percentVal) percent.html(percentVal); }, uploadProgress: function(event, position, total, percentComplete) { var percentVal = percentComplete + '%'; bar.width(percentVal) percent.html(percentVal); }, success: function() { var percentVal = '100%'; bar.width(percentVal) percent.html(percentVal); }, complete: function(xhr) { status.html(xhr.responseText); } }); })(); </script> 

更新中…

调用Action方法两次的人是由于Ajax.BeginForm,只是将其转换为Html.BeginForm()。 有关更多说明和下载示例代码,请参阅此博客

来自Ashwini Verma的回答几乎是正确的,但它有一个缺点,表单提交两次。

这是由于使用Ajax.BeginForm()造成的。 使用Html.BeginForm()将修复它。

这是一个例子:

 @* do not use Ajax.BeginForm() as it would cause the form to submit twice in connection with jQuery.Form *@ @using (var lForm = Html.BeginForm( <ActionName>, <ControllerName>, FormMethod.Post, new Dictionary<string, object> {{"name", <YourFormName>}, {"enctype", "multipart/form-data"}})) { 

您需要使用html5文件处理并读取客户端上的文件内容以获取base64编码数据。

在客户端你必须把:

 <div> @Html.HiddenFor(m => m.AttachmentFileName) @Html.HiddenFor(m => m.AttachmentFileSize) @Html.HiddenFor(m => m.AttachmentFileType) @Html.HiddenFor(m => m.AttachmentFileContentsBase64) <input type="file" name="AttachmentFile" id="AttachmentFile" onchange="handleAttachmentFileChange(this.files)" /> @Html.ValidationMessageFor(m => m.AttachmentFile) </div> <script> function handleAttachmentFileChange(files) { var file = files[0]; $("#AttachmentFileName").val(file.name); $("#AttachmentFileSize").val(file.size); $("#AttachmentFileType").val(file.type || "application/octet-stream"); var fileReader = new FileReader(); fileReader.onload = function () { fileReader.result; $("#AttachmentFileContentsBase64").val(fileReader.result); }; fileReader.readAsDataURL(file); }; </script> 

所以你的代码将填充隐藏的文件数据(文件名,types,大小,base64编码的内容)字段。 而在服务器端,你把:

  if (AttachmentFileSize > 0) { string fileName = AttachmentFileName.Contains("\\") ? AttachmentFileName.Substring(AttachmentFileName.LastIndexOf("\\") + 1) : AttachmentFileName; byte[] fileBytes = Convert.FromBase64String(AttachmentFileContentsBase64.Substring(AttachmentFileContentsBase64.IndexOf(',') + 1)); //save file to file system or db ModelState.Remove("CurrentAttachmentFileId"); ModelState.Remove("CurrentAttachmentFileName"); } else if (AttachmentFileSize == -1) { //remove existing file from fs or db } 

该代码需要修改您的模型和逻辑,但它为我工作