如何使用multipart / form-data做一个ASP.NET MVC Ajax表单发布?

我正在一个ASP.NET MVC的网站,它有一个窗体,允许使用窗体标签上的多部分/表单数据enctype选项上传文件

<form enctype="multipart/form-data" method="post" action='<%= Url.Action("Post","Entries",new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}) %>'> 

我怎么会写这个来做一个ASP.NET MVC Ajax表单发布?

  1. 您可以使用一些额外的上传(例如jQuery多file upload )(我更喜欢这种方式,我不喜欢使用MS Ajax)
  2. 使用:

     AjaxHelper.BeginForm("Post", "Entries", new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}, new AjaxOptions(){/*some options*/}, new {enctype="multipart/form-data"}) 

但在第二种情况下,我不确定它会起作用。

这是可能的,但是还有很长的路要走。 第1步:写下你的表格

例如:

 @using (Ajax.BeginForm(YourMethod, YourController, new { id= Model.Id }, new AjaxOptions {//needed options }, new { enctype = "multipart/form-data" })) { <input type="file" id="image" name="image" /> <input type="submit" value="Modify" /> } 

第二步:拦截请求并发送给服务器

 <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 //handleSuccessFunctionHERE(data); }, error: function(jqXHR, textStatus, errorThrown) { //do your own thing alert("fail"); } }); }); //end .submit() }); </script> 

第3步:因为你打一个Ajax调用你可能想要replace一些图像或多multipart/form-data

例如:

 handleSuccessFunctionHERE(data) { $.ajax({ type: "GET", url: "/Profile/GetImageModified", data: {}, dataType: "text", success: function (MSG) { $("#imageUploaded").attr("src", "data:image/gif;base64,"+msg); }, error: function (msg) { alert(msg); } }); } 

MSGvariables是一个base64encryptionstring。 在我的情况下,这是图像的来源。

通过这种方式,我设法更改了个人资料照片,之后照片立即更新。 还要确保你添加了Application_Start(global.asax) ValueProviderFactories.Factories.Add(new JsonValueProviderFactory()); 很好,不是吗?

PS:这个解决scheme的作品,所以不要犹豫,要求更多的细节。

我遇到了这个小黑客,很好地解决了这个问题

 window.addEventListener("submit", function (e) { var form = e.target; if (form.getAttribute("enctype") === "multipart/form-data") { if (form.dataset.ajax) { e.preventDefault(); e.stopImmediatePropagation(); var xhr = new XMLHttpRequest(); xhr.open(form.method, form.action); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { if (form.dataset.ajaxUpdate) { var updateTarget = document.querySelector(form.dataset.ajaxUpdate); if (updateTarget) { updateTarget.innerHTML = xhr.responseText; } } } }; xhr.send(new FormData(form)); } } }, true); 

jQuery表单插件支持file upload这种方式。

我其实自己回答了这个问题

 <% using (Ajax.BeginForm("Post", "Entries", new { id = ViewData.Model.MemberDetermination.DeterminationMemberID }, new AjaxOptions { UpdateTargetId = "dc_goal_placeholder" }, new { enctype = "multipart/form-data" })) 

对于在MVC中使用@Ajax.BeginForm进行多部分enctypes /file upload的问题仍然存在问题

诊断和提出解决scheme

在由@Ajax.BeginForm帮助器生成的表单元素上运行“Inspect元素”工具可以发现,帮助器相当莫名其妙地覆盖了指定的控制器参数。 如果您为部分回发实施单独的控制器,则是这种情况。

解决这个问题的一个快速解决scheme是明确指定您的html action属性值为/<yourcontrollername>/<youractionname>

 @using (Ajax.BeginForm("", "", new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "<TargetElementId>", InsertionMode = InsertionMode.Replace }, new { enctype = "multipart/form-data", action = "/<Controller>/<Action>" })) 

代码,我用它和它的作品! 这是@James'Fluffy'Burton解决scheme的副本。 我只是即兴答案,以便MVC的新人能够很快理解其后果。

以下是我的观点:

 @using (Ajax.BeginForm("FileUploader", null, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "AjaxUpdatePanel" }, new { enctype = "multipart/form-data", id = "frmUploader" })){ <div id="AjaxUpdatePanel"> <div class="form-group"> <input type="file" id="dataFile" name="upload" /> </div> <div class="form-group"> <input type="submit" value="Upload" class="btn btn-default" id="btnUpload"/> </div> </div>} <script> window.addEventListener("submit", function (e) { var form = e.target; if (form.getAttribute("enctype") === "multipart/form-data") { if (form.dataset.ajax) { e.preventDefault(); e.stopImmediatePropagation(); var xhr = new XMLHttpRequest(); xhr.open(form.method, form.action); xhr.onreadystatechange = function () { if (xhr.readyState == 4 && xhr.status == 200) { if (form.dataset.ajaxUpdate) { var updateTarget = document.querySelector(form.dataset.ajaxUpdate); if (updateTarget) { updateTarget.innerHTML = xhr.responseText; } } } }; xhr.send(new FormData(form)); } } }, true); 

