Sending JSON from Angular to ASP.NET Core and Deserializing into a DTO
These two questions describe the two sides of the same HTTP request:
Angular
↓
TypeScript object
↓
HttpClient.post()
↓
JSON request body
↓
ASP.NET Core Web API
↓
Model Binding + JSON Deserialization
↓
C# DTO
Full Simple Sample Program
We will send this product from Angular:
{
"name": "Laptop",
"price": 75000
}
ASP.NET Core will receive it as:
CreateProductDto
Angular — product.ts
export interface CreateProduct {
name: string;
price: number;
}
Angular — product.service.ts
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { CreateProduct } from './product';
@Injectable({
providedIn: 'root'
})
export class ProductService {
private http = inject(HttpClient);
private apiUrl =
'https://localhost:7001/api/products';
addProduct(
product: CreateProduct
): Observable<CreateProduct> {
return this.http.post<CreateProduct>(
this.apiUrl,
product
);
}
}
Angular — Component
import { Component, inject } from '@angular/core';
import { ProductService } from './product.service';
import { CreateProduct } from './product';
@Component({
selector: 'app-products',
standalone: true,
template: `
<button (click)="addProduct()">
Add Product
</button>
`
})
export class Products {
private productService = inject(ProductService);
addProduct(): void {
const product: CreateProduct = {
name: 'Laptop',
price: 75000
};
this.productService
.addProduct(product)
.subscribe({
next: (response) => {
console.log(response);
},
error: (error) => {
console.error(error);
}
});
}
}
ASP.NET Core Web API
CreateProductDto.cs
namespace ProductApi.DTOs;
public class CreateProductDto
{
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
}
ProductsController.cs
using Microsoft.AspNetCore.Mvc;
using ProductApi.DTOs;
namespace ProductApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpPost]
public IActionResult CreateProduct(
[FromBody] CreateProductDto product)
{
Console.WriteLine(product.Name);
Console.WriteLine(product.Price);
return Ok(product);
}
}
1. How Do You Send JSON Data from Angular to ASP.NET Core?
Suppose Angular has this TypeScript object:
const product: CreateProduct = {
name: 'Laptop',
price: 75000
};
We send it using:
this.http.post<CreateProduct>(
this.apiUrl,
product
);
The important part is:
http.post(url, body)
Here:
this.apiUrl
↓
Where to send
product
↓
Request body
Angular's HttpClient handles the normal JSON serialization of the object.
Conceptually:
TypeScript Object
{
name: 'Laptop',
price: 75000
}
↓
HttpClient
↓
JSON serialization
↓
{
"name": "Laptop",
"price": 75000
}
HTTP Request
Conceptually, Angular sends:
POST /api/products
Content-Type: application/json
{
"name": "Laptop",
"price": 75000
}
The header:
Content-Type: application/json
tells the server:
The request body contains JSON data.
For normal object bodies, Angular HttpClient handles the JSON content type/serialization appropriately, so you generally don't need to manually call JSON.stringify().
Normally do this:
this.http.post(
this.apiUrl,
product
);
rather than manually doing:
this.http.post(
this.apiUrl,
JSON.stringify(product)
);
2. How Does ASP.NET Core Deserialize Angular JSON into a DTO?
Now consider the ASP.NET Core action:
[HttpPost]
public IActionResult CreateProduct(
[FromBody] CreateProductDto product)
{
return Ok(product);
}
Angular sends:
{
"name": "Laptop",
"price": 75000
}
ASP.NET Core sees:
[FromBody] CreateProductDto product
and creates a C# object:
CreateProductDto
Name = "Laptop"
Price = 75000
This process involves model binding and input formatting/JSON deserialization.
What Does [FromBody] Mean?
[FromBody]
tells ASP.NET Core:
Get the value for this parameter from the HTTP request body.
For example:
[FromBody] CreateProductDto product
Request:
POST /api/products
{
"name": "Laptop",
"price": 75000
}
becomes:
product.Name
with:
Laptop
and:
product.Price
with:
75000
Complete Deserialization Flow
Angular
│
│ TypeScript Object
↓
{
name: 'Laptop',
price: 75000
}
↓
HttpClient.post()
↓
HTTP Request
↓
Content-Type: application/json
↓
{
"name": "Laptop",
"price": 75000
}
↓
ASP.NET Core
↓
JSON input formatter
(System.Text.Json by default)
↓
Model Binding
↓
CreateProductDto
↓
Name = "Laptop"
Price = 75000
↓
Controller Action
How Does Property Matching Work?
Angular sends:
{
"name": "Laptop",
"price": 75000
}
C# has:
public class CreateProductDto
{
public string Name { get; set; }
public decimal Price { get; set; }
}
Notice:
JSON C#
name → Name
price → Price
ASP.NET Core's default web JSON configuration handles this common camelCase/PascalCase difference.
Therefore:
"name"
can populate:
Name
and:
"price"
can populate:
Price
What Performs the JSON Deserialization?
ASP.NET Core uses:
System.Text.Json
by default for JSON serialization/deserialization.
Conceptually:
JSON
↓
System.Text.Json
↓
C# object
For example:
{
"name": "Laptop",
"price": 75000
}
becomes:
new CreateProductDto
{
Name = "Laptop",
Price = 75000
};
You normally do not manually write this conversion. ASP.NET Core performs it as part of request processing.
Do We Always Need [FromBody]?
With an API controller:
[ApiController]
public class ProductsController : ControllerBase
ASP.NET Core can infer that a complex type such as:
CreateProductDto
should come from the request body.
Therefore this commonly works:
[HttpPost]
public IActionResult CreateProduct(
CreateProductDto product)
{
return Ok(product);
}
as well as the explicit version:
[HttpPost]
public IActionResult CreateProduct(
[FromBody] CreateProductDto product)
{
return Ok(product);
}
For learning and interviews, the explicit version makes the source very clear:
[FromBody] CreateProductDto product
POST Example
Angular:
const product = {
name: 'Laptop',
price: 75000
};
return this.http.post(
'https://localhost:7001/api/products',
product
);
ASP.NET Core:
[HttpPost]
public IActionResult Create(
[FromBody] CreateProductDto product)
{
return Ok(product);
}
Flow:
Angular Object
↓
POST
↓
JSON
↓
Request Body
↓
[FromBody]
↓
CreateProductDto
PUT Works the Same Way
JSON request bodies are not limited to POST.
Angular:
updateProduct(
id: number,
product: CreateProduct
): Observable<void> {
return this.http.put<void>(
`${this.apiUrl}/${id}`,
product
);
}
ASP.NET Core:
[HttpPut("{id}")]
public IActionResult UpdateProduct(
int id,
[FromBody] CreateProductDto product)
{
Console.WriteLine(id);
Console.WriteLine(product.Name);
Console.WriteLine(product.Price);
return NoContent();
}
Request:
PUT /api/products/10
Content-Type: application/json
{
"name": "Gaming Laptop",
"price": 95000
}
ASP.NET Core receives:
id = 10
product.Name
= "Gaming Laptop"
product.Price
= 95000
[FromBody] vs [FromQuery] vs [FromRoute] vs [FromHeader]
This is important for ASP.NET Core interviews.
| Attribute | Reads From | Example |
|---|---|---|
[FromBody] |
Request body | JSON DTO |
[FromQuery] |
Query string | ?page=1 |
[FromRoute] |
URL route | /products/10 |
[FromHeader] |
HTTP header | X-Api-Key |
For example:
[HttpPut("{id}")]
public IActionResult Update(
[FromRoute] int id,
[FromQuery] bool notify,
[FromHeader(Name = "X-Api-Key")] string apiKey,
[FromBody] CreateProductDto product)
{
return NoContent();
}
Angular might send:
PUT /api/products/10?notify=true
X-Api-Key: 123456
{
"name": "Laptop",
"price": 75000
}
Mapping:
URL /10
↓
[FromRoute]
↓
id = 10
?notify=true
↓
[FromQuery]
↓
notify = true
X-Api-Key: 123456
↓
[FromHeader]
↓
apiKey = "123456"
JSON Body
↓
[FromBody]
↓
CreateProductDto
DTO Validation
A DTO can also contain validation rules.
For example:
using System.ComponentModel.DataAnnotations;
public class CreateProductDto
{
[Required]
public string Name { get; set; } = string.Empty;
[Range(1, 1000000)]
public decimal Price { get; set; }
}
If Angular sends invalid data:
{
"name": "",
"price": -100
}
with [ApiController], ASP.NET Core can automatically return a validation error response when model validation fails.
So the broader flow becomes:
Angular JSON
↓
ASP.NET Core
↓
JSON Deserialization
↓
DTO
↓
Validation
↓
Controller
If validation fails:
JSON
↓
DTO binding/validation
↓
Invalid
↓
400 Bad Request
Request DTO vs Entity
In a real application, Angular should normally send an API contract/DTO, rather than designing the client around your EF Core entity.
For example:
Angular
CreateProduct
↓
JSON
↓
ASP.NET Core
CreateProductDto
↓
Application / Business Logic
↓
Product Entity
↓
EF Core
↓
SQL Server
This keeps the API contract separated from persistence concerns.
Important Distinction: Serialization vs Deserialization
These two terms are commonly asked in interviews.
Serialization
Object → JSON
Angular side:
TypeScript Object
↓
JSON
Example:
{
name: 'Laptop',
price: 75000
}
becomes JSON over HTTP:
{
"name": "Laptop",
"price": 75000
}
Deserialization
JSON → Object
ASP.NET Core side:
JSON
↓
C# DTO
Example:
{
"name": "Laptop",
"price": 75000
}
becomes:
CreateProductDto
with:
Name = Laptop
Price = 75000
Easy way to remember:
Serialization
Object → JSON
Deserialization
JSON → Object
Complete End-to-End Flow
ANGULAR
──────────────────────────────
CreateProduct object
{
name: 'Laptop',
price: 75000
}
↓
HttpClient.post(url, product)
↓
JSON Serialization
↓
HTTP POST
Content-Type: application/json
↓
{
"name": "Laptop",
"price": 75000
}
ASP.NET CORE
──────────────────────────────
HTTP Request
↓
Routing
↓
ProductsController
↓
[FromBody]
↓
JSON Input Formatter
System.Text.Json
↓
JSON Deserialization
↓
CreateProductDto
↓
Name = "Laptop"
Price = 75000
↓
Controller / Application Layer
↓
EF Core
↓
SQL Server
Key Points
- Angular
HttpClientcan send TypeScript objects as JSON request bodies. - POST syntax:
this.http.post(url, object);
- PUT syntax:
this.http.put(url, object);
- You normally don't need to manually call
JSON.stringify()when passing an object toHttpClient. - JSON requests normally use:
Content-Type: application/json
- ASP.NET Core reads JSON request bodies into DTOs using model binding and JSON input formatting.
[FromBody]explicitly indicates that the parameter comes from the request body.System.Text.Jsonis the default JSON serializer in modern ASP.NET Core.[ApiController]can infer body binding for complex types.- camelCase JSON such as
namecommonly maps to PascalCase C# properties such asName. - DTO validation can happen after/beside binding before the controller action executes.
- Prefer API DTOs/contracts rather than exposing EF Core entities directly.
Interview Questions and Answers
1. How do you send JSON data from Angular to ASP.NET Core?
Pass a TypeScript object as the request body to HttpClient.post() or put():
this.http.post(
'/api/products',
product
);
Angular HttpClient handles the normal JSON serialization.
2. How does ASP.NET Core deserialize Angular JSON into a DTO?
ASP.NET Core reads the JSON request body through its model-binding/input-formatting pipeline and uses System.Text.Json by default to deserialize it into the specified C# DTO.
public IActionResult Create(
[FromBody] CreateProductDto product)
3. What does [FromBody] mean?
It tells ASP.NET Core to obtain the parameter value from the HTTP request body.
[FromBody] CreateProductDto product
4. Is [FromBody] mandatory with [ApiController]?
Not always. [ApiController] can infer body binding for complex types, but [FromBody] can be used explicitly for clarity.
5. Which JSON serializer does ASP.NET Core use by default?
Modern ASP.NET Core uses:
System.Text.Json
by default.
6. Do we need JSON.stringify() before calling HttpClient.post()?
Normally, no.
Pass the object directly:
this.http.post(url, product);
7. What is serialization?
Serialization converts an object into a transport representation such as JSON:
Object → JSON
8. What is deserialization?
Deserialization converts JSON into an application object:
JSON → C# DTO
9. How does Angular's name map to C# Name?
ASP.NET Core's default web JSON configuration supports the conventional JSON naming behavior and case-insensitive property matching, allowing common camelCase JSON properties to bind to PascalCase C# properties.
10. Should the Angular application send EF Core entities directly?
Typically, use API request/response DTOs as the contract:
Angular Model
↓
JSON
↓
Request DTO
↓
Business/Application Layer
↓
Domain/Entity
↓
Database
Short Interview Answer
Angular sends JSON by passing a TypeScript object to
HttpClient.post()orHttpClient.put(). ASP.NET Core reads the JSON request body and, using its model-binding/input-formatting pipeline withSystem.Text.Jsonby default, deserializes the JSON into a C# DTO, commonly represented explicitly with[FromBody].