Angular에서 ASP.NET Core로 파일 업로드

Dec 11 2020

처음으로 Angular 구성 요소에서 ASPNET Core 웹 페이지로 파일을 업로드하려고하는데 작동하지 않습니다. 바라건대 다음 코드 발췌 부분이 무슨 일이 일어나고 있는지의 핵심을 보여주기에 충분할 것입니다. 문제는 HttpClient의 post 메서드 (frmData)에 전달 된 매개 변수가 유효한지 확인했지만 ASPNet Core 작업 메서드가이 매개 변수를 보지 못하고 IFormFile이 항상 null이라고보고한다는 것입니다.

편집 : 이전에 콘텐츠 유형으로 multipart / form-data를 사용하려고 시도했지만 Kestrel의 용기에서 처리되지 않은 예외를 제공했습니다. 이것이 올바른 방법이며 json 콘텐츠 유형을 사용하는 것이 내 원래 문제의 원인이라는 것을 이제 깨달았습니다. 하지만 여기서 어디로 가야할지 모르겠습니다. 일부 인터넷 검색에서 해당 예외가 발생하는 데 약 10 억 가지 다른 원인이 있음을 알 수 있습니다.

POST 실행 끝점 'JovenesA.Controllers.StudentssController.PostStudentGradesReport (JAWebAPI)'
04 : 55 : 38.4853 정보 컨트롤러 ActionInvoker
{action = "PostStudentGradesReport", 컨트롤러 = "Becas"}와 일치하는 POST 경로. JovenesA.Controllers.BecasController.PostStudentGradesReport (JAWebAPI) 조치 실행
04 : 55 : 38.5032 오류 DeveloperExceptionPageMiddleware
POST 요청을 실행하는 동안 처리되지 않은 예외가 발생했습니다.
04 : 55 : 38.5333 정보 웹 호스트
POST 요청은 48.1225ms 500 text / html로 완료되었습니다. charset = utf-8
04 : 55 : 38.5333 정보 Kestrel
 연결 ID "0HM4UHGE85O17", 요청 ID "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 컨트롤

// 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 요청에서 전송되는 데이터입니다.

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
사용자 에이전트 : Mozilla / 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit / 537.36 (KHTML, like Gecko) Chrome / 87.0.4280.88 Safari / 537.36
콘텐츠 유형 : application / json
출처 : http : // localhost : 3000
참조 자 : http : // localhost : 3000 /
Accept-Encoding : gzip, deflate
Accept-Language : en-US, en; q = 0.9, es-MX; q = 0.8, es; q = 0.7

------ WebKitFormBoundaryBVuZ7IbkjtQAKQ0a
콘텐츠 처리 : 양식 데이터; name = "test1.PNG"; filename = "test1.PNG"
콘텐츠 유형 : image / png

 PNG
 
  [이미지 파일의 바이너리 내용]  

------ WebKitFormBoundaryBVuZ7IbkjtQAKQ0a--

답변

2 jandrew Dec 12 2020 at 09:30

파일을 양식 데이터로 보내므로 올바른 콘텐츠 유형 헤더를 지정해야합니다. 현재 헤더에 보내는 application/jsonContent-Type입니다. API를 호출하는 경우에도 마찬가지이며 처음에는 이해하기 어려울 수 있습니다. 이 경우 올바른 콘텐츠 유형은 multipart/form-data입니다. IFormFile요청이 JSON이라고 생각하기 때문에 API에이 표시되지 않습니다 . 올바른 콘텐츠 유형 헤더 값으로 Angular 코드를 수정했습니다.

편집 :Content-Type 헤더 를 수동으로 지정 하면 경계 값이 헤더 값에 자동으로 설정되지 않는 것으로 나타났습니다. 대신 간단한 해결책은 헤더를 직접 추가하지 않는 것입니다. 그러면 적절한 콘텐츠 유형 및 경계 값이 자동으로 설정됩니다. 헤더를 직접 설정하는 경우 경계 값도 설정해야합니다. 대부분의 경우 기본값으로 두는 것이 가장 좋은 해결책 일 것입니다. 이를 지적하는 질문 / 답변 링크. FormData multipart / form-data에서 경계를 가져 오거나 설정하는 방법-Angular

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 프로젝트를 시작하지는 않았지만 콘텐츠 유형이 문제를 해결해야합니다.

편집 : 파일이있는 양식 필드의 키로 파일 이름을 사용하고 있음을 확인했습니다. 컨트롤러 코드의 매개 변수 이름과 일치해야하는 양식 필드에 '파일'과 같은 키를 사용해야합니다. 컨트롤러 코드 내에서 파일의 실제 파일 이름을 얻을 수 있으며 키는 단순히 파일이 첨부 된 양식 필드를 나타냅니다. 예

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(); 
}
1 Coco Dec 11 2020 at 23:02

이것이 작동한다고 보장 할 수는 없지만 Angular의 HttpRequest를 사용해 볼 수 있습니다. 따라서 각도 서비스에서 다음을 시도하십시오.

const request = new HttpRequest (
    'POST',
     url, // http://localhost/your_endpoint
     frmData,
     { withCredentials: false }
);
    
return this.http.request(request);

또한 백엔드 API를 호출하는 함수에서 데이터 유효성 검사를 수행하면 안됩니다. if(frmData)거짓 이면 함수가 무엇을 반환 합니까?