ajax 发布对象列表包含文件到 asp.net 控制器不起作用

Posted

技术标签:

【中文标题】ajax 发布对象列表包含文件到 asp.net 控制器不起作用【英文标题】:ajax post list of objects contains file to asp.net controller not working 【发布时间】:2021-09-17 05:36:39 【问题描述】:

我正在研究 asp.net 核心,我想将包含来自 ajax 请求的文件的列表对象发送到控制器

这里有更多细节:在这张图片中,我要发送的对象包括文件

视图模型

 public class FormDataVM
    
        public Guid FormTemplateId  get; set; 
        public int FieldTemplateId  get; set; 
        public string Value  get; set; 
    

控制器

[HttpPost]
        public async Task<JsonResult> SubmitForm(List<FormDataVM> formData , IFormFile file)
        
            if (ModelState.IsValid)
            
                var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "images");

                if (file != null && file.Length > 0)
                
                    var fileName = Guid.NewGuid().ToString().Replace("-", "") +
                                    Path.GetExtension(file.FileName);
                    using (var s = new FileStream(Path.Combine(uploads, fileName),
                                                                FileMode.Create))
                    
                        await file.CopyToAsync(s);

                    
// to be continued
                
                return Json(new  status = "success", message = "success" );
            
            return Json(new  status = "failed", message = "failed" );
        

ajax 请求:data 是在控制台打印的对象

<form>
    <div id="Cards">
        @foreach (var item in Model.FieldTemplates)
        
            <div class="form-box">
                <div class="card">
                    <div class="card-body">
                        <h5 class="card-title">@item.Name</h5>
                        <div class="form-group">
                            @if (item.FieldTemplateEnum == FormBuilder.Enums.FieldTemplateEnum.Answer)
                            
                                @html.HiddenFor(x => item.Id)
                                @Html.HiddenFor(x => item.FieldTemplateEnum)
                                <h5 class="card-title">
                                    <input placeholder="Untitled Question"  type="text" class="form-control AnswerInput">
                                </h5>

                            
                            @if (item.FieldTemplateEnum == FormBuilder.Enums.FieldTemplateEnum.CheckBox)
                            
                                @Html.HiddenFor(x => item.Id)
                                @Html.HiddenFor(x => item.FieldTemplateEnum)
                                <div class="CheckBoxItemView">
                                    @foreach (var value in item.FieldElementTemplates)
                                    
                                        <div class="form-check">
                                            <input class="form-check-input" name="CheckBoxInput" type="checkbox" value="@value.Value">
                                            <label class="form-check-label" for="flexCheckDefault">
                                                @value.Value
                                            </label>
                                        </div>
                                    
                                </div>
                            
                            @if (item.FieldTemplateEnum == FormBuilder.Enums.FieldTemplateEnum.RadioButton)
                            
                                @Html.HiddenFor(x => item.Id)
                                @Html.HiddenFor(x => item.FieldTemplateEnum)
                                <div class="RadioButtonItemView">
                                    @foreach (var value in item.FieldElementTemplates)
                                    
                                        <div class="form-check">
                                            <input class="form-check-input" type="radio" value="@value.Value" name="RadioInput" id="exampleRadios3">
                                            <label class="form-check-label" for="exampleRadios3">
                                                @value.Value
                                            </label>
                                        </div>
                                    
                                </div>
                            
                            @if (item.FieldTemplateEnum == FormBuilder.Enums.FieldTemplateEnum.FileUpload)
                            
                                @Html.HiddenFor(x => item.Id)
                                @Html.HiddenFor(x => item.FieldTemplateEnum)
                                <div class="form-group">
                                    <label for="exampleFormControlFile1">upload file</label>
                                    <input type="file" class="form-control-file FileInput">
                                </div>
                            
                            @if (item.FieldTemplateEnum == FormBuilder.Enums.FieldTemplateEnum.DateAndTime)
                            
                                @Html.HiddenFor(x => item.Id)
                                @Html.HiddenFor(x => item.FieldTemplateEnum)
                                <div class="col-md-4">
                                    <input type="text" class="form-control DateTimeInput">
                                </div>
                            
                        </div>
                    </div>
                </div>
            </div>
        
        <div class="row">
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" id="Submit" value="Submit" class="btn btn-primary" />
                </div>
            </div>
        </div>
    </div>
