如何使用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表单发布?
- 您可以使用一些额外的上传(例如jQuery多file upload )(我更喜欢这种方式,我不喜欢使用MS Ajax)
-
使用:
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表单,而不是。 上面已经提到了这一点。