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

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

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

在客户端,我只需创建一个 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 后端 Controller 代码:

        [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。”

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

谢谢!!

最佳答案

原因是您在 multipart/form-data 中发送的是 类 json 对象 而不是有效负载 格式。从 JSON不能表示二进制字节(文件),你永远不能这样。

如何解决:

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

服务器端

替换FormData IList<IFormFile> Files 的属性(property):

[Serializable]
public class FileProvider
{
    public string TestString { get; set; }
    public IFormCollection FormData { get; set; }
    public IList<IFormFile> Files { get; set; }
}

public IActionResult Upload([FromForm]FileProvider fileProvider)
{
    var files = fileProvider.Files;
    var testString = fileProvider.TestString;
    ...
}

客户端

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

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

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

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);
        myFormData.append('files', file, file.name);    // the filed name is `files` because the server side declares a `Files` property
      }
      myFormData.append("testString", "This is just a test string... but will be a class");       // add extra fields 
      // ... add more fields as you like

      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 resp = await this.dataService.UploadData(myFormData).toPromise();
      alert("Successfully loaded Data");
    }
    catch (error) {
      alert(error.message + ", Status: " + error.status + ",  OK: " + error.ok + ",  " + error.error);
    }
}

关于c# - 上传带有附加信息的文件(Angular 8 到 C# Core 3),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58938944/

相关文章:

javascript - Angular 2 @HostListener 未捕获 keyup 事件

asp.net-mvc-2 - 使用 Jquery 表单插件上传图像在 IE8 中不起作用

c# - WCF - 如何在 C# 代码中指定端点的契约(Contract)?

C# 隐式更新传递给没有返回类型且没有 out 或 ref 用法的方法的参数

java - 带有 Angular 的 Spring Boot。从源 'http://localhost:8080/' 访问位于 'http://localhost:4200' 的 XMLHttpRequest 已被 CORS 策略阻止

angular - 保持按钮禁用,直到用户到达 Angular Material 对话框中文本段落的末尾

javascript - 如何通过 javascript 将文件上传到保管箱?

Java文件上传在上传时重命名文件

c# - 连接到集线器的 SignalR 2.2.0 WebSocket 错误

c# - .NET 中的货币格式