ASP.NET Core  

Build a Simple CRUD App (Angular Frontend + ASP.NET Core API + SQL Server)

Introduction

Building a simple CRUD application is one of the best ways to understand how all layers of a full-stack application work together. CRUD stands for Create, Read, Update, and Delete. In this tutorial, we will build a complete CRUD system using:

  • Angular as the frontend

  • ASP.NET Core Web API as the backend

  • SQL Server as the database

This guide walks you step-by-step through the entire setup: database design, API development, Angular UI, service integration, and testing CRUD operations.

Application Architecture Overview

The full-stack flow looks like this:

Angular UI  →  Angular Service  →  ASP.NET Core API  →  EF Core  →  SQL Server
      ↑                                                         ↓
      ←————— JSON Response ←————————— API Controller ←————————— 

Each layer has a clear responsibility:

  • SQL Server stores the data

  • Entity Framework Core manages the ORM

  • ASP.NET Core exposes APIs

  • Angular interacts with the API and displays UI

1. Setting Up the Database

Create the SQL Table

We will build a simple "Employees" CRUD system.

Run this SQL script:

CREATE TABLE Employees (
    Id INT IDENTITY(1,1) PRIMARY KEY,
    Name NVARCHAR(100),
    Email NVARCHAR(100),
    Department NVARCHAR(50)
);

This table will store our data.

2. Building the ASP.NET Core API

Create a New Project

Run:

dotnet new webapi -n CrudApi
cd CrudApi

Add Entity Framework Core and SQL Server Provider

Install packages:

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

Create the DB Context

Create AppDbContext.cs:

using Microsoft.EntityFrameworkCore;

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

        public DbSet<Employee> Employees { get; set; }
    }
}

Create Employee Model

Create Employee.cs:

namespace CrudApi.Models
{
    public class Employee
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string Department { get; set; }
    }
}

Add Connection String in appsettings.json

"ConnectionStrings": {
  "DefaultConnection": "Server=YOUR_SERVER;Database=CrudDb;Trusted_Connection=True;TrustServerCertificate=True;"
}

Register SQL Server in Program.cs

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

Create the CRUD Controller

Create EmployeesController.cs:

[ApiController]
[Route("api/[controller]")]
public class EmployeesController : ControllerBase
{
    private readonly AppDbContext _context;

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

    // GET All
    [HttpGet]
    public async Task<IActionResult> Get()
    {
        return Ok(await _context.Employees.ToListAsync());
    }

    // GET by Id
    [HttpGet("{id}")]
    public async Task<IActionResult> Get(int id)
    {
        var emp = await _context.Employees.FindAsync(id);
        return emp == null ? NotFound() : Ok(emp);
    }

    // POST Create
    [HttpPost]
    public async Task<IActionResult> Post(Employee emp)
    {
        _context.Employees.Add(emp);
        await _context.SaveChangesAsync();
        return Ok(emp);
    }

    // PUT Update
    [HttpPut("{id}")]
    public async Task<IActionResult> Put(int id, Employee emp)
    {
        var dbEmp = await _context.Employees.FindAsync(id);
        if (dbEmp == null) return NotFound();

        dbEmp.Name = emp.Name;
        dbEmp.Email = emp.Email;
        dbEmp.Department = emp.Department;

        await _context.SaveChangesAsync();
        return Ok(dbEmp);
    }

    // DELETE
    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(int id)
    {
        var emp = await _context.Employees.FindAsync(id);
        if (emp == null) return NotFound();

        _context.Employees.Remove(emp);
        await _context.SaveChangesAsync();
        return Ok();
    }
}

Your API is now ready.

3. Building the Angular Frontend

Create Angular Project

ng new crud-ui
cd crud-ui

Install Angular Material (optional):

ng add @angular/material

Create Employee Model

Create employee.model.ts:

export interface Employee {
  id?: number;
  name: string;
  email: string;
  department: string;
}

Create an Employee Service

ng generate service services/employee

employee.service.ts:

@Injectable({
  providedIn: 'root'
})
export class EmployeeService {

  apiUrl = 'https://localhost:5001/api/employees';

  constructor(private http: HttpClient) {}

  getEmployees() {
    return this.http.get<Employee[]>(this.apiUrl);
  }

  addEmployee(emp: Employee) {
    return this.http.post<Employee>(this.apiUrl, emp);
  }

  updateEmployee(emp: Employee) {
    return this.http.put<Employee>(`${this.apiUrl}/${emp.id}`, emp);
  }

  deleteEmployee(id: number) {
    return this.http.delete(`${this.apiUrl}/${id}`);
  }
}

4. Creating Components for CRUD

Generate Components

ng generate component pages/employee-list
ng generate component pages/employee-form

Employee List Component

employee-list.component.ts:

export class EmployeeListComponent implements OnInit {

  employees: Employee[] = [];

  constructor(private service: EmployeeService) {}

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

  loadEmployees() {
    this.service.getEmployees().subscribe(res => this.employees = res);
  }

  delete(id: number) {
    this.service.deleteEmployee(id).subscribe(() => this.loadEmployees());
  }
}

employee-list.component.html:

<h3>Employee List</h3>

<table>
  <tr>
    <th>Name</th>
    <th>Email</th>
    <th>Department</th>
    <th>Actions</th>
  </tr>

  <tr *ngFor="let emp of employees">
    <td>{{ emp.name }}</td>
    <td>{{ emp.email }}</td>
    <td>{{ emp.department }}</td>
    <td>
      <button (click)="delete(emp.id!)">Delete</button>
    </td>
  </tr>
</table>

<a routerLink="/add">Add Employee</a>

Employee Form Component

employee-form.component.ts:

export class EmployeeFormComponent {

  employee: Employee = {
    name: '',
    email: '',
    department: ''
  };

  constructor(private service: EmployeeService, private router: Router) {}

  save() {
    this.service.addEmployee(this.employee).subscribe(() => {
      this.router.navigate(['/']);
    });
  }
}

employee-form.component.html:

<h3>Add Employee</h3>

<form (ngSubmit)="save()">
  <input [(ngModel)]="employee.name" name="name" placeholder="Name">
  <input [(ngModel)]="employee.email" name="email" placeholder="Email">
  <input [(ngModel)]="employee.department" name="department" placeholder="Department">
  <button type="submit">Save</button>
</form>

5. Setting Up Angular Routing

Add routes in app-routing.module.ts:

const routes: Routes = [
  { path: '', component: EmployeeListComponent },
  { path: 'add', component: EmployeeFormComponent }
];

6. Testing the CRUD App

Once both the backend and frontend are running:

  • Run API: dotnet run

  • Run Angular: ng serve

Test all operations:

  • Add a new employee

  • View all employees

  • Update an employee

  • Delete an employee

Everything should be fully functional.

7. Best Practices for Production

  1. Use DTOs instead of exposing entity models directly

  2. Add client-side and server-side validation

  3. Use Angular Material or PrimeNG for better UI

  4. Secure the API with JWT authentication

  5. Implement global error handling in Angular and ASP.NET Core

  6. Use environment variables for API URLs

  7. Add pagination to large datasets

  8. Create a repository layer for cleaner architecture

Conclusion

You have now built a fully functional CRUD application using:

  • Angular for the UI

  • ASP.NET Core Web API for the backend

  • Entity Framework Core + SQL Server for the database

This architecture is widely used in enterprise-grade applications. By understanding the flow between the UI, API, and database, you gain the foundation needed for building large, scalable systems.