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。”
我该怎么做才能传入两个参数类?
谢谢!!
原因是您正在发送一个类似 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);
}
}