以下是我的控制器:

 [HttpPost] public JsonResult FileUploader(HttpPostedFileBase upload) { if (ModelState.IsValid) { if (upload != null && upload.ContentLength > 0) { if (upload.FileName.EndsWith(".csv")) { Stream stream = upload.InputStream; DataTable csvTable = new DataTable(); using (CsvReader csvReader = new CsvReader(new StreamReader(stream), true)) { csvTable.Load(csvReader); } } else { return Json(new { dataerror = true, errormsg = "This file format is not supported" }); } } else { return Json(new { dataerror = true, errormsg = "Please Upload Your file" }); } } return Json(new { result = true }); } 

以下是上述代码的快速注意事项:通过Ajax,我将我的excel(* .csv)文件发布到服务器,并使用Nuget包(LumenWorksCsvReader)将其读取到一个DataTable。

欢呼! 有用。 谢谢@詹姆斯

Ajax.BegineForm()适用于多部分表单数据,下面是相同的工作代码示例:

视图:

 @using(Ajax.BeginForm("UploadFile","MyPOC", new AjaxOptions { HttpMethod = "POST" }, new { enctype = "multipart/form-data" })) { <input type="file" name="files" id="fileUploaderControl" /> <input type="submit" value="Upload" id="btnFileUpload" /> } 

控制器操作方法:

 public void UploadFile(IEnumerable<HttpPostedFileBase> files) { HttpPostedFileBase file = files.FirstOrDefault(); //Attach a debugger here and check whether you are getting your file on server side or null. if (file != null && file.ContentLength > 0) { //Do other validations before saving the file //Save File file.SaveAs(path); } } 

PS确保文件uploader控件的“name”属性和传递给Action方法UploadFile()的参数名称必须相同(在这种情况下为“files”)。

我把Brad Larson的答案与Amirhossein Mehrvarzi混合在一起,因为Brad答复没有提供任何方式来处理这个反应,而Amirhossein正在造成2次回传。 我只是添加($('#formBacklink')。有效())在发送之前调用模型validation。

 window.addEventListener("submit", function (e) { if ($('#formBacklink').valid()) { var form = e.target; if (form.getAttribute("enctype") === "multipart/form-data") { if (form.dataset.ajax) { e.preventDefault(); e.stopImmediatePropagation(); var dataString; event.preventDefault(); var action = $("#formBacklink").attr("action"); if ($("#formBacklink").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($("#formBacklink").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 //handleSuccessFunctionHERE(data); }, error: function (jqXHR, textStatus, errorThrown) { //do your own thing } }); } } } }, true); 

如果您需要使用OnSuccess AjaxOption和/或在控制器中使用Request.IsAjaxRequest()来检查请求types即

 @using (Ajax.BeginForm("FileUploader", null, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "elementToUpdate", OnSuccess = "mySuccessFuntion(returnedData)", OnFailure = "myFailureFuntion(returnedData)"}, new { enctype = "multipart/form-data" })) 

然后你可以使用下面的代码(我修改了@James'Fluffy'Burton的答案)。 如果可以的话,这也会将响应文本转换为JSON对象(如果需要,可以省略)。

 <script> if(typeof window.FormData === 'undefined') { alert("This browser doesn't support HTML5 file uploads!"); } window.addEventListener("submit", function (e) { var form = e.target; if (form.getAttribute("enctype") === "multipart/form-data") { if (form.dataset.ajax) { e.preventDefault(); e.stopImmediatePropagation(); var xhr = new XMLHttpRequest(); xhr.open(form.method, form.action); xhr.setRequestHeader("x-Requested-With", "XMLHttpRequest"); // this allows 'Request.IsAjaxRequest()' to work in the controller code xhr.onreadystatechange = function () { if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { var returnedData; //this variable needs to be named the same as the parameter in the function call specified for the AjaxOptions.OnSuccess try { returnedData = JSON.parse(xhr.responseText); //I also want my returned data to be parsed if it is a JSON object }catch(e){ returnedData = xhr.responseText; } if (form.dataset.ajaxSuccess) { eval(form.dataset.ajaxSuccess); //converts function text to real function and executes (not very safe though) } else if (form.dataset.ajaxFailure) { eval(form.dataset.ajaxFailure); } if (form.dataset.ajaxUpdate) { var updateTarget = document.querySelector(form.dataset.ajaxUpdate); if (updateTarget) { updateTarget.innerHTML = data; } } } }; xhr.send(new FormData(form)); } } }, true); </script> 

NB我使用javascript函数eval()将string转换为函数…如果有人有更好的解决scheme,请评论。 我也使用JQuery JSON.parse()所以这不是一个香草的JavaScript解决scheme,但脚本不需要function,因此可以删除。

从我的小调查。 上面的所有答案似乎是正确的,这取决于Ajax.BeginForm的问题。 但是,我刚刚注意到,问题是在〜/ Scripts / jquery.unobtrusive-ajax.min.js JavaScript库在某些情况下。 所以在我的情况下,我只是从视图模型中删除它,并决定使用JQuery表单插件为我的需要与HTML表单,而不是。 上面已经提到了这一点。