I have one front-end in angular 4, and one back-end in ASP.NET Core WebAPI, the functionality of them is, send data and an curriculum vitae of one people to one database which is SQL Server, but... always the IFormFile of method who catch the data and send file to the database is null.
I've already tried all type of solution that I found on the internet but none of them worked for me.
as response of the Post method i receive this exception
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
Down here I pasted parts of the code of the project who do this.
github link for complete code:
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);
}
Upload images in Angular 4 without a plugin provides a walkthrough of the process you're attempting to achieve. It uses @ViewChild
to grab a reference to the file input in the DOM and then uses that when building up the FormData
. In your scenario, this involves a few changes, as follows:
ngModel
on the file input in your HTML with #file
. This creates a template reference variable that can be accessed inside your component when using @ViewChild
in the next step.@ViewChild('file') fileInput;
to the component, above your constructor. This links the #file
template reference variable to your component code.Remove the following code from your component:
const { file } = form.value;
delete form.value.file;
The file
property will no longer exist at this point, so there's nothing to delete.
Replace data.append('file', file);
with the following:
let fileBrowser = this.fileInput.nativeElement;
if (fileBrowser.files && fileBrowser.files[0]) {
data.append("file", fileBrowser.files[0]);
}
This last block of code grabs a handle on the file and appends it to your FormData
.
You can name the variables and template reference variable whatever you want. The only thing that needs to be specific is the string value file
used in data.append
must match the variable name used for your C# IFormFile
variable.
As an aside, you can also remove your custom Headers
and RequestOptions
as setting Access-Control-Allow-Origin
as a request header is doing nothing here. This header should be set on the response, by the server.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With