Html 如何使用多部分/表单数据进行 ASP.NET MVC Ajax 表单发布?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/581703/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to do a ASP.NET MVC Ajax form post with multipart/form-data?
提问by dswatik
I am working on a ASP.NET MVC web site which has a form that allows for the upload of files using the multipart/form data enctype option on the form tag like so
我正在开发一个 ASP.NET MVC 网站,该网站有一个表单,允许使用表单标签上的 multipart/form data enctype 选项上传文件,如下所示
<form enctype="multipart/form-data" method="post" action='<%= Url.Action("Post","Entries",new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}) %>'>
How would I write this to do an ASP.NET MVC Ajax form post instead?
我将如何编写它来代替 ASP.NET MVC Ajax 表单发布?
采纳答案by zihotki
- You can use some additional uploaders (e.g. jQuery multiple file uploader) (I prefer this way and I prefer not to use MS Ajax)
Use:
AjaxHelper.BeginForm("Post", "Entries", new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}, new AjaxOptions(){/*some options*/}, new {enctype="multipart/form-data"})
- 你可以使用一些额外的上传器(例如jQuery 多文件上传器)(我更喜欢这种方式,我不喜欢使用 MS Ajax)
用:
AjaxHelper.BeginForm("Post", "Entries", new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}, new AjaxOptions(){/*some options*/}, new {enctype="multipart/form-data"})
But in second case I'm not sure that it will work.
但在第二种情况下,我不确定它会起作用。
回答by Demian Flavius
It is possible but it's a long way. Step 1: write your form
这是可能的,但还有很长的路要走。第 1 步:编写表单
ex:
前任:
@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" />
}
Step 2: intercept the request and send it to the server
第二步:拦截请求并发送给服务器
<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>
Step 3: Because you make an ajax call you probably want to replace some image or something of multipart/form-data
第 3 步:因为您进行了 ajax 调用,所以您可能想要替换一些图像或其他内容 multipart/form-data
ex:
前任:
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);
}
});
}
The MSG variable is an base64 encrypted string. In my case it's the source of the image.
MSG 变量是一个 base64 加密字符串。就我而言,它是图像的来源。
In this way I managed to change a profile picture and after that the picture is immediately updated.
Also make sure you add in Application_Start (global.asax)ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());Pretty nice no?
通过这种方式,我设法更改了个人资料图片,然后立即更新了图片。还要确保您添加了Application_Start (global.asax)ValueProviderFactories.Factories.Add(new JsonValueProviderFactory());很好,不是吗?
P.S.: This Solution works so don't hesitate to ask more details.
PS:此解决方案有效,因此请不要犹豫询问更多详细信息。
回答by James 'Fluffy' Burton
I came across this little hack, which resolves it nicely
我遇到了这个小技巧,它很好地解决了它
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);
回答by Marc Gravell
The jquery forms pluginsupports file uploadsin this way.
在jQuery的形式插件支持文件上传这种方式。
回答by Karthick Jayaraman
Code which I used and it works !! It's a copy of @James 'Fluffy' Burton solution. I just improvising his answer so that people who is new to MVC will be able to quickly understand the consequences.
我使用的代码并且它有效!!这是@James 'Fluffy' Burton 解决方案的副本。我只是即兴创作他的答案,以便不熟悉 MVC 的人能够快速了解后果。
Following are my View:
以下是我的观点:
@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);
Following are my controller:
以下是我的控制器:
[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 });
}
Following is the quick Note of above code: Through Ajax, I have posted my excel (*.csv) file to Server and read it to an DataTable using a Nuget package (LumenWorksCsvReader).
以下是上述代码的快速注释:通过 Ajax,我已将我的 excel (*.csv) 文件发布到服务器,并使用 Nuget 包 (LumenWorksCsvReader) 将其读取到数据表。
Hurray! It works. Thanks @James
欢呼!有用。谢谢@詹姆斯
回答by dswatik
I actually answered the question myself...
其实我自己回答了这个问题...
<% using (Ajax.BeginForm("Post", "Entries", new { id = ViewData.Model.MemberDetermination.DeterminationMemberID }, new AjaxOptions { UpdateTargetId = "dc_goal_placeholder" }, new { enctype = "multipart/form-data" }))
回答by dswatik
For those who still have problems using @Ajax.BeginFormfor multipart enctypes / file uploads in MVC
对于那些@Ajax.BeginForm在 MVC 中使用multipart enctypes / 文件上传仍有问题的人
Diagnosis and proposed solution
诊断和建议的解决方案
Running the “Inspect element” tool on a form element generated by the @Ajax.BeginFormhelper reveals that the helper, rather inexplicably, overrides the controller parameter specified. This is the case if you implemented a separate controller for your partial postback.
在@Ajax.BeginForm帮助程序生成的表单元素上运行“检查元素”工具会发现帮助程序覆盖了指定的控制器参数,但令人费解。如果您为部分回发实现了一个单独的控制器,就会出现这种情况。
A quick-fix for the problem is to explicitly specify your html action attribute value as /<yourcontrollername>/<youractionname>.
该问题的快速解决方法是将您的 html action 属性值显式指定为/<yourcontrollername>/<youractionname>.
Example
例子
@using (Ajax.BeginForm("", "", new AjaxOptions() { HttpMethod = "POST", UpdateTargetId = "<TargetElementId>", InsertionMode = InsertionMode.Replace }, new { enctype = "multipart/form-data", action = "/<Controller>/<Action>" }))
回答by Claudio
I mixed Brad Larson answer with Amirhossein Mehrvarzi, because Brad answer wasn't providing any way to handle the response and Amirhossein was causing 2 postbacks. I just added ($('#formBacklink').valid()) to call model validation before send.
我将 Brad Larson 的回答与 Amirhossein Mehrvarzi 混合在一起,因为 Brad 的回答没有提供任何方式来处理响应,而 Amirhossein 导致了 2 个回发。我刚刚添加 ($('#formBacklink').valid()) 在发送之前调用模型验证。
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);
回答by oli_taz
If you need to use the OnSuccessAjaxOption and/or use Request.IsAjaxRequest()in the controller to check the request type i.e.
如果您需要使用OnSuccessAjaxOption 和/或Request.IsAjaxRequest()在控制器中使用来检查请求类型,即
@using (Ajax.BeginForm("FileUploader", null, new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "elementToUpdate", OnSuccess = "mySuccessFuntion(returnedData)", OnFailure = "myFailureFuntion(returnedData)"}, new { enctype = "multipart/form-data" }))
Then you can use the following code (I've modified @James 'Fluffy' Burton's answer). This will also convert the response text to JSON object if it can (you can omit this if you want).
然后您可以使用以下代码(我修改了@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>
N.B. I use the javascript function eval()to convert the string in to a function... if anyone has a better solution please comment.
I also use JQuery JSON.parse()so this isn't a vanilla javascript solution but it isn't required for the script to function so it could be removed.
注意我使用javascript函数eval()将字符串转换为函数......如果有人有更好的解决方案,请发表评论。我也使用 JQuery,JSON.parse()所以这不是一个普通的 javascript 解决方案,但它不需要脚本运行,所以它可以被删除。
回答by Abdullah Sheikh
You can use this code instead of eval
您可以使用此代码而不是 eval
var body = "function(a){ " + form.dataset.ajaxSuccess + "(a) }";
var wrap = s => "{ return " + body + " };"
var func = new Function(wrap(body));
func.call(null).call(null, returnedData);

