【问题标题】:Upload File(s) with Additional Information (Angular 8 to C# Core 3)上传带有附加信息的文件(Angular 8 到 C# Core 3)
【发布时间】:2020-03-15 06:17:02
【问题描述】:

我终于想出了如何将文件从 Angular 8 前端上传到 C# .Net Core 3.0 后端 API 控制器。但是为了得到我完全需要的东西,我还有一个类,它定义了需要传入的用户设置的文件内容(例如,标题行数、列值等等......)。

在客户端,我只需创建一个 FormData 对象并将文件推送到其中,然后将其发送到后端。如果我只是发送此类然后在后端将其作为“IFormFileCollection”接收,这将非常有用。但是,如果我将 FormData 和我的附加类放在 Wrapper 类中,则会出现错误(发布在底部)。这里我贴出不起作用的代码。

这是我发送的客户端代码:

export interface FileProvider 
{
  formData: FormData;
  testString: string;
}

然后我的 TypeScript 代码发送到后端:

 async UploadFiles() {

    try {

      let files: File[] = this.files;
      let myFormData: FormData = new FormData();

      for (let i = 0; i < files.length; i++) {
        let file: File = files[i];
        myFormData.append('file', file, file.name);
      }

      /** Wrap this in a class. */
      let fileProvider: FileProvider = {
        formData: myFormData,
        testString: "This is just a test string... but will be a class"
      }

      let promise = new Promise((resolve, reject) => {
        this.dataService.UploadData(fileProvider).subscribe(data => resolve(data), error => reject(error))
      });

      let result = await promise;
      alert("Successfully loaded Data");
    }
    catch (error) {
      alert(error.message + ", Status: " + error.status + ",  OK: " + error.ok + ",  " + error.error);
    }
  }

我的小DataService post方法:

  UploadData(fileProvider: FileProvider) {
    let path: string = this.api + 'wells/formdata';
    return this.http.post(path, fileProvider);
  }

还有我的 C# .Net Core 3 后端控制器代码:

        [Serializable]
        public class FileProvider
        {
            public IFormCollection FormData { get; set; }
            public string TestString { get; set; }
        }


     [HttpPost("formdata"), DisableRequestSizeLimit]
        public IActionResult Upload(FileProvider fileProvider)
        {
            try
            {

                IFormFileCollection fileCollection = fileProvider.FormData.Files;
                string testString = fileProvider.TestString;


                foreach (IFormFile file in fileCollection)
                {

                    /// Read at a line a time.
                    StringBuilder lineAtATime = new StringBuilder();
                    using (var reader = new StreamReader(file.OpenReadStream()))
                    {
                        while (reader.Peek() >= 0)
                        {
                            string line = reader.ReadLine();
                            lineAtATime.Append(line);
                        }
                    }
                    string textByLines = lineAtATime.ToString();


                }
                return Ok();
            }
            catch (Exception ex)
            {
                return StatusCode(500, "Internal server error: " + ex.Message);
            }
        }

最终抛出的错误如下:

"无法将当前 JSON 对象(例如 {"name":"value"})反序列化为类型 'Microsoft.AspNetCore.Http.IFormCollection' 因为该类型需要一个 JSON 数组(例如 [1,2,3])才能正确反序列化。 要修复此错误,请将 JSON 更改为 JSON 数组(例如 [1,2,3])或更改反序列化类型,使其 是一个普通的 .NET 类型(例如,不是像整数这样的原始类型,不是像数组或列表这样的集合类型),可以 从 JSON 对象反序列化。 JsonObjectAttribute 也可以添加到类型中以强制它从 JSON 对象反序列化。 路径 'formData',第 1 行,位置 14。”

我可以做些什么来传递两个参数类?

谢谢!!

【问题讨论】:

    标签: c# angular file-upload asp.net-core-3.0


    【解决方案1】:

    原因是您发送的是 类 json 对象,而不是 multipart/form-data 格式的有效负载。由于JSON 不能表示二进制字节(文件),因此您永远无法做到这一点。

    如何解决:

    无需上传自定义FileProvider (json),只需testString 字段附加到FormData,然后直接上传FormData

    服务器端

    FormData 属性替换为IList&lt;IFormFile&gt; Files

    [可序列化] 公共类 FileProvider { 公共字符串 TestString { 获取;放; } public IFormCollection FormData { get;放; } 公共 IList 文件 { 获取;放; } } public IActionResult Upload([FromForm]FileProvider fileProvider) { var 文件 = fileProvider.Files; var testString = fileProvider.TestString; ... }

    客户端

    更改您的Service 以接收FormData 类型的参数:

    UploadData(fileProvider: FileProvider) { 上传数据(表单数据:表单数据){ 让路径:string = this.api+ 'wells/formdata'; 返回 this.http.post(path, formdata); }

    最后,将额外的字段直接附加到FormData

    异步上传文件(){ 尝试 { 让文件:文件[] = this.files; 让 myFormData: FormData = new FormData(); for (让 i = 0; i myFormData.append('file', file, file.name); myFormData.append('files', file, file.name); // 文件名是 `files` 因为服务器端声明了一个 `Files` 属性 } myFormData.append("testString", "This is just a test string... but will be a class"); // 添加额外字段 // ... 根据需要添加更多字段 让 fileProvider: FileProvider = { 表单数据:我的表单数据, testString:“这只是一个测试字符串......但将是一个类” } 让 promise = new Promise((resolve, reject) => { this.dataService.UploadData(fileProvider).subscribe(data => resolve(data), error => reject(error)) }); 让 resp = await this.dataService.UploadData(myFormData).toPromise(); alert("数据加载成功"); } 捕捉(错误){ alert(error.message + ", 状态: " + error.status + ", OK: " + error.ok + ", " + error.error); } }

    【讨论】:

    • 昨天看了更多之后发现,这正是我所做的。我只是不确定这是否是“可行的方式”,但很高兴看到这是您推荐的。非常感谢!!像你这样的人真的让 StackOverflow 成为了一个很棒的工具。我检查了您的回复是否已接受。
    猜你喜欢
    • 2019-10-14
    • 2015-05-26
    • 2020-07-09
    • 2022-11-08
    • 1970-01-01
    • 2011-07-28
    • 2021-12-03
    • 2021-09-07
    • 2019-11-03
    相关资源
    最近更新 更多