อัปโหลดไฟล์จาก Angular ไปยัง ASP.NET Core
เป็นครั้งแรกที่ฉันพยายามอัปโหลดไฟล์จากส่วนประกอบเชิงมุมไปยังหน้าเว็บ ASPNET Core และไม่สามารถใช้งานได้ หวังว่าข้อความที่ตัดตอนมาของโค้ดต่อไปนี้จะเพียงพอที่จะแสดงข้อมูลสำคัญของสิ่งที่เกิดขึ้น ปัญหาคือแม้ว่าฉันจะยืนยันว่าพารามิเตอร์ที่ส่งไปยังเมธอดการโพสต์ของ HttpClient (frmData) นั้นถูกต้อง แต่วิธีการดำเนินการของ ASPNet Core จะไม่เห็นมันและรายงานว่า IFormFile เป็นโมฆะเสมอ
แก้ไข: ก่อนหน้านี้ฉันเคยลองใช้หลายส่วน / แบบฟอร์มข้อมูลเป็นประเภทเนื้อหา แต่ฉันให้ข้อยกเว้นที่ไม่สามารถจัดการได้ในความกล้าของ Kestrel ฉันรู้แล้วว่านี่เป็นวิธีที่ถูกต้องในการทำและการใช้ประเภทเนื้อหา json เป็นที่มาของปัญหาดั้งเดิมของฉัน แต่ฉันไม่รู้ว่าจะไปจากที่นี่ ฉันเห็นจาก googling บางอย่างมีสาเหตุที่แตกต่างกันประมาณพันล้านสาเหตุที่ทำให้เกิดข้อยกเว้น
POST ดำเนินการจุดสิ้นสุด 'JovenesA.Controllers.StudentssController.PostStudentGradesReport (JAWebAPI)'
04: 55: 38.4853 Info ControllerActionInvoker
POST เส้นทางตรงกับ {action = "PostStudentGradesReport", controller = "Becas"} การดำเนินการดำเนินการ JovenesA.Controllers.BecasController.PostStudentGradesReport (JAWebAPI)
04: 55: 38.5032 ข้อผิดพลาด DeveloperExceptionPageMiddleware
POST มีข้อยกเว้นที่ไม่สามารถจัดการได้เกิดขึ้นขณะดำเนินการตามคำขอ
04: 55: 38.5333 ข้อมูล WebHost
คำขอ POST เสร็จสิ้นใน 48.1225ms 500 text / html; charset = utf-8
04: 55: 38.5333 ข้อมูล Kestrel
รหัสการเชื่อมต่อ "0HM4UHGE85O17", รหัสคำขอ "0HM4UHGE85O17: 00000006": แอปพลิเคชันเสร็จสมบูรณ์โดยไม่อ่านเนื้อหาคำขอทั้งหมด
ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชมอย่างมาก!
ส่วนประกอบเชิงมุม:
fileEntry.file((file: File) => {
console.log('fileEntry relativePath: ' + currFile.relativePath);
console.log('filEntry.name: ', file.name);
console.log('filEntry.size: ', file.size);
const frmData = new FormData();
frmData.append(file.name, file);
this.studentData.uploadStudentGradesReport(file.name, frmData).subscribe(
() => {
this.successMessage = 'Changes were saved successfully.';
window.scrollTo(0, 0);
window.setTimeout(() => {
this.successMessage = '';
}, 3000);
},
(error) => {
this.errorMessage = error;
}
);
});
บริการเชิงมุม:
public uploadStudentGradesReport(filename: string, frmData: FormData): Observable<any> {
const url = this.WebApiPrefix + 'students/' + 'student-grades-report';
const headers = new HttpHeaders().set('Content-Type', 'application/json');
if (frmData) {
console.log('ready to post ' + url + ' filename: ' + filename + ' options ' + headers);
return this.http.post(url, frmData, { headers });
}
}
ASPNET Core Controlle
// POST api/students/student-grades-report
[HttpPost("student-grades-report", Name = "PostStudentGradseReportRoute")]
//[ValidateAntiForgeryToken]
[ProducesResponseType(typeof(GradesGivenEntryApiResponse), 200)]
[ProducesResponseType(typeof(GradesGivenEntryApiResponse), 400)]
public async Task<ActionResult> PostStudentGradesReport([FromForm] IFormFile myFile)
{
_Logger.LogInformation("Post StudentGradesReport ");
if (myFile != null)
{
var totalSize = myFile.Length;
var fileBytes = new byte[myFile.Length];
หากช่วยได้นี่คือข้อมูลที่กำลังส่งในคำขอ POST
โพสต์ http://192.168.0.16:1099/api/students/student-grades-report HTTP / 1.1 โฮสต์: 192.168.0.16:1099 การเชื่อมต่อ: ให้มีชีวิตอยู่ ความยาวเนื้อหา: 13561 ยอมรับ: application / json, text / plain, * / * DNT: 1 User-Agent: Mozilla / 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit / 537.36 (KHTML เช่น Gecko) Chrome / 87.0.4280.88 Safari / 537.36 ประเภทเนื้อหา: application / json ที่มา: http: // localhost: 3000 ผู้อ้างอิง: http: // localhost: 3000 / ยอมรับการเข้ารหัส: gzip, deflate ภาษาที่ยอมรับ: en-US, en; q = 0.9, es-MX; q = 0.8, es; q = 0.7 ------ WebKitFormBoundaryBVuZ7IbkjtQAKQ0a Content-Disposition: form-data; ชื่อ = "test1.PNG"; ชื่อไฟล์ = "test1.PNG" ประเภทเนื้อหา: image / png PNG [เนื้อหาไบนารีของไฟล์รูปภาพ] ------ WebKitFormBoundaryBVuZ7IbkjtQAKQ0a--
คำตอบ
คุณกำลังส่งไฟล์เป็นข้อมูลแบบฟอร์มดังนั้นคุณต้องระบุส่วนหัวประเภทเนื้อหาที่ถูกต้อง ขณะนี้การส่งของคุณapplication/jsonในContent-Typeส่วนหัว แม้ว่าจะเรียก API ซึ่งอาจทำให้เกิดความสับสนได้ในตอนแรก multipart/form-dataประเภทเนื้อหาที่ถูกต้องในกรณีนี้คือ API ของคุณไม่เห็นIFormFileเนื่องจากคิดว่าคำขอเป็น JSON ฉันได้แก้ไขโค้ดเชิงมุมของคุณด้วยค่าส่วนหัวประเภทเนื้อหาที่ถูกต้อง
แก้ไข:ปรากฎว่าการระบุContent-Typeส่วนหัวด้วยตนเองจะทำให้ค่าขอบเขตไม่ถูกตั้งค่าโดยอัตโนมัติในค่าส่วนหัว วิธีแก้ปัญหาง่ายๆคืออย่าเพิ่มส่วนหัวด้วยตัวเองซึ่งจะส่งผลให้ค่าประเภทเนื้อหาและขอบเขตที่เหมาะสมถูกกำหนดโดยอัตโนมัติ หากคุณตั้งค่าส่วนหัวด้วยตัวคุณเองคุณจะต้องกำหนดค่าขอบเขตด้วยเช่นกัน สำหรับสถานการณ์ส่วนใหญ่การปล่อยให้เป็นค่าเริ่มต้นน่าจะเป็นทางออกที่ดีที่สุด เชื่อมโยงไปยังคำถาม / คำตอบที่ชี้ให้เห็น FormData วิธีรับหรือกำหนดขอบเขตในหลายส่วน / แบบฟอร์มข้อมูล - เชิงมุม
public uploadStudentGradesReport(filename: string, frmData: FormData): Observable<any> {
const url = this.WebApiPrefix + 'students/' + 'student-grades-report';
const headers = new HttpHeaders().set('Content-Type', 'multipart/form-data');
if (frmData) {
console.log('ready to post ' + url + ' filename: ' + filename + ' options ' + headers);
return this.http.post(url, frmData, { headers });
}
}
คุณยังสามารถจดบันทึกการจัดการเนื้อหาที่อยู่ในคำขอ HTTP ที่คุณระบุซึ่งจะแสดงข้อมูลแบบฟอร์มพร้อมกับประเภทของไฟล์ที่แนบ หวังว่านี่จะช่วยได้ ฉันไม่ได้เริ่มโครงการ Angular เพื่อทดสอบโค้ดของคุณ แต่ประเภทเนื้อหาควรแก้ไขปัญหาของคุณได้
แก้ไข : ฉันสังเกตเห็นว่าคุณใช้ชื่อไฟล์เป็นคีย์สำหรับฟิลด์แบบฟอร์มกับไฟล์ คุณต้องใช้คีย์เช่น 'file' สำหรับฟิลด์แบบฟอร์มซึ่งควรตรงกับชื่อของพารามิเตอร์ในรหัสคอนโทรลเลอร์ของคุณ คุณสามารถรับชื่อไฟล์ที่แท้จริงของไฟล์ได้ภายในรหัสคอนโทรลเลอร์ของคุณคีย์จะระบุเพียงว่าฟิลด์ฟอร์มใดที่ไฟล์แนบอยู่ ตัวอย่าง
frmData.append('file', file);
จากนั้นสำหรับการดำเนินการควบคุมของคุณ
public async Task<IActionResult> PostStudentGradesReport([FromForm] IFormFile file)
{
if (file.Length <= 0 || file.ContentType is null) return BadRequest();
var actualFileName = file.FileName;
using (var stream = file.OpenReadStream())
{
// Process file...
}
return Ok();
}
ฉันไม่สามารถรับประกันได้ว่าจะได้ผล แต่คุณสามารถลองใช้ HttpRequest ของ Angular ดังนั้นในบริการเชิงมุมของคุณให้ลองทำดังนี้:
const request = new HttpRequest (
'POST',
url, // http://localhost/your_endpoint
frmData,
{ withCredentials: false }
);
return this.http.request(request);
โปรดทราบว่าคุณไม่ควรทำการตรวจสอบข้อมูลในฟังก์ชันที่เรียกใช้แบ็กเอนด์ Api ฟังก์ชันของคุณจะส่งคืนอะไรหากif(frmData)เป็นเท็จ