【问题标题】:WebAPI core IFormFile always showing nullWebAPI 核心 IFormFile 始终显示 null
【发布时间】:2018-04-20 07:03:40
【问题描述】:

我有一个 Angular 4 的前端和一个 ASP.NET Core WebAPI 的后端,它们的功能是将数据和一个人的简历发送到一个数据库,即 SQL Server,但是。 .. 捕获数据并将文件发送到数据库的方法的 IFormFile 总是为空。

我已经尝试了在互联网上找到的所有类型的解决方案,但没有一个对我有用。

作为 Post 方法的响应,我收到此异常

An unhandled exception occurred while processing the request.  
  NullReferenceException: Object reference not set to an instance of an object.  
  WebApplication.Controllers.CandidateController+<Post>d__4.MoveNext() in CandidateController.cs, line 60

我在这里粘贴了执行此操作的项目的部分代码。

完整代码的github链接:
front-end code
back-end code

HTML

<form class="col-md-6 offset-md-3" method="POST" enctype="multipart/form-data" #form="ngForm" (ngSubmit)="onSubmit(form)">
  <div class="form-group row">
    <label for="name" class="col-sm-2 col-form-label">Name</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" placeholder="Nome completo" id="name"  name="name" ngModel />
    </div>
  </div>
  <div class="form-group row">
    <label for="email" class="col-sm-2 col-form-label">Email</label>
    <div class="col-sm-10">
      <input type="email" class="form-control" id="email" placeholder="Email" name="email" ngModel />
      <small id="emailHelp" class="form-text text-muted">
        We'll never share your email with anyone else.
      </small>
    </div>
  </div>
  <div class="form-group row">
    <label for="country" class="col-sm-2 col-form-label">Country</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" id="country" placeholder="Country" name="country" ngModel />
    </div>
  </div>
  <div class="form-group row">
    <label for="state" class="col-sm-2 col-form-label">State</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" id="state" placeholder="Estado" name="state" ngModel />
    </div>
  </div>
  <div class="form-group row">
    <label for="city" class="col-sm-2 col-form-label">City</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" id="city" placeholder="Cidade" name="city" ngModel />
    </div>
  </div>
  <div class="form-group row">
    <label for="file" class="col-sm-2 col-form-label">Curriculum</label>
    <div class="col-sm-10">
        <input type="file" id="file" name="file" ngModel />
    </div>
  </div>
  <div class="container text-center">
    <button type="submit" class="btn btn-outline-dark">Submit</button>
  </div>
</form>

Angular 4

onSubmit(form: NgForm) {
  const { file } = form.value;
  delete form.value.file;

  var data = new FormData();
  data.append('Candidates', JSON.stringify(form.value));
  data.append('file', file);

  console.log(form.value);
  console.log(file);

  const headers = new Headers();
  headers.append('Access-Control-Allow-Origin', '*');

  const options = new RequestOptions({headers: headers});

  this.http.post("http://localhost:54392/api/candidates", data, options)
    .subscribe(
      data => {
        console.log("Foi");
      },
      error => {
        console.log("Não foi");
      });
}

C#

[HttpPost("candidates")]
public async Task<IActionResult> Post(IFormFile file)
{
    var json = HttpContext.Request.Form["Candidates"];      
    var jsonTextReader = new JsonTextReader(new StringReader(json));
    var candidate = new JsonSerializer().Deserialize<Candidate>(jsonTextReader);

    if (!ModelState.IsValid) 
        return BadRequest();

    using (var memoryStream = new MemoryStream())
    {
        await file.OpenReadStream().CopyToAsync(memoryStream);
        candidate.CurriculumVitae = memoryStream.ToArray();
    }
    await dataBase.AddAsync(candidate);
    dataBase.SaveChanges();
    return Ok(candidate);
}

【问题讨论】:

    标签: c# angular asp.net-web-api asp.net-core


    【解决方案1】:

    Upload images in Angular 4 without a plugin 提供了您尝试实现的过程的演练。它使用@ViewChild 来获取对DOM 中文件输入的引用,然后在构建FormData 时使用它。在您的场景中,这涉及到一些更改,如下所示:

    1. 将 HTML 中文件输入的 ngModel 替换为 #file。这会创建一个template reference variable,在下一步使用@ViewChild 时可以在组件内部访问该template reference variable
    2. @ViewChild('file') fileInput; 添加到组件的构造函数上方。这会将#file 模板引用变量链接到您的组件代码。
    3. 从您的组件中删除以下代码:

      const { file } = form.value;
      delete form.value.file;
      

      file 属性此时将不再存在,因此无需删除任何内容。

    4. data.append('file', file); 替换为以下内容:

      let fileBrowser = this.fileInput.nativeElement;
      if (fileBrowser.files && fileBrowser.files[0]) {
          data.append("file", fileBrowser.files[0]);
      }
      

      最后一段代码获取文件的句柄并将其附加到您的FormData

    您可以随意命名变量和模板引用变量。唯一需要具体说明的是data.append 中使用的字符串值file 必须与用于C# IFormFile 变量的变量名称匹配。

    顺便说一句,您还可以删除您的自定义HeadersRequestOptions,因为将Access-Control-Allow-Origin 设置为请求标头在这里什么都不做。此标头应由服务器在响应中设置。

    【讨论】:

      【解决方案2】:

      我之前遇到过这个问题,通过删除得到了解决。 'Content-Type', 'application/json; charset=utf-8'

      而且您还需要确保在客户端和服务器端发送和接收相同的参数

      【讨论】:

        【解决方案3】:

        添加[FromBody] 属性。你可以在这里阅读更多:Binding formatted data from the request body

        public async Task&lt;IActionResult&gt; Post(IFormFile file) 更改为public async Task&lt;IActionResult&gt; Post([FromBody] IFormFile file)

        【讨论】:

        • 投了反对票。这会产生HTTP 415 响应。让它在没有任何属性的情况下工作。
        • 嗨@LukePuplett - 感谢您花时间解释您的失望?
        • 谢谢,我可能是错的,所以留下答案。您的回答对我来说很有意义,但在实践中没有用。另外,我认为 SO 应该强制解释否决票。我认为他们尝试过,人们只是进入了低质量的 cmets。总有一天会有一个高质量的 AI :)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-03
        • 1970-01-01
        • 2020-12-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多