ASP.NET Core  

Full-Stack CRUD Application with Angular + ASP.NET Core + EF Core

Introduction

Building a full-stack application may feel challenging for beginners, especially when you need to connect different technologies such as Angular, ASP.NET Core, and SQL Server. However, once you understand the flow and how each layer communicates, full-stack development becomes simple and enjoyable.

In this guide, you will learn how to build a complete CRUD (Create, Read, Update, Delete) application using:

  • Angular for the frontend

  • ASP.NET Core Web API for the backend

  • Entity Framework Core (EF Core) for database access

  • SQL Server for data storage

By the end of this article, you will have a fully functional full-stack project where Angular communicates with ASP.NET Core, and ASP.NET Core interacts with SQL Server through EF Core.

Understanding the Full-Stack Flow

Before writing any code, it is important to understand the flow of data in a full-stack application:

Angular (Frontend)
        ↓ HTTP Calls (GET, POST, PUT, DELETE)
ASP.NET Core Web API (Backend)
        ↓ EF Core (ORM)
SQL Server (Database)
  • Angular displays UI, captures user data, and sends requests.

  • ASP.NET Core API exposes endpoints for CRUD operations.

  • EF Core performs database operations.

  • SQL Server stores the actual data.

This architecture ensures proper separation of concerns and makes your application scalable, maintainable, and professional.

Part 1: Setting Up the Backend with ASP.NET Core and EF Core

Step 1: Create a New ASP.NET Core Web API Project

Open terminal:

dotnet new webapi -n AngularAspNetEfCoreDemo
cd AngularAspNetEfCoreDemo

This creates the backend project.

Step 2: Install EF Core and SQL Server Packages

dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools

These packages allow the application to work with SQL Server through EF Core.

Step 3: Create a Model (Database Table Structure)

Create folder Models > Product.cs:

namespace AngularAspNetEfCoreDemo.Models
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
        public int Quantity { get; set; }
    }
}

This model represents a product in the system.

Step 4: Create a DbContext Class

Create folder Data > AppDbContext.cs:

using Microsoft.EntityFrameworkCore;
using AngularAspNetEfCoreDemo.Models;

namespace AngularAspNetEfCoreDemo.Data
{
    public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) {}

        public DbSet<Product> Products { get; set; }
    }
}

DbSet<Product> represents the Products table in SQL Server.

Step 5: Add Connection String

Open appsettings.json:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Database=ProductDB;Trusted_Connection=True;"
  }
}

EF Core will use this connection string to connect to SQL Server.

Step 6: Register DbContext in Program.cs

Open Program.cs and update:

using Microsoft.EntityFrameworkCore;
using AngularAspNetEfCoreDemo.Data;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllers();

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

var app = builder.Build();

app.MapControllers();

app.Run();

Now the backend knows how to connect to SQL Server.

Step 7: Create Database Using EF Core Migrations

dotnet ef migrations add InitialCreate
dotnet ef database update

This creates:

  • Database: ProductDB

  • Table: Products

Step 8: Create Products API Controller

Create file: Controllers/ProductsController.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using AngularAspNetEfCoreDemo.Data;
using AngularAspNetEfCoreDemo.Models;

namespace AngularAspNetEfCoreDemo.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class ProductsController : ControllerBase
    {
        private readonly AppDbContext _context;

        public ProductsController(AppDbContext context)
        {
            _context = context;
        }

        [HttpGet]
        public async Task<IEnumerable<Product>> GetProducts()
        {
            return await _context.Products.ToListAsync();
        }

        [HttpGet("{id}")]
        public async Task<ActionResult<Product>> GetProduct(int id)
        {
            var product = await _context.Products.FindAsync(id);
            if (product == null) return NotFound();
            return product;
        }

        [HttpPost]
        public async Task<ActionResult<Product>> AddProduct(Product product)
        {
            _context.Products.Add(product);
            await _context.SaveChangesAsync();
            return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product);
        }

        [HttpPut("{id}")]
        public async Task<IActionResult> UpdateProduct(int id, Product product)
        {
            if (id != product.Id) return BadRequest();

            _context.Entry(product).State = EntityState.Modified;
            await _context.SaveChangesAsync();
            return NoContent();
        }

        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteProduct(int id)
        {
            var product = await _context.Products.FindAsync(id);
            if (product == null) return NotFound();

            _context.Products.Remove(product);
            await _context.SaveChangesAsync();
            return NoContent();
        }
    }
}

Your backend is now fully functional.

Part 2: Creating the Angular Frontend

Step 1: Create Angular Project

Open terminal:

ng new product-app
cd product-app
ng serve -o

