How Does Angular SSR Work with ASP.NET Core Web API?
In an Angular SSR + ASP.NET Core Web API architecture:
- Angular SSR server renders the initial HTML.
- ASP.NET Core Web API provides backend data/business logic.
- SQL Server stores the data.
- After the initial HTML reaches the browser, Angular hydrates the page and becomes interactive.
The key architecture is:
Browser
↓
Angular SSR Server
↓
ASP.NET Core Web API
↓
SQL Server
1. Full Simple Sample Program
Let's build a simple Products page.
The goal:
User requests /products
↓
Angular SSR renders Products page
↓
Angular SSR calls ASP.NET Core API
↓
API returns products
↓
Angular SSR generates HTML
↓
Browser receives HTML
↓
Angular hydrates page
ASP.NET Core Web API
Product.cs
namespace ProductApi.Models;
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
}
ProductsController.cs
using Microsoft.AspNetCore.Mvc;
using ProductApi.Models;
namespace ProductApi.Controllers;
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet]
public ActionResult<List<Product>> Get()
{
var products = new List<Product>
{
new()
{
Id = 1,
Name = "Laptop",
Price = 50000
},
new()
{
Id = 2,
Name = "Mouse",
Price = 1000
},
new()
{
Id = 3,
Name = "Keyboard",
Price = 2000
}
};
return Ok(products);
}
}
Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
builder.Services.AddCors(options =>
{
options.AddPolicy("Angular", policy =>
{
policy
.WithOrigins("http://localhost:4200")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
var app = builder.Build();
app.UseHttpsRedirection();
app.UseCors("Angular");
app.MapControllers();
app.Run();
Assume the API runs at:
https://localhost:7001
and:
GET https://localhost:7001/api/products
returns:
[
{
"id": 1,
"name": "Laptop",
"price": 50000
},
{
"id": 2,
"name": "Mouse",
"price": 1000
},
{
"id": 3,
"name": "Keyboard",
"price": 2000
}
]
Angular SSR Application
Create Angular with SSR enabled, or add SSR to an existing application:
ng add @angular/ssr
product.ts
export interface Product {
id: number;
name: string;
price: number;
}
product-service.ts
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Product } from './product';
@Injectable({
providedIn: 'root'
})
export class ProductService {
private http = inject(HttpClient);
private apiUrl =
'https://localhost:7001/api/products';
getProducts(): Observable<Product[]> {
return this.http.get<Product[]>(
this.apiUrl
);
}
}
products.ts
import { Component, inject } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { ProductService } from './product-service';
@Component({
selector: 'app-products',
standalone: true,
imports: [AsyncPipe],
templateUrl: './products.html'
})
export class Products {
private productService =
inject(ProductService);
products$ =
this.productService.getProducts();
}
products.html
<h1>Products</h1>
@if (products$ | async; as products) {
@for (product of products; track product.id) {
<div>
<h2>{{ product.name }}</h2>
<p>
Price: {{ product.price }}
</p>
</div>
}
}
app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: 'products',
loadComponent: () =>
import('./products')
.then(m => m.Products)
}
];
app.routes.server.ts
Configure /products to use SSR:
import {
RenderMode,
ServerRoute
} from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{
path: 'products',
renderMode: RenderMode.Server
},
{
path: '**',
renderMode: RenderMode.Client
}
];
Here:
RenderMode.Server
means:
Render this route on the server when it is requested.
app.config.ts
import {
ApplicationConfig
} from '@angular/core';
import {
provideHttpClient,
withFetch
} from '@angular/common/http';
import {
provideClientHydration
} from '@angular/platform-browser';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(
withFetch()
),
provideClientHydration()
]
};
2. How Does the Complete Flow Work?
Suppose the user enters:
https://www.jntech.in/products
The important thing is that there are two Angular execution environments:
Angular on Server
+
Angular in Browser
Let's follow the request.
Step 1 — Browser Requests /products
Browser
│
│ GET /products
▼
Angular SSR Server
Unlike pure CSR, the browser isn't simply given an empty Angular shell and told to do all initial rendering itself.
Step 2 — Angular Runs on the Server
Because the route is configured as:
{
path: 'products',
renderMode: RenderMode.Server
}
Angular executes the Products component on the server.
The component contains:
products$ =
this.productService.getProducts();
Therefore the service executes.
Step 3 — Angular SSR Calls ASP.NET Core
The service executes:
this.http.get<Product[]>(
'https://localhost:7001/api/products'
);
The architecture is now:
Browser
│
▼
Angular SSR Server
│
│ GET /api/products
▼
ASP.NET Core Web API
This is an important point:
During SSR, the API request needed for initial rendering can originate from the Angular server environment, not from the user's browser.
Step 4 — ASP.NET Core Gets the Data
In a real application:
ProductsController
↓
Application Service
↓
Repository / EF Core
↓
SQL Server
For example:
[HttpGet]
public async Task<IActionResult> Get()
{
var products =
await _productService.GetProductsAsync();
return Ok(products);
}
ASP.NET Core returns JSON:
[
{
"id": 1,
"name": "Laptop",
"price": 50000
}
]
Step 5 — Angular SSR Receives JSON
The response returns to Angular:
ASP.NET Core
│
│ JSON
▼
Angular SSR Server
Angular now has:
[
{
id: 1,
name: 'Laptop',
price: 50000
}
]
Step 6 — Angular Generates HTML on the Server
Angular processes:
@for (product of products; track product.id) {
<h2>{{ product.name }}</h2>
<p>
Price: {{ product.price }}
</p>
}
The server generates HTML conceptually like:
<h1>Products</h1>
<div>
<h2>Laptop</h2>
<p>Price: 50000</p>
</div>
<div>
<h2>Mouse</h2>
<p>Price: 1000</p>
</div>
<div>
<h2>Keyboard</h2>
<p>Price: 2000</p>
</div>
Step 7 — HTML Is Sent to Browser
Angular SSR Server
│
│ Rendered HTML
▼
Browser
Now the user can see:
Products
Laptop
Price: 50000
Mouse
Price: 1000
Keyboard
Price: 2000
without waiting for the browser to perform the entire initial Angular rendering process.
Step 8 — Angular JavaScript Loads
SSR doesn't mean Angular only runs on the server.
The browser also downloads Angular's JavaScript.
Rendered HTML
↓
Browser displays page
↓
Angular JS loads
↓
Angular starts
Step 9 — Hydration Happens
Angular recognizes that the HTML already exists.
Instead of unnecessarily rebuilding everything:
Existing server HTML
↓
Angular client starts
↓
Hydration
↓
Reuse existing DOM
↓
Attach Angular behavior
Now the application becomes fully interactive.
3. Complete Architecture
For a real Angular + ASP.NET Core application:
USER
│
│ GET /articles
▼
┌───────────────┐
│ Angular SSR │
│ Server │
└───────┬───────┘
│
│ HTTP API
▼
┌───────────────┐
│ ASP.NET Core │
│ Web API │
└───────┬───────┘
│
▼
┌───────────────┐
│ Application │
│ Layer │
└───────┬───────┘
│
▼
┌───────────────┐
│ EF Core │
└───────┬───────┘
│
▼
┌───────────────┐
│ SQL Server │
└───────────────┘
Angular SSR receives JSON
│
▼
Generate HTML
│
▼
Browser
│
▼
Hydration
│
▼
Interactive Angular Application
4. What Happens After Hydration?
This is very important.
Suppose the user is already viewing /products and clicks:
Load More
Angular can now make an API request directly from the browser:
Browser Angular
│
│ GET /api/products?page=2
▼
ASP.NET Core Web API
│
▼
SQL Server
│
▼
JSON
│
▼
Browser Angular
│
▼
Update UI
Therefore, the same Angular application can have two kinds of API calls.
During initial SSR
Angular SSR Server
↓
ASP.NET Core API
After hydration
Browser Angular
↓
ASP.NET Core API
This distinction is critical when designing authentication, URLs, cookies, CORS, and networking.
5. CSR vs SSR with ASP.NET Core
CSR
Browser
│
│ Load Angular
▼
Angular
│
│ API call
▼
ASP.NET Core
│
▼
SQL Server
│
▼
JSON
│
▼
Angular
│
▼
Render UI
The browser calls ASP.NET Core for the initial application data.
SSR
Browser
│
│ Request page
▼
Angular SSR
│
│ API call
▼
ASP.NET Core
│
▼
SQL Server
│
▼
JSON
│
▼
Angular SSR
│
│ Render HTML
▼
Browser
│
▼
Hydration
The Angular SSR environment can call ASP.NET Core before sending the initial page.
6. Important: CORS
There's an important difference here.
Server-to-server request
During SSR:
Angular SSR Server
↓
ASP.NET Core API
CORS is fundamentally a browser security mechanism, so a server-to-server HTTP call itself isn't blocked by browser CORS policy.
Browser request
After hydration:
Browser
↓
ASP.NET Core API
If Angular and ASP.NET Core are on different origins, browser CORS rules apply.
For example:
Angular
https://www.jntech.in
API
https://api.jntech.in
ASP.NET Core may need:
builder.Services.AddCors(options =>
{
options.AddPolicy("Angular", policy =>
{
policy
.WithOrigins("https://www.jntech.in")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
7. Important: Authentication
Authentication needs special consideration with SSR.
Suppose your Angular application uses:
JWT
In pure CSR:
Browser
│
│ JWT
▼
ASP.NET Core API
But during SSR:
Browser request
↓
Angular SSR Server
↓
ASP.NET Core API
If the page requires authenticated data, the SSR environment needs an appropriate secure mechanism to propagate the user's authentication context to the API.
This is one reason private admin areas are often kept CSR unless server rendering provides a concrete benefit.
8. Browser APIs Need Care
With CSR, code runs in the browser, so APIs such as these exist:
window
document
localStorage
sessionStorage
navigator
During SSR, the initial Angular code runs in a server environment.
Therefore code like:
const token =
localStorage.getItem('token');
cannot simply be assumed to work during server rendering.
Why?
Server
↓
No browser
↓
No browser localStorage
SSR-compatible Angular code must account for whether execution is happening on the server or in the browser.
9. Where Does ASP.NET Core Fit?
A common misunderstanding is:
"If Angular uses SSR, does ASP.NET Core also render Angular?"
Not necessarily.
In this architecture they have different responsibilities.
Angular SSR
Responsible for:
Angular components
Templates
Initial HTML rendering
Hydration support
ASP.NET Core Web API
Responsible for:
Business logic
Authentication
Authorization
Validation
Data access
Database operations
API endpoints
SQL Server
Responsible for:
Persistent application data
So:
Angular SSR
≠
ASP.NET Core SSR
Angular has its own server-side rendering runtime, while ASP.NET Core remains your backend API.
10. Example for Your Portfolio Architecture
For a portfolio architecture such as:
Angular
↓
ASP.NET Core Web API
↓
SQL Server
you might have:
Public
│
├── Home
├── Portfolio
├── Articles
└── Article Details
Admin
│
├── Login
├── Dashboard
├── Categories
├── Tags
└── Articles CRUD
A hybrid strategy could be:
Home → SSG
Portfolio → SSG/SSR
Articles → SSR
Article Details → SSR
Admin Login → CSR
Dashboard → CSR
Categories → CSR
Tags → CSR
Articles CRUD → CSR
For an article request:
User
↓
/articles/angular-ssr
↓
Angular SSR
↓
GET /api/articles/angular-ssr
↓
ASP.NET Core Web API
↓
SQL Server
↓
Article DTO
↓
Angular SSR
↓
Rendered Article HTML
↓
Browser
↓
Hydration
This architecture gives the public article page server-rendered initial HTML while keeping the ASP.NET Core API as the backend source of truth.
11. Key Points
- Angular SSR renders the initial HTML on the server.
- ASP.NET Core Web API remains the backend API.
- Angular SSR can call ASP.NET Core to retrieve initial data.
- ASP.NET Core can use EF Core to retrieve data from SQL Server.
- ASP.NET Core returns JSON/DTOs to Angular.
- Angular SSR converts that data into HTML.
- The browser receives the rendered HTML.
- Angular then performs hydration.
- After hydration, Angular behaves like an interactive client application.
- Subsequent API calls may originate directly from the browser.
- CORS matters for browser cross-origin requests, not ordinary server-to-server calls.
- Authentication needs careful design when SSR must render user-specific protected data.
- Browser-only APIs such as
localStoragecannot be assumed to exist during server rendering.
12. Interview Questions and Answers
1. How does Angular SSR work with ASP.NET Core Web API?
Answer:
Angular SSR executes the Angular application on the server, calls the ASP.NET Core Web API for required data, generates HTML using that data, and sends the rendered HTML to the browser. Angular then hydrates the page.
2. Does ASP.NET Core render the Angular SSR page?
Answer:
Not necessarily. Angular's SSR runtime performs the Angular rendering, while ASP.NET Core Web API typically provides business logic, authentication/authorization, and data access.
3. Does Angular SSR directly access SQL Server?
Answer:
Normally, no.
Use:
Angular SSR
↓
ASP.NET Core Web API
↓
EF Core
↓
SQL Server
This keeps business logic and database access in the backend.
4. Who calls the API during SSR?
Answer:
For data required during initial server rendering, the Angular SSR server can call the ASP.NET Core Web API.
Angular SSR → ASP.NET Core API
5. Who calls the API after hydration?
Answer:
Angular running in the browser can call the ASP.NET Core Web API directly.
Browser Angular → ASP.NET Core API
6. Is CORS required between Angular SSR and ASP.NET Core?
Answer:
Browser CORS restrictions don't apply to ordinary server-to-server calls. However, after hydration, browser requests to an API on another origin are subject to CORS.
7. Can I use localStorage during Angular SSR?
Answer:
Not directly during server execution because localStorage is a browser API. SSR code must account for the server/browser execution environment.
8. Does SSR replace the ASP.NET Core Web API?
Answer:
No. They have different responsibilities:
Angular SSR
→ Initial UI rendering
ASP.NET Core Web API
→ Backend/business/data services
9. What happens after Angular SSR sends HTML to the browser?
Answer:
Angular JavaScript loads in the browser and performs hydration, reusing the server-rendered DOM and making the application interactive.
Interview Quick Answer
With Angular SSR and ASP.NET Core Web API, Angular runs on the server for the initial request, calls the ASP.NET Core API to obtain data, generates HTML, and sends it to the browser. Angular then hydrates the server-rendered page, and subsequent interactions/API calls can run from the browser.