angular - 从 Angular 上传文件到 ASP.NET Core

标签 angular asp.net-core kestrel-http-server

我第一次尝试将文件从 Angular 组件上传到 ASPNET Core 网页,但根本无法正常工作。希望以下代码摘录足以显示正在发生的事情的要点。问题是,虽然我确认传递给 HttpClient 的 post 方法 (frmData) 的参数是有效的,但 ASPNet Core 操作方法从未看到它,并报告 IFormFile 始终为 null。

编辑:我之前曾尝试使用 multipart/form-data 作为内容类型,但我在 Kestrel 的内部给出了一个未处理的异常 .我现在意识到这是正确的方法,使用 json 内容类型是我的原始问题的根源。但我不知道从这里去哪里。我从一些谷歌搜索中看到,大约有\billion 个不同的原因导致该异常发生。

POST Executing endpoint 'JovenesA.Controllers.StudentssController.PostStudentGradesReport (JAWebAPI)'
04:55:38.4853 Info ControllerActionInvoker
POST Route matched with {action = "PostStudentGradesReport", controller = "Becas"}. Executing action JovenesA.Controllers.BecasController.PostStudentGradesReport (JAWebAPI)
04:55:38.5032 Error DeveloperExceptionPageMiddleware
POST An unhandled exception has occurred while executing the request.
04:55:38.5333 Info WebHost
POST Request finished in 48.1225ms 500 text/html; charset=utf-8
04:55:38.5333 Info Kestrel
 Connection id "0HM4UHGE85O17", Request id "0HM4UHGE85O17:00000006": the application completed without reading the entire request body.

Any help would be greatly appreciated!

Angular Component:

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;
        }
      );
    });

Angular 服务:

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 核心控件

// 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
Host: 192.168.0.16:1099
Connection: keep-alive
Content-Length: 13561
Accept: application/json, text/plain, */*
DNT: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36
Content-Type: application/json
Origin: http://localhost:3000
Referer: 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
Content-Disposition: form-data; name="test1.PNG"; filename="test1.PNG"
Content-Type: image/png

 PNG
 
  [ binary contents of the image file ]  

------WebKitFormBoundaryBVuZ7IbkjtQAKQ0a--

最佳答案

您将文件作为表单数据发送,因此您需要指定正确的内容类型 header 。目前您在 Content-Type header 中发送 application/json 。即使在调用 API 时也是如此,一开始可能会造成混淆,这是可以理解的。在这种情况下,正确的内容类型是 multipart/form-data。您的 API 没有看到 IFormFile,因为它认为请求是 JSON。我已经使用正确的内容类型 header 值修改了您的 Angular 代码。

编辑: 结果表明,手动指定 Content-Type header 将导致不会在 header 值中自动设置边界值。相反,简单的解决方案是不要自己添加 header ,这将导致自动设置正确的内容类型和边界值。如果您自己设置 header ,则还必须设置边界值。对于大多数情况,将其保留为默认值可能是最好的解决方案。指向指出这一点的问题/答案的链接。 FormData how to get or set boundary in 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 项目来测试您的代码,但内容类型应该可以解决您的问题。

编辑:我注意到您使用文件名作为文件表单字段的键。您需要为表单字段使用诸如"file"之类的键,该键应与 Controller 代码中的参数名称相匹配。您可以在 Controller 代码中获取文件的实际文件名,键仅指示文件附加到哪个表单字段。示例

frmData.append('file', file);

然后为您的 Controller 操作

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(); 
}

关于angular - 从 Angular 上传文件到 ASP.NET Core,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65256628/

相关文章:

Angular Material : Split button

javascript - 如何检查 mobx observable 是否有订阅者?

angular - 防止 Angular 在重新访问路由时构造组件的新实例(路由重用策略)

c# - Dapper 选择映射到模型的内连接

asp.net-mvc - Asp Net vNext 上的 Kestrel 不提供/下的索引页

angular - 在 Azure 上部署 Angular 应用程序时出现 '/' 应用程序中的服务器错误

c# - 删除 taghelper 生成的输入标签中的前缀

c# - 当托管在 Azure 应用服务中时,如何控制添加到 ASP.NET Core Web 应用程序的 HTTP 响应 header ?

asp.net-core - 找不到 Index.cshtml NET Core 应用程序 3.0

visual-studio-2015 - 在 Windows 中发布的 ASP.NET 5 Web 应用程序可以在 Linux 上运行吗?