</form>
@section Scripts
    <script type="text/javascript">
    $(document).ready(function () 
        $(function () 
            $('.DateTimeInput').datetimepicker();
        );
        $('#Submit').click(function () 
            PrepareForm();
        );
        function PrepareForm() 
            var DataObject = new Object();
            var listCards = [];
            $('#Cards>div').each(function () 
                var singleObj = ;
                singleObj['FormTemplateId'] = $('#Id').val();
                singleObj['FieldTemplateId'] = $(this).find('#item_Id').val();
                var templateType = $(this).find('#item_FieldTemplateEnum').val();
                if (templateType == "Answer") 
                    singleObj['Value'] = $(this).find('.AnswerInput').val();
                
                else if (templateType == "CheckBox") 
                    var selectedChecks = '';
                    $('input:checkbox[name=CheckBoxInput]:checked').each(function () 
                        selectedChecks += $(this).val() + " , ";
                        singleObj['Value'] = selectedChecks.replace(/,(\s+)?$/, '');
                    );
                
                else if (templateType == "RadioButton") 
                    singleObj['Value'] = $(this).find($("input[name=RadioInput]:checked")).val();
                
                else if (templateType == "FileUpload") 
                    singleObj['Value'] = $(this).find('.FileInput')[0].files[0];
                    //console.log($(this).find('.FileInput')[0].files[0].name);
                
                else if (templateType == "DateAndTime") 
                    singleObj['Value'] = $(this).find('.DateTimeInput').val();
                
                listCards.push(singleObj);
            );
            DataObject = listCards;
            console.log(DataObject);
            var data = new FormData();
            debugger;
            for (var i = 0; i < DataObject.length; i++) 
                debugger;
                data.append([i]+"FormTemplateId", DataObject[i].FormTemplateId);
                data.append([i]+"FieldTemplateId", DataObject[i].FieldTemplateId);
                data.append([i]+"Value", DataObject[i].Value);
            
            SubmitForm(data);
        
        function SubmitForm(formData) 
            $.ajax(
                type: "POST",
                url: "@Url.Action("SubmitForm", "Form")",
                data: formData,
                contentType: false,
                processData: false,
                success: function (message) 
                    alert(message);
                ,
                error: function () 
                    alert("there was error uploading files!");
                
            );
        
    );
    </script>


当我发送请求时,实际操作中的列表始终计数为 0 并且文件为 null ,那么如何解决此问题。

【问题讨论】:

您的控制台屏幕截图显示data 是一个数组。此外,您必须使用 FormData 对象来上传文件。 【参考方案1】:

更新:

1.你没有任何id为Id的元素,所以singleObj中的FormTemplateId是未定义的:

singleObj['FormTemplateId'] = $('#Id').val();

2.你需要把type="submit"改成type="button":

<input type="button" id="Submit" value="Submit" class="btn btn-primary" />

3.需要添加名为file的FormData,因为后端接收文件参数为IFormFile file:

data.append("file", $(this).find('.FileInput')[0].files[0]);

4.将包含按钮的div移到&lt;div id="Cards"&gt;之外,否则这里的代码($('#Cards&gt;div').each)会附加无用的值。

5.formdata包含值和键名,你的键名不正确,应该是[index].PropertyName(例如[0].FormTemplateId),你在下面所做的只是'indexPropertyName'(例如0FormTemplateId):

data.append([i]+"FormTemplateId", DataObject[i].FormTemplateId);
data.append([i]+"FieldTemplateId", DataObject[i].FieldTemplateId);
data.append([i]+"Value", DataObject[i].Value);

您需要更改为:

data.append("["+i+"].FormTemplateId", DataObject[i].FormTemplateId);
data.append("[" + i +"].FieldTemplateId", DataObject[i].FieldTemplateId);
data.append("[" + i +"].Value", DataObject[i].Value);

这是一个完整的工作演示:

型号:

public class FormDataVM

    public Guid FormTemplateId  get; set; 
    public int FieldTemplateId  get; set; 
    public string Value  get; set; 

public class FormTemplate

    public List<FieldTemplate> FieldTemplates  get; set; 

public class FieldTemplate

    public string FieldTemplateEnum  get; set; 
    public string Name  get; set; 
    public int Id  get; set; 
    public List<FieldElementTemplate> FieldElementTemplates  get; set; 

public class FieldElementTemplate

    public string Value  get; set; 

查看(不确定您的 html 中的 FormBuilder.Enums.FieldTemplateEnum.XXX 是什么。为了方便测试,我只是将其硬编码为一个简单的字符串):

@model FormTemplate
<form>
    <div id="Cards">
        @foreach (var item in Model.FieldTemplates)
        
            <div class="form-box">
                <div class="card">
                    <div class="card-body">
                        <h5 class="card-title">@item.Name</h5>
                        <div class="form-group">
                            @if (item.FieldTemplateEnum == "Answer")
                            
                                @Html.HiddenFor(x => item.Id)
                                @Html.HiddenFor(x => item.FieldTemplateEnum)
                                <h5 class="card-title">
                                    <input placeholder="Untitled Question" type="text" class="form-control AnswerInput">
                                </h5>
                            
                            @if (item.FieldTemplateEnum == "CheckBox")
                            
                                @Html.HiddenFor(x => item.Id)
                                @Html.HiddenFor(x => item.FieldTemplateEnum)
                                <div class="CheckBoxItemView">
                                    @foreach (var value in item.FieldElementTemplates)
                                    
                                        <div class="form-check">
                                            <input class="form-check-input" name="CheckBoxInput" type="checkbox" value="@value.Value">
                                            <label class="form-check-label" for="flexCheckDefault">
                                                @value.Value
                                            </label>
                                        </div>
                                    
                                </div>
                            
                            @if (item.FieldTemplateEnum == "RadioButton")
                            
                                @Html.HiddenFor(x => item.Id)
                                @Html.HiddenFor(x => item.FieldTemplateEnum)
                                <div class="RadioButtonItemView">
                                    @foreach (var value in item.FieldElementTemplates)
                                    
                                        <div class="form-check">
                                            <input class="form-check-input" type="radio" value="@value.Value" name="RadioInput" id="exampleRadios3">
                                            <label class="form-check-label" for="exampleRadios3">
                                                @value.Value
                                            </label>
                                        </div>
                                    
                                </div>
                            
                            @if (item.FieldTemplateEnum == "FileUpload")
                            
                                @Html.HiddenFor(x => item.Id)
                                @Html.HiddenFor(x => item.FieldTemplateEnum)
                                <div class="form-group">
                                    <label for="exampleFormControlFile1">upload file</label>
                                    <input type="file" class="form-control-file FileInput">
                                </div>
                            
                            @if (item.FieldTemplateEnum == "DateAndTime")
                            
                                @Html.HiddenFor(x => item.Id)
                                @Html.HiddenFor(x => item.FieldTemplateEnum)
                                <div class="col-md-4">
                                    <input type="text" class="form-control DateTimeInput">
                                </div>
                            
                        </div>
                    </div>
                </div>
            </div>
        
    </div>

     //move to here....
    <div class="row">
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                         //change here....
                <input type="button" id="Submit" value="Submit" class="btn btn-primary" />
            </div>
        </div>
    </div>
</form>

JS:

$(document).ready(function () 
    $(function () 
        $('.DateTimeInput').datetimepicker();
    );
    $('#Submit').click(function () 
        PrepareForm();
    );
    function PrepareForm() 
        var DataObject = new Object();
        var listCards = [];
        var data = new FormData();   //move to here...
        $('#Cards>div').each(function () 
            var singleObj = ;
            //singleObj['FormTemplateId'] = $('#Id').val();
            // you do not have element which id is Id in your html code...       
             //for easy testing...I hard coded a GUID...
            singleObj['FormTemplateId'] = "2f1b0003-f8c9-47a5-ad2c-3ed2ace711d9";
            singleObj['FieldTemplateId'] = $(this).find('#item_Id').val();;
            var templateType = $(this).find('#item_FieldTemplateEnum').val();
            if (templateType == "Answer") 
                singleObj['Value'] = $(this).find('.AnswerInput').val();
            
            else if (templateType == "CheckBox") 
                var selectedChecks = '';
                $('input:checkbox[name=CheckBoxInput]:checked').each(function () 
                    selectedChecks += $(this).val() + " , ";
                    singleObj['Value'] = selectedChecks.replace(/,(\s+)?$/, '');
                );
            
            else if (templateType == "RadioButton") 
                singleObj['Value'] = $(this).find($("input[name=RadioInput]:checked")).val();
            
            else if (templateType == "FileUpload") 
                  //add here..............
                data.append("file", $(this).find('.FileInput')[0].files[0]);
                singleObj['Value'] = $(this).find('.FileInput')[0].files[0];
            
            else if (templateType == "DateAndTime") 
                singleObj['Value'] = $(this).find('.DateTimeInput').val();
            
            listCards.push(singleObj);
        );
        DataObject = listCards;
        console.log(DataObject);

        debugger;
        for (var i = 0; i < DataObject.length; i++) 
            debugger;
                          //change here.......
            data.append("["+i+"].FormTemplateId", DataObject[i].FormTemplateId);
            data.append("[" + i +"].FieldTemplateId", DataObject[i].FieldTemplateId);
            data.append("[" + i +"].Value", DataObject[i].Value);
        
        SubmitForm(data);
    
    function SubmitForm(formData) 
        $.ajax(
            type: "POST",
            url: "@Url.Action("SubmitForm", "Home")",
            data: formData,
            contentType: false,
            processData: false,
            success: function (message) 
                alert(message);
            ,
            error: function () 
                alert("there was error uploading files!");
            
        );
    
);

注意:我已在代码中为所有更改添加注释。请仔细阅读,不要遗漏任何内容。

结果:

【讨论】:

我试过你的例子,它是工作文件,但我的代码同样的问题,所以我会发布我的代码,你能帮我吗 嗨@Rena 有FormTemplate 模型,其中包含FieldTemplates 列表和foreach FieldTemplates 使用它的id `@Html.HiddenFor(x => 项进行隐藏输入。 Id)` 在运行时显示为&lt;input data-val="true" data-val-required="The Id field is required." id="item_Id" name="item.Id" type="hidden" value="1"&gt; 嗨@KarimFahmy,您没有id="Id" 的任何元素。更多详细信息,您可以查看我更新的答案。如果对你有帮助,记得采纳为答案。 嗨@Rena,我在div.cards 上面有元素表单id,非常感谢

以上是关于ajax 发布对象列表包含文件到 asp.net 控制器不起作用的主要内容,如果未能解决你的问题,请参考以下文章

对“asp.net core WebApi”的 ajax 调用返回一个奇怪/奇怪的值

带有大型数据源的 Kendo Chart 的 Ajax 请求上的 ASP.NET MVC 应用程序?

asp.net webforms ajax 更新gridview

在 ASP.Net Core 中使用 AJAX 将复选框列表类的值发送到服务器

如何将带有附加数据的 FormData 文件发送到 asp.net web api ajax 调用

如何在 Asp.Net MVC5 中使用 Ajax 将数据库更改保存到拖放列表