上传包含附加信息的文件(Angular 8 到 C# Core 3)
Upload File(s) with Additional Information (Angular 8 to C# Core 3)
我终于想出了如何将文件从 Angular 8 前端上传到 C# .Net Core 3.0 后端 API 控制器。但是为了得到我完全需要的东西,我还有一个 class 来定义文件内容(例如 header 行的#,列值等等......)由需要的用户设置也被传入。
在客户端,我只是创建一个 FormData object 并将文件推送到其中,然后将其发送到后端。如果我只发送此 class 然后在后端将其作为 "IFormFileCollection" 接收,则效果很好。但是,如果我将 FormData 和附加的 class 放入包装器 class 中,则会出现错误(posted 在底部)。这里我 post 代码不起作用。
这是我发送的客户端代码:
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);
}
}
我的小数据服务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);
}
}
最后抛出的错误如下:
"Cannot deserialize the current JSON object (e.g. {"name":"value"}) 输入 'Microsoft.AspNetCore.Http.IFormCollection'
因为该类型需要 JSON 数组(例如 [1,2,3])才能正确反序列化。
要修复此错误,请将 JSON 更改为 JSON 数组(例如 [1,2,3])或更改反序列化类型,以便它
是一个普通的 .NET 类型(例如,不是像整数这样的原始类型,不是像数组或列表这样的 collection 类型),它可以是
从 JSON object 反序列化。也可以将 JsonObjectAttribute 添加到类型以强制它从 JSON object 反序列化。
路径 'formData',第 1 行,位置 14。“
如何传入两个参数 classes?
谢谢!!
原因是您发送的是 json 类对象 而不是 multipart/form-data
[=46= 中的有效负载] 格式。因为 JSON
不能表示二进制字节(文件),所以你永远不能用那种方式来表示。
如何修复:
无需上传自定义 FileProvider
(json),只需 将 testString
字段附加到 FormData
,然后直接上传FormData
.
服务器端
将 FormData
属性 替换为 IList<IFormFile> Files
:
[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);
}
}
我终于想出了如何将文件从 Angular 8 前端上传到 C# .Net Core 3.0 后端 API 控制器。但是为了得到我完全需要的东西,我还有一个 class 来定义文件内容(例如 header 行的#,列值等等......)由需要的用户设置也被传入。
在客户端,我只是创建一个 FormData object 并将文件推送到其中,然后将其发送到后端。如果我只发送此 class 然后在后端将其作为 "IFormFileCollection" 接收,则效果很好。但是,如果我将 FormData 和附加的 class 放入包装器 class 中,则会出现错误(posted 在底部)。这里我 post 代码不起作用。
这是我发送的客户端代码:
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);
}
}
我的小数据服务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);
}
}
最后抛出的错误如下:
"Cannot deserialize the current JSON object (e.g. {"name":"value"}) 输入 'Microsoft.AspNetCore.Http.IFormCollection' 因为该类型需要 JSON 数组(例如 [1,2,3])才能正确反序列化。 要修复此错误,请将 JSON 更改为 JSON 数组(例如 [1,2,3])或更改反序列化类型,以便它 是一个普通的 .NET 类型(例如,不是像整数这样的原始类型,不是像数组或列表这样的 collection 类型),它可以是 从 JSON object 反序列化。也可以将 JsonObjectAttribute 添加到类型以强制它从 JSON object 反序列化。 路径 'formData',第 1 行,位置 14。“
如何传入两个参数 classes?
谢谢!!
原因是您发送的是 json 类对象 而不是 multipart/form-data
[=46= 中的有效负载] 格式。因为 JSON
不能表示二进制字节(文件),所以你永远不能用那种方式来表示。
如何修复:
无需上传自定义 FileProvider
(json),只需 将 testString
字段附加到 FormData
,然后直接上传FormData
.
服务器端
将 FormData
属性 替换为 IList<IFormFile> Files
:
[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 likelet 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); } }