This creates and launches the Angular application.

Step 2: Create a Service for API Calls

Create:

src/app/services/product.service.ts

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

export interface Product {
  id: number;
  name: string;
  price: number;
  quantity: number;
}

@Injectable({
  providedIn: 'root'
})
export class ProductService {
  private apiUrl = 'https://localhost:5001/api/products';

  constructor(private http: HttpClient) {}

  getProducts(): Observable<Product[]> {
    return this.http.get<Product[]>(this.apiUrl);
  }

  getProduct(id: number): Observable<Product> {
    return this.http.get<Product>(`${this.apiUrl}/${id}`);
  }

  addProduct(product: Product): Observable<Product> {
    return this.http.post<Product>(this.apiUrl, product);
  }

  updateProduct(product: Product): Observable<void> {
    return this.http.put<void>(`${this.apiUrl}/${product.id}`, product);
  }

  deleteProduct(id: number): Observable<void> {
    return this.http.delete<void>(`${this.apiUrl}/${id}`);
  }
}

This service communicates with the ASP.NET Core backend.

Step 3: Add HttpClientModule

Open app.module.ts:

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [],
  imports: [
    BrowserModule,
    HttpClientModule,
    FormsModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

This allows Angular to make HTTP requests.

Step 4: Create Product Components

ng generate component components/product-list
ng generate component components/product-form

Step 5: Product List Component

product-list.component.ts

import { Component, OnInit } from '@angular/core';
import { Product, ProductService } from '../../services/product.service';

@Component({
  selector: 'app-product-list',
  templateUrl: './product-list.component.html'
})
export class ProductListComponent implements OnInit {
  products: Product[] = [];

  constructor(private service: ProductService) {}

  ngOnInit(): void {
    this.loadProducts();
  }

  loadProducts() {
    this.service.getProducts().subscribe(res => {
      this.products = res;
    });
  }

  deleteProduct(id: number) {
    this.service.deleteProduct(id).subscribe(() => {
      this.loadProducts();
    });
  }
}

product-list.component.html

<h2>Product List</h2>

<table border="1" width="100%">
  <tr>
    <th>Id</th>
    <th>Name</th>
    <th>Price</th>
    <th>Quantity</th>
    <th>Actions</th>
  </tr>

  <tr *ngFor="let p of products">
    <td>{{ p.id }}</td>
    <td>{{ p.name }}</td>
    <td>{{ p.price }}</td>
    <td>{{ p.quantity }}</td>
    <td>
      <button (click)="deleteProduct(p.id)">Delete</button>
    </td>
  </tr>
</table>

Step 6: Product Form Component

product-form.component.ts

import { Component } from '@angular/core';
import { ProductService, Product } from '../../services/product.service';

@Component({
  selector: 'app-product-form',
  templateUrl: './product-form.component.html'
})
export class ProductFormComponent {
  product: Product = { id: 0, name: '', price: 0, quantity: 0 };

  constructor(private service: ProductService) {}

  addProduct() {
    this.service.addProduct(this.product).subscribe(() => {
      alert('Product added successfully');
      this.product = { id: 0, name: '', price: 0, quantity: 0 };
    });
  }
}

product-form.component.html

<h2>Add Product</h2>

<form (submit)="addProduct()">
  <label>Name</label>
  <input [(ngModel)]="product.name" name="name">

  <label>Price</label>
  <input [(ngModel)]="product.price" name="price">

  <label>Quantity</label>
  <input [(ngModel)]="product.quantity" name="quantity">

  <button type="submit">Add</button>
</form>

Step 7: Add Components to App Component

Open app.component.html:

<h1>Product Management System</h1>

<app-product-form></app-product-form>
<hr>
<app-product-list></app-product-list>

Understanding the Integration

Now your full-stack system works like this:

1. Angular UI sends requests

  • GET /api/products

  • POST /api/products

2. ASP.NET Core Web API receives and processes requests

  • Routes in ProductsController handle them

3. EF Core interacts with SQL Server

  • Uses DbContext to run queries

  • Stores and fetches data

4. SQL Server stores all product information

5. Data returns to Angular

  • Displayed in the UI

This completes the full cycle of a full-stack CRUD application.

Conclusion

Building a full-stack application using Angular + ASP.NET Core + EF Core is easier once you understand how each part works. You learned:

  • How to build an ASP.NET Core Web API with CRUD operations

  • How to use EF Core to interact with SQL Server

  • How to create Angular components and services

  • How to connect Angular to the backend using HTTP

  • How the entire full-stack flow works

This architecture is used widely in enterprise applications because it is clean, modular, maintainable, fast, and scalable.