Intro
When I had POST data from the Angular app to ASP.NET Core app, sometimes I failed even though there hadn't been any exceptions happened.Because I had wanted to know the reason, I tried something.
What I did
- Set data to Request Payload and POST
- Set data to Form Data and POST
- Get data from ASP.NET Core
Sample Codes
ASP.NET Core
ApiController.cs
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Files;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Models;
using UpgradeSample.Models;
using UpgradeSample.Products;
namespace UpgradeSample.Controllers
{
public class ApiController: Controller
{
private readonly IProductService _productService;
public ApiController(IProductService productService)
{
_productService = productService;
}
[HttpGet]
[Route("/products")]
public async Task<List<Product>> GetProducts()
{
return await _productService.GetProductsAsync();
}
[Route("/post-sample/form")]
public UploadResult GetFormSample([FromForm] int productId, string productName)
{
return new UploadResult
{
Succeeded = (string.IsNullOrEmpty(productName) == false),
ErrorMessage = $"ID: {productId} NAME: {productName}"
};
}
[Route("/post-sample/form-class")]
public UploadResult GetFormClassSample([FromForm] Product product)
{
return new UploadResult
{
Succeeded = (product != null),
ErrorMessage = $"ID: {product?.ProductId} NAME: {product?.ProductName}"
};
}
[Route("/post-sample/body-class")]
public UploadResult GetBodyClassSample([FromBody] Product product)
{
return new UploadResult
{
Succeeded = (product != null),
ErrorMessage = $"ID: {product?.ProductId} NAME: {product?.ProductName}"
};
}
}
}
Product.cs
using System.ComponentModel.DataAnnotations.Schema;
namespace UpgradeSample.Models
{
[Table("Product")]
public class Product
{
[Column("ProductId")]
public int? ProductId { get; set; }
[Column("ProductName")]
public string ProductName { get; set; }
}
}
UploadResult
namespace Files
{
public class UploadResult
{
public bool Succeeded { get; set; }
public string ErrorMessage { get; set; }
}
}
Angular
post-sample.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { UploadResult } from '../file-upload/upload-result';
import { Product } from '../models/product';
@Injectable({
providedIn: 'root'
})
export class PostSampleService {
constructor(private httpClient: HttpClient) { }
public sendRequestPayloadClass(): Observable<UploadResult> {
// POST grouped data as Request Payload
}
public sendForm(): Observable<UploadResult> {
// POST separated data as FormData
}
public sendFormClass(): Observable<UploadResult> {
// POST grouped data as FormData
}
public getProducts(): Observable<Array<Product>> {
// GET data
}
}
post-sample.component.html
<button (click)="sendRequestPayloadClass()">RequestPayloadClass</button>
<button (click)="sendForm()">Form</button>
<button (click)="sendFormClass()">FormClass</button>
<button (click)="get()">Get</button>
post-sample.component.ts
import { Component, OnInit } from '@angular/core';
import { PostSampleService } from './post-sample.service';
@Component({
selector: 'app-post-sample',
templateUrl: './post-sample.component.html',
styleUrls: ['./post-sample.component.css']
})
export class PostSampleComponent implements OnInit {
constructor(private postSampleService: PostSampleService) { }
ngOnInit() {
}
public sendRequestPayloadClass() {
this.postSampleService.sendRequestPayloadClass()
.subscribe(result => {
console.log(result);
});
}
public sendForm() {
this.postSampleService.sendForm()
.subscribe(result => {
console.log(result);
});
}
public sendFormClass() {
this.postSampleService.sendFormClass()
.subscribe(result => {
console.log(result);
});
}
public get() {
this.postSampleService.getProducts()
.subscribe(products => {
console.log(products);
});
}
}
upload-result.ts
export interface UploadResult {
succeeded: boolean;
errorMessage: string;
}
Set data to Request Payload and POST
POST grouped data
Because I only could set single data as Request Payload, I just tried POST grouped data.post-sample.service.ts
...
export class PostSampleService {
...
public sendRequestPayload(): Observable<UploadResult> {
// POST separated data as Request Payload
const product = {
productId: 6,
productName: 'World'
};
return this.httpClient.post<UploadResult>(
`http://localhost:5000/post-sample/body-class`,
product, {
headers: {
'Content-Type': 'application/json'
}
}
);
}
...
}
I could receive data as Product class.So I got the result like below.
{"succeeded":true,"errorMessage":"ID: 6 NAME: World"}
Send data that had partial properties
If the data hadn't had all of the properties of Product class, the ASP.NET Core app could receive as Product class.post-sample.service.ts
...
export class PostSampleService {
...
public sendRequestPayload(): Observable<UploadResult> {
// POST separated data as Request Payload
const product = {
productId: 6,
};
return this.httpClient.post<UploadResult>(
`http://localhost:5000/post-sample/body-class`,
product, {
headers: {
'Content-Type': 'application/json'
}
}
);
}
...
}
result
{"succeeded":true,"errorMessage":"ID: 6 NAME: "}
Send data that had other properties
Even though the data had other properties, the ASP.NET Core app still could receive as Product class.post-sample.service.ts
...
export class PostSampleService {
...
public sendRequestPayload(): Observable<UploadResult> {
// POST separated data as Request Payload
const product = {
productId: 6,
product: 'Hello world'
};
return this.httpClient.post<UploadResult>(
`http://localhost:5000/post-sample/body-class`,
product, {
headers: {
'Content-Type': 'application/json'
}
}
);
}
...
}
result
{"succeeded":true,"errorMessage":"ID: 6 NAME: "}
Send data that had the property that had same name & different data type
How about this?post-sample.service.ts
...
export class PostSampleService {
...
public sendRequestPayload(): Observable<UploadResult> {
// POST separated data as Request Payload
const product = {
productId: '6',
productName: 'Hello world'
};
return this.httpClient.post<UploadResult>(
`http://localhost:5000/post-sample/body-class`,
product, {
headers: {
'Content-Type': 'application/json'
}
}
);
}
...
}
The result was the ASP.NET Core app hadn't been able to receive.Because TypeScriptcould mix the data what had different data types, sometimes the problems occurred.
Did I have to add "Content-Type" to headers?
No. Because when I had sent, "Content-Type" was added by default.Did I have to create class(or interface) to send data?
- Angular: No
- ASP.NET Core: Yes
Set data to Form Data and POST
POST separated data
I could send separated data by FormData.post-sample.service.ts
...
export class PostSampleService {
...
public sendForm(): Observable<UploadResult> {
const formData = new FormData();
const id = 3;
formData.append('productId', id.toString(10));
formData.append('productName', 'Hello world');
return this.httpClient.post<UploadResult>(
`http://localhost:5000/post-sample/form`,
formData, { }
);
}
...
}
Send data that had partial properties
There were no problems happened.The properties what I hadn't send had default values.
Send data that had the property that had same name & different data type
No problem.If the data had been able to convert(ex. Angular sent '3'), ASP.NET Core app could get values.
If the converting failed, the properties had default values.
Add 'Content-Type': 'application/json' to headers?
I failed sending.Because for sending FormData, the content type was "multipart/form-data" by default.
I also couldn't send data when I had set "application/x-www-form-urlencoded" to the content type.
I thought the controller method of ASP.NET Core also needed change to get.
POST grouped data
I couldn't send grouped data.post-sample.service.ts
...
export class PostSampleService {
...
public sendFormClass(): Observable<UploadResult> {
const product = {
productId: 4,
productName: 'Hello world'
};
const formData = new FormData();
formData.append('product', JSON.stringify(product));
return this.httpClient.post<UploadResult>(
`http://localhost:5000/post-sample/form-class`,
formData, { }
);
}
...
}
Even though the argument hadn't been null, "ProductId" & "ProductName" was null.I didn't know there had been any way to send grouped data with FormData.
But now, I had used RequestPayload to send grouped data.
Get data
How about the getting data from ASP.NET Core?Were there same problems as sending data?
post-sample.service.ts
...
export class PostSampleService {
...
public getProducts(): Observable<Array<Product>> {
return this.httpClient.get<Array<Product>>(
`http://localhost:5000/products`);
}
...
}
The answer was no.Even though I had put any types in get<T>, the return value type was as same as sent from server.
So even if I changed like below...
post-sample.service.ts
...
export class PostSampleService {
...
public getProducts(): Observable<any> {
return this.httpClient.get<boolean>(
`http://localhost:5000/products`);
}
...
}
The result was like this.(2) [{…}, {…}] 0: productId: 1 ProductName: "Nykee Running Shoes" __proto__: Object 1: productId: 2 ProductName: "South Face Jacket" __proto__: Object length: 2 __proto__: Array(0)
Resources
Angular - HttpClientAngular - HttpClient
Model Binding in ASP.NET Core | Microsoft Docs
Custom Model Binding in ASP.NET Core | Microsoft Docs
コメント
コメントを投稿