.net - Varför förstår inte min C#-endpoint mina Angular Reactive-formulärdata?
Ursäkta - Angular och TypeScript är fortfarande relativt grekiska för mig. Kort sagt, när jag skickar mitt formulär till en C#/.NET 3.1-endpoint, blir alla nyckel-värde-par från mitt formulär hopslagna till en stor nyckel utan motsvarande värde.
Jag har satt ihop ett formulär i en Angular-komponent, som
export class DialogFileUpload {
uploadForm = this.fb.group({
isFoo:[''],
hasHeaders:['', [Validators.required]],
distributor:[''],
file:['']
});
date = new FormControl(moment());
distributors: IDistributor[] = [];
get aliases() {
return this.uploadForm.get('aliases') as FormArray;
}
constructor(
public dialogRef: MatDialogRef<DialogFileUpload>,
private fb: FormBuilder,
private distributorService: DistributorService,
private uploadService: UploadService) {}
ngOnInit() {
this.distributorService.getDistributors()
.subscribe(distributors => {
this.distributors = distributors;
})
...
Mitt motsvarande HTML ser ut som
<form [formGroup]="uploadForm" (ngSubmit)="onSubmit()">
<mat-form-field>
<input matInput formControlName="effectiveMonth" [matDatepicker]="picker" [min]="sixMonthsAgo" [max]="today" placeholder="Effective Month">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker
startView="multi-year"
(yearSelected) = "chosenYearHandler($event)"
(monthSelected)= "closeDatePicker($event, picker)">
</mat-datepicker>
</mat-form-field>
<mat-form-field appearance="fill" class="distributor-select">
<mat-label>Distributor</mat-label>
<mat-select formControlName="distributor">
<mat-option value="-1">--</mat-option>
<mat-option *ngFor="let distributor of distributors" [value]="distributor.id">
{{distributor.name}}
</mat-option>
</mat-select>
</mat-form-field>
<input type="file" formControlName="file" (change)="appendFile($event.target.files)">
<mat-radio-group
formControlName="isFoo">
<mat-radio-button value="true">foo</mat-radio-button>
<mat-radio-button value="false">Non-foo</mat-radio-button>
</mat-radio-group>
<mat-radio-group *ngIf="uploadForm.value.isFoo == 'false'"
formControlName="hasHeaders">
<mat-radio-button value="true">Has Headers</mat-radio-button>
<mat-radio-button value="false">Headerless</mat-radio-button>
</mat-radio-group>
<div mat-dialog-actions>
<button mat-button (click)="onNoClick()">Cancel</button>
<button mat-raised-button color="primary" cdkFocusInitial>Ok</button>
</div>
</form>
<br>{{uploadForm.value | json}}
För övrigt verkar uploadForm.value vara korrekt formaterad. När formuläret är ifyllt finns detta anrop:
onSubmit(): void {
console.log(this.uploadForm.value);
this.uploadService.postFileToServer(this.uploadForm.value)
.subscribe({
next: () =>{},
error: () => {},
complete: () =>{
this.dialogRef.close();
window.location.reload();
}
})
}
Vilket kallar detta:
postFileToServer(data: FormData) {
let url = this.baseUrl + this.fileUploadUrl;
return this.http.post(url, data, {headers : { "Content-Type" : "Application/x-www-form-urlencoded"}});
}
Borde detta vara application/x-www-form-urlencoded? Multipart/form-data? Jag får fel i min backend om jag använder det senare. Hur som helst, ser den motsvarande slutpunkten ut så här
[HttpPost]
[DisableRequestSizeLimit]
public IActionResult UploadEdiFile() {
var foo = Request.Form;
Console.WriteLine(foo["distributor"]);
bool isFoo = Request.Form["isFoo"] == "true" ? true : false;
Och det visar sig att 'isFoo' returnerar null. När jag tittar på request-objektet ser jag bara en nyckel och inget värde, det är som om det har kombinerat alla mina nyckelvärden till en enda massa.
{[{"isFoo":"true","hasHeaders":"true","distributor":"5","file":"","effectiveMonth":"2021-06-21T22:54:18.038Z"}, {}]}
uploadForm.value || json som visas i webbläsaren ser dock ut så här:
{ "isFoo": "true", "hasHeaders": "true", "distributor": "5", "file": "", "effectiveMonth": "2021-06-21T22:51:39.688Z" }
Var gjorde jag fel?
Svar #1
Enligt kommentarerna på frågan tror jag att detta är redo att köras - även om det känns mer som en tillfällig lösning än en ideal väg.
När en fil läggs till i formuläret, anropas följande:
appendFile(uploadFile: File) : void {
this.uploadForm.controls['file'].setValue(uploadFile, uploadFile ? uploadFile.name : '');
}
Den nya versionen av min onSubmit-metod ser dock ut så här:
onSubmit(): void {
const formData = new FormData();
formData.append('file', this.uploadForm.get('file').value[0]);
formData.append('isFoo', this.uploadForm.get('isFoo').value);
formData.append('hasHeasders', this.uploadForm.get('hasHeaders').value);
formData.append('effectiveMonth', this.uploadForm.get('effectiveMonth').value);
formData.append('distributor', this.uploadForm.get('distributor').value);
this.uploadService.postFileToServer(formData)
.subscribe({
next: () =>{},
error: () => {},
complete: () =>{
this.dialogRef.close();
window.location.reload();
}
})
}
Det skapar nu en ny instans av FormData och lägger till varje element från FormGroup, som sedan skickas. Postmetoden behöver inte längre någon form av speciell content-type-angivelse, och faktiskt gjorde varken urlencodedform eller multipart/form-data mig några tjänster.
