文件从Angular上载到ASP.NET Core

文件从Angular上载到ASP.NET Core,angular,asp.net-core,kestrel-http-server,Angular,Asp.net Core,Kestrel Http Server,这是我第一次尝试将文件从Angular组件上传到ASPNET Core网页,但根本无法让它工作。希望下面的代码摘录足以说明正在进行的工作的要点。问题是,尽管我确认传递给HttpClient的post方法(frmData)的参数是有效的,但ASPNet核心操作方法从未看到它,并报告IFormFile始终为null 编辑:我以前曾尝试使用多部分/表单数据作为内容类型,但我给出了一个未经处理的异常 . 我现在意识到这是正确的方法,使用json内容类型是我最初问题的根源。但我不知道接下来该怎么办。我在谷

这是我第一次尝试将文件从Angular组件上传到ASPNET Core网页,但根本无法让它工作。希望下面的代码摘录足以说明正在进行的工作的要点。问题是,尽管我确认传递给HttpClient的post方法(frmData)的参数是有效的,但ASPNet核心操作方法从未看到它,并报告IFormFile始终为null

编辑:我以前曾尝试使用多部分/表单数据作为内容类型,但我给出了一个未经处理的异常 . 我现在意识到这是正确的方法,使用json内容类型是我最初问题的根源。但我不知道接下来该怎么办。我在谷歌上看到,出现这种异常的原因大约有十亿种

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. 角度服务:

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 });
    }
}
public uploadStudentGradesReport(文件名:string,frmData:FormData):可观察{
const url=this.WebApiPrefix+“学生/”+“学生成绩报告”;
const headers=new-HttpHeaders().set('Content-Type','application/json');
如果(frmData){
log('ready to post'+url+'filename:'+filename+'options'+headers');
返回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];
//发布api/学生/学生成绩报告
[HttpPost(“学生成绩报告”,Name=“PostStudentGradesReportRoute”)]
//[ValidateAntiForgeryToken]
[ProductsResponseType(typeof(GradesGiveEntryAPIResponse),200)]
[ProductsResponseType(typeof(gradesgiveEntryAPIResponse),400)]
公共异步任务PostStudentGradesReport([FromForm]IFormFile myFile)
{
_登录信息(“学生成绩报告”);
如果(myFile!=null)
{
var totalSize=myFile.Length;
var fileBytes=新字节[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-- 邮递http://192.168.0.16:1099/api/students/student-职系报告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,类似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 内容配置:表单数据;name=“test1.PNG”;filename=“test1.PNG” 内容类型:图像/png 巴布亚新几内亚 [图像文件的二进制内容] ------WebKitFormBoundaryBVuZ7IbkjtQAKQ0a--
我不能保证这会起作用,但您可以尝试使用Angular的HttpRequest。因此,在Angular服务中,请尝试以下方法:

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

还请注意,您不应该在调用后端Api的函数中执行数据验证。如果
if(frmData),您的函数将返回什么
为false?

您将文件作为表单数据发送,因此需要指定正确的内容类型标头。当前,您正在
内容类型
标头中发送
应用程序/json
。即使在调用API时也是如此,这在一开始可能会让人困惑。在这种情况下,正确的内容类型是
mul>tipart/form data
。您的API没有看到
ifformfile
,因为它认为请求是JSON。我已经用正确的内容类型头值修改了您的Angular代码

编辑:结果表明,手动指定
内容类型
标题将导致不会在标题值中自动设置边界值。相反,简单的解决方案是不自己添加标题,这将导致自动设置正确的内容类型和边界值。如果设置标题呃,你自己也必须设置边界值。对于大多数情况,保留默认值可能是最好的解决方案。链接到问题/答案,指出了这一点。

public uploadStudentGradesReport(文件名:string,frmData:FormData):可观察{
const url=this.WebApiPrefix+“学生/”+“学生成绩报告”;
const headers=new HttpHeaders().set('Content-Type','multipart/form data');
如果(frmData){
log('ready to post'+url+'filename:'+filename+'options'+headers');
返回this.http.post(url,frmData,{headers});
}
}
您还可以注意到您提供的HTTP请求上的内容配置,其中显示了表单数据以及所附文件的类型。希望这能有所帮助。我没有启动Angular项目来测试您的代码,但内容类型应该可以解决您的问题

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

frmData.append('file',file);
然后是控制器的动作

public异步任务PostStudentGradesReport([FromForm]ifformfile)
{

如果(file.Length感谢您的建议;但是遗憾的是,数据仍然没有进入ASPNet控制器。关于数据验证,您是正确的,我只是暂时将其放在那里,以便在调用之前证明frmData在客户端不是空的。
内容类型:application/json
这是您的问题,对吗这里。如果要将文件作为表单数据发送,则需要在Angular请求代码中指定正确的内容类型。在这种情况下,正确的类型应该是
multipart/form data
。即使在调用API时也是如此,文件上载的标准方法是将其作为表单数据发送,如yo
const request = new HttpRequest (
    'POST',
     url, // http://localhost/your_endpoint
     frmData,
     { withCredentials: false }
);
    
return this.http.request(request);