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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 23:19:13  来源:igfitidea点击:

How to do a ASP.NET MVC Ajax form post with multipart/form-data?

asp.nethtmlasp.net-mvc

提问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

  1. You can use some additional uploaders (e.g. jQuery multiple file uploader) (I prefer this way and I prefer not to use MS Ajax)
  2. Use:

    AjaxHelper.BeginForm("Post", "Entries", new {id=ViewData.Model.MemberDetermination.DeterminationMemberID}, new AjaxOptions(){/*some options*/}, new {enctype="multipart/form-data"})
    
  1. 你可以使用一些额外的上传器(例如jQuery 多文件上传器)(我更喜欢这种方式,我不喜欢使用 MS Ajax)
  2. 用:

    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);