如何在 MVC 5 中以单个 Ajax POST 请求发送 ViewModel 和文件?

Posted

技术标签:

【中文标题】如何在 MVC 5 中以单个 Ajax POST 请求发送 ViewModel 和文件?【英文标题】:How to send ViewModel and a file in single Ajax POST request, in MVC 5? 【发布时间】:2015-12-24 11:36:35 【问题描述】:

我有一个 ASP.NET MVC 5 应用程序。我正在尝试使用模型数据发送 POST 请求,并且还包括用户选择的文件。 这是我的 ViewModel(为清楚起见进行了简化):

public class Model

    public string Text  get; set; 
    public long Id  get; set; 

这是控制器动作:

[HttpPost]
public ActionResult UploadFile(long userId, Model model)

    foreach (string file in Request.Files)
    
        // process files
    

    return View("Index");

html 输入元素:

<div>
    <input type="file" name="UploadFile" id="txtUploadFile" />
</div>

还有 javascript 代码:

$('#txtUploadFile').on('change', function (e) 
    var data = new FormData();
    for (var x = 0; x < files.length; x++) 
        data.append("file" + x, files[x]);
    
    data.append("userId", 1);
    data.append("model", JSON.stringify( Text: 'test text', Id: 3 ));

    $.ajax(
        type: "POST",
        url: '/Home/UploadFile',
        contentType: false,
        processData: false,
        data: data,
        success: function (result)  ,
        error: function (xhr, status, p3, p4)  
    );
);

问题是,当请求到达控制器操作时,我填充了文件和“userId”,但“模型”参数始终为空。填充 FormData 对象时我做错了吗?

【问题讨论】:

使用 contentType: "application/json" 它不会发送文件。 参考this answer - 而不是data.append("model", JSON.stringify( Text: 'test text', Id: 3 )); 它应该是data.append(Text, 'test text'); data.append(Id, 3); 谢谢,现在我知道 FormData 有什么问题了! 【参考方案1】:

这是我使用 MVC5 和 IE11 / chrome 测试的内容

查看

<script>
    $(function () 
        $("#form1").submit(function () 
            /*You can also inject values to suitable named hidden fields*/
            /*You can also inject the whole hidden filed to form dynamically*/
            $('#name2').val(Date); 
            var formData = new FormData($(this)[0]);
            $.ajax(
                url: $(this).attr('action'),
                type: $(this).attr('method'),
                data: formData,
                async: false,
                success: function (data) 
                    alert(data)
                ,
                error: function()
                    alert('error');
                ,
                cache: false,
                contentType: false,
                processData: false
            );
            return false;
        );
    );
</script>

<form id="form1" action="/Home/Index" method="post" enctype="multipart/form-data">
    <input type="text" id="name1" name="name1" value="value1" />
    <input type="hidden" id ="name2" name="name2" value="" />
    <input name="file1" type="file" />
    <input type="submit" value="Sublit" />
</form>

控制器

public class HomeController : Controller

    [HttpGet]
    public ActionResult Index()
    
        return View();
    

    [HttpPost]
    public ActionResult Index(HttpPostedFileBase file1, string name1, string name2)
    
        var result = new List<string>();
        if (file1 != null)
            result.Add(string.Format("0: 1 bytes", file1.FileName, file1.ContentLength));
        else
            result.Add("No file");
        result.Add(string.Format("name1: 0", name1));
        result.Add(string.Format("name2: 0", name2));
        return Content(string.Join(" - ", result.ToArray()));
    

感谢 Silver89 的answer

【讨论】:

问题是我的表单上没有所有必填字段,所以Model是用JS代码构造的,就在发送POST请求之前。 @IgorGoroshko 我认为有很多方法可以解决这个问题,您可以测试的一种方法是将您的值注入到合适的命名隐藏字段中。 @IgorGoroshko 更新为在隐藏字段中注入值。 谢谢,这可行,但我的代码中的问题是我们有一个 JS 函数,它接受 Model 作为参数。该函数负责在 input:file 元素组中查找文件并将它们与模型一起发送,因此我们无法访问表单元素。 @IgorGoroshko 正如我所说,有很多方法可以做到这一点,例如,data = new FormData(); data.append( 'file', $( '#file' )[0].files[0] );

以上是关于如何在 MVC 5 中以单个 Ajax POST 请求发送 ViewModel 和文件?的主要内容,如果未能解决你的问题,请参考以下文章

ajax提交数据,spring Mvc按照单个参数接收

在 Spring MVC 中以 AJAX 响应发送文件

如何在 ASP.NET MVC 中以 JSON 格式返回 500 错误?

MVC中前台如何向后台传递数据------$.get(),$post(),$ajax(),$.getJSON()总结

如何将两个数组作为 POST 请求参数从 AJAX 发送到 MVC 控制器(ASP .NET Core 3.1 剃须刀)?

确保控制器方法实际上是由 ajax 或 mvc 中的 POST 请求调用的