← Back to Articles         
How does Angular SSR work with ASP.NET Core Web API?

How does Angular SSR work with ASP.NET Core Web API?

Published on 02 Oct 2026     11 min read Angular
SSR, CSR, SSG

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 localStorage cannot 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.

← Back to Articles