上传带有附加信息的文件(Angular 8 到 C# Core 3)

Chr*_*ris 2 c# file-upload angular asp.net-core-3.0

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

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

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

export interface FileProvider 
{
  formData: FormData;
  testString: string;
}
Run Code Online (Sandbox Code Playgroud)

然后我的 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);
    }
  }
Run Code Online (Sandbox Code Playgroud)

我的小型 DataService post 方法:

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

还有我的 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);
            }
        }

Run Code Online (Sandbox Code Playgroud)

抛出的最终错误如下:

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

我该怎么做才能传入两个参数类?

谢谢!!

itm*_*nus 7

原因是您正在发送一个类似 json 的对象而不是multipart/form-data格式的有效负载。由于JSON不能表示二进制字节(文件),因此您永远无法通过这种方式实现。

怎么修:

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

服务器端

FormData属性替换为IList<IFormFile> Files

[可序列化]
公共类 FileProvider
{
    公共字符串 TestString { 获取;放; }
    公共 IFormCollection FormData { 获取;放; }
    公共 IList<IFormFile> 文件 { get; 放; }
}

公共 IActionResult 上传([FromForm] FileProvider fileProvider)
{
    var 文件 = fileProvider.Files;
    var testString = fileProvider.TestString;
    ...
}

客户端

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

  上传数据(文件提供者:文件提供者){
  上传数据(表单数据:表单数据){
    让路径:string = this.api+ 'wells/formdata';
    返回 this.http.post(path, formdata);
  }

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

异步上传文件(){
    尝试 {

      让文件:文件[] = this.files;
      让 myFormData: FormData = new FormData();

      for (let i = 0; i < files.length; i++) {
        让文件:文件 = 文件 [i];
        myFormData.append('file', file, file.name); 
        myFormData.append('files', file, file.name);     // 文件名是 `files` 因为服务器端声明了一个 `Files` 属性
      }
      myFormData.append("testString", "这只是一个测试字符串...但将是一个类");        // 添加额外的字段
      // ... 根据需要添加更多字段

      让文件提供者:文件提供者 = {
        表单数据:我的表单数据,
        testString: "这只是一个测试字符串......但将是一个类"
      }

      让承诺 = 新承诺((解决,拒绝)=> {
        this.dataService.UploadData(fileProvider).subscribe(data => resolve(data), error => reject(error))
      });

      let resp = await this.dataService.UploadData(myFormData).toPromise();
      alert("数据加载成功");
    }
    捕捉(错误){
      alert(error.message + ", Status: " + error.status + ", OK: " + error.ok + ", " + error.error);
    }
}

  • 昨天读了更多内容后发现,这正是我所做的。我只是不确定这是否是一种“可行的方式”,但很高兴看到这是您推荐的。非常感谢!!像您这样的人确实让 StackOverflow 成为了一个很棒的工具。我检查了您的回复已被接受。 (2认同)