You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS前端+ASP.NET Core 5 API同时传文件存数据问题

同时上传文件与复杂JSON数据的解决方案(NextJS + ASP.NET Core 5)

问题背景

使用NextJS作为前端、ASP.NET Core 5作为后端Web API,需同时上传文件(对应softwareBillingDocumentFile的PdfFile字段)并提交复杂JSON结构数据,但后端接收时PdfFile为空,无法完成上传。


后端调整

1. 定义统一接收模型

创建包含所有业务数据和文件列表的主模型,替代拆分的参数接收方式:

// 主接收模型,整合所有业务数据与文件列表
public class SoftwareBillingSubmission
{
    // 原JSON结构的所有字段
    public string SNo { get; set; }
    public string ApplicationName { get; set; }
    public string Status { get; set; }
    public string ApplicationDescription { get; set; }
    public string EntryBy { get; set; }
    public string EntryDate { get; set; }
    public string Action { get; set; }
    public List<SoftwareBillingDetail> SoftwareBillingDetails { get; set; }
    public List<SoftwareBillingDocument> SoftwareBillingDocument { get; set; }
    public List<SoftwareVendor> SoftwareVendors { get; set; }
    public List<SoftwareBillingEquipmentInfo> SoftwareBillingEquipmentInfo { get; set; }
    public string RequestedDate { get; set; }
    public string ApprovedDate { get; set; }
    public string ApplicantName { get; set; }
    public string Designation { get; set; }
    public string ApplicantEmail { get; set; }
    public string ApplicantPhone { get; set; }
    public string ApplicantMobile { get; set; }
    public string Website { get; set; }
    public string Remarks { get; set; }
    public string ApplicationDisName { get; set; }
    
    // 文件列表字段
    public List<SoftwareBillingDocumentFile> SoftwareBillingDocumentFile { get; set; }
}

// 补充子模型(匹配原JSON结构)
public class SoftwareBillingDetail
{
    public string SNo { get; set; }
    public string Version { get; set; }
    public string CertificationNo { get; set; }
    public string FrontEnd { get; set; }
    public string BackEnd { get; set; }
    public string CertificatedDate { get; set; }
    public string Action { get; set; }
}

public class SoftwareBillingDocument
{
    public string SNo { get; set; }
    public string DocumentType { get; set; }
    public string IncludedYN { get; set; }
    public string Action { get; set; }
}

public class SoftwareVendor
{
    public string SNo { get; set; }
    public string Pan { get; set; }
    public string VendorName { get; set; }
    public string VendorType { get; set; }
    public string ContactNo { get; set; }
    public string DeveloperForDistibuters { get; set; }
    public string DeveloperCountry { get; set; }
    public string Action { get; set; }
}

public class SoftwareBillingEquipmentInfo
{
    public string SNo { get; set; }
    public string Version { get; set; }
    public string EquipSno { get; set; }
    public string EquipmentName { get; set; }
    public string BrandName { get; set; }
    public string ModelNo { get; set; }
    public string CountryName { get; set; }
    public string ManufacturingDate { get; set; }
    public string BuiltInSoftware { get; set; }
    public string FrontEnd { get; set; }
    public string BackEnd { get; set; }
}

// 保留原文件模型不变
public class SoftwareBillingDocumentFile
{
    public string SubmissionNo { get; set; }
    public object Document { get; set; }
    public int SeqNo { get; set; }
    public string DocumentType { get; set; }
    public string FileName { get; set; }
    public IFormFile? PdfFile { get; set; }
}

2. 修改API接口方法

使用[FromForm]标记主模型,统一接收所有数据:

[HttpPost]
public IActionResult SubmitSoftwareBilling([FromForm] SoftwareBillingSubmission submission)
{
    if (submission.SoftwareBillingDocumentFile?.Count > 0)
    {
        var fileItem = submission.SoftwareBillingDocumentFile[0];
        if (fileItem.PdfFile != null)
        {
            var formFile = fileItem.PdfFile;
            var extension = Path.GetExtension(formFile.FileName).ToLowerInvariant();
            
            if (extension != ".pdf")
            {
                return BadRequest("file type not supported");
            }

            var contentLength = formFile.Length / 1024;
            if (contentLength > 51200) // 限制50MB
            {
                return BadRequest("file size greater than 5mb is not allowed");
            }

            // 文件保存逻辑
            var fileName = formFile.FileName.Replace(" ", "");
            var guidFileName = $"{RandomString(10)}_{fileName}";
            var filePath = Path.Combine(Directory.GetCurrentDirectory(), "fileupload", guidFileName);
            
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                formFile.CopyTo(stream);
            }

            return Ok("File uploaded and data submitted successfully");
        }
    }

    return BadRequest("No file or valid data provided");
}

// 随机字符串生成方法
private string RandomString(int length)
{
    var random = new Random();
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    return new string(Enumerable.Repeat(chars, length)
        .Select(s => s[random.Next(s.Length)]).ToArray());
}

前端调整

1. 状态管理优化

在组件状态中单独存储选中的文件对象,方便后续组装FormData:

import { useState } from 'react';

const YourComponent = () => {
    // 初始化复杂JSON结构
    const [userData, setUserData] = useState({
        SNo: "",
        ApplicationName: "",
        // ... 其他字段初始化
        SoftwareBillingDocumentFile: []
    });
    const [selectedFile, setSelectedFile] = useState(null);

    // 文件选择处理
    const fileUploadHandler = (e) => {
        const file = e.target.files[0];
        setSelectedFile(file);
        
        setUserData(prev => ({
            ...prev,
            SoftwareBillingDocumentFile: [{
                FileName: file.name,
                DocumentType: file.type,
                SubmissionNo: "800030444804",
                SeqNo: 0,
                Document: ""
            }]
        }));
    };

2. 组装FormData并提交

将JSON数据序列化为字符串,与文件一起添加到FormData中,避免嵌套FormData:

// 表单提交方法
    const submitForm = async () => {
        const formData = new FormData();
        
        // 将整个业务数据序列化为JSON字符串
        formData.append('SoftwareBillingSubmission', JSON.stringify(userData));
        
        // 添加文件及相关属性,字段名匹配后端模型结构
        if (selectedFile && userData.SoftwareBillingDocumentFile.length > 0) {
            const fileItem = userData.SoftwareBillingDocumentFile[0];
            formData.append('SoftwareBillingDocumentFile[0].PdfFile', selectedFile);
            formData.append('SoftwareBillingDocumentFile[0].FileName', fileItem.FileName);
            formData.append('SoftwareBillingDocumentFile[0].DocumentType', fileItem.DocumentType);
            formData.append('SoftwareBillingDocumentFile[0].SubmissionNo', fileItem.SubmissionNo);
            formData.append('SoftwareBillingDocumentFile[0].SeqNo', fileItem.SeqNo);
        }
        
        try {
            const response = await fetch('/api/SubmitSoftwareBilling', {
                method: 'POST',
                body: formData
            });
            
            if (response.ok) {
                const result = await response.json();
                console.log('提交成功:', result);
            } else {
                const error = await response.text();
                console.error('提交失败:', error);
            }
        } catch (err) {
            console.error('请求出错:', err);
        }
    };

    return (
        <div>
            <input type="file" accept=".pdf" onChange={fileUploadHandler} />
            <button onClick={submitForm}>提交</button>
        </div>
    );
};

export default YourComponent;

内容的提问来源于stack exchange,提问作者Rajeev Yadav

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 06:30:16