The post How to Create CRUD operation using Angular and ASP.NET Core Web API appeared first on Tech Insights.
]]>We will take a systematic step-by-step approach, applying the principles of clean architecture, to develop CRUD operation using Angular and ASP.NET Core Web API
Prerequisites
dotnet new project_Name
# Create Domain layer dotnet new classlib -n Domain # Create Application layer dotnet new classlib -n Application # Create Infrastructure layer dotnet new classlib -n Infrastructure
Now that we understand the principles of Clean Architecture, let’s see how we can reference it in an ASP.NET Core Web API project
<ItemGroup> <ProjectReference Include="..\Domain\Domain.csproj" /> </ItemGroup>
<ItemGroup> <ProjectReference Include="..\Domain\Domain.csproj" /> <ProjectReference Include="..\Application\Application.csproj" /> </ItemGroup>
<ItemGroup> <ProjectReference Include="..\Infrastructure\Infrastructure.csproj" /> </ItemGroup>
path:/Domain/Entities
Employee.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Domain.Entities { public class Employee : BaseEntity { public string FirstName { get; set; } public string LastName { get; set; } public string Street {get;set;} public string City { get; set; } public string State { get; set; } } }
BaseEntity.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Domain.Entities { public class BaseEntity { public BaseEntity() { CreateAt = DateTime.UtcNow; } public int Id { get; set; } public DateTime CreateAt { get; set; } } }
path:/Application/Interfaces
IEmployeeRepo.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Domain.Entities; namespace Application.Interfaces { public interface IEmployeeRepo { Task<IReadOnlyList<Employee>> GetEmployeeListAsync(); Employee GetEmployeeById(int id); Employee CreateEmployee(Employee employee); Employee UpdateEmployee(Employee employee); void DeleteEmployee(int id); } }
path:/Infrastructure/Data
AppDbContext.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Domain.Entities; using Microsoft.EntityFrameworkCore; namespace Infrastructure.Data { public class AppDbContext : DbContext { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } public DbSet<Employee> Employees { get; set;} } }
path:/Infrastructure/Repository
EmployeeRepository.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Application.Interfaces; using Domain.Entities; using Infrastructure.Data; using Microsoft.EntityFrameworkCore; namespace Infrastructure.Repository { public class EmployeeRepository : IEmployeeRepo { private readonly AppDbContext _context; public EmployeeRepository(AppDbContext context) { _context = context; } public Employee CreateEmployee(Employee employees) { _context.Employees.Add(employees); var result = _context.SaveChangesAsync(); if (result.IsCompletedSuccessfully) { return employees; } return null; } public Employee GetEmployeeById(int id) { return _context.Employees.FindAsync(id).Result; } public async Task<IReadOnlyList<Employee>> GetEmployeeListAsync() { return await _context.Employees.ToListAsync(); } public Employee UpdateEmployee(Employee employee) { this._context.Employees.Update(employee); _context.SaveChanges(); return employee; } public void DeleteEmployee(int id) { var result = GetEmployeeById(id); _context.Employees.Remove(result); _context.SaveChanges(); } } }
path:/Infrastructure/Services
ServicesConfig.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Application.Interfaces; using Infrastructure.Data; using Infrastructure.Repository; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace Infrastructure.Services { public static class ServicesConfig { public static IServiceCollection AddApplication(this IServiceCollection services, IConfiguration config) { services.AddDbContext<AppDbContext>(opt => { opt.UseSqlite(config.GetConnectionString("connection")); }); services.AddScoped<IEmployeeRepo, EmployeeRepository>(); return services; } } }
using Infrastructure.Services; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); builder.Services.AddApplication(builder.Configuration); //builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); builder.Services.AddCors(Opt => Opt.AddDefaultPolicy(opt => { opt.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin(); })); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.UseCors(); app.Run();
dotnet ef migrations add initialcreate -p .\Infrastructure\ -s API -o Migrations dotnet ef database update -p Infrastructure -s API
EmployeeController.cs
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Application.Interfaces; using Domain.Entities; using Microsoft.AspNetCore.Mvc; namespace API.Controllers { [Route("api/[controller]")] [ApiController] public class EmployeeController : ControllerBase { private readonly IEmployeeRepo _employeeRepo; public EmployeeController(IEmployeeRepo employeeRepo) { _employeeRepo = employeeRepo; } [HttpGet] public async Task<IReadOnlyList<Employee>> GetEmployees() { return await this._employeeRepo.GetEmployeeListAsync(); } [HttpPost] public ActionResult EmployeePost(Employee employees) { var result = _employeeRepo.CreateEmployee(employees); return Ok(result); } [HttpPut] public ActionResult EmployeePut(Employee employee) { var result = _employeeRepo.UpdateEmployee(employee); return Ok(result); } [HttpGet("{id}")] public Employee EmployeeGetById(int id) { var result = this._employeeRepo.GetEmployeeById(id); return result; } [HttpDelete("{id}")] public ActionResult DeleteEmployee(int id) { this._employeeRepo.DeleteEmployee(id); return Ok("Employee Deleted"); } } }
To create the client-side application, we’ll be using Angular. This section will guide you through setting up an Angular project and creating the necessary components.
# Create a client side Application ng new project_name # Navigate the inside project folder cd project_name # open the VS Code code . # Run the App ng serve
# Create a module ng g m employee/employee --flat # Create a Routing ng g m employee/employee-routing --flat # Create a Service ng g s employee/employee --flat # Shared module Employee.ts
import { NgModule, createComponent } from '@angular/core'; import { CommonModule } from '@angular/common'; import { Routes, RouterModule } from '@angular/router'; import { ReadComponent } from './read/read.component'; import { UpdateComponent } from './update/update.component'; import { DeleteComponent } from './delete/delete.component'; import { CreateComponent } from './create/create.component'; const routes : Routes=[ {path:'', component:ReadComponent}, {path:'Create', component:CreateComponent}, {path:'update/:id', component:UpdateComponent}, {path:'delete/:id', component:DeleteComponent}, ] @NgModule({ declarations: [], imports: [ RouterModule.forChild(routes), CommonModule ], exports:[ RouterModule ] }) export class EmployeeRoutingModule { }
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { CreateComponent } from './create/create.component'; import { UpdateComponent } from './update/update.component'; import { ReadComponent } from './read/read.component'; import { DeleteComponent } from './delete/delete.component'; import { EmployeeRoutingModule } from './employee-routing.module'; import { ReactiveFormsModule } from '@angular/forms'; @NgModule({ declarations: [ CreateComponent, UpdateComponent, ReadComponent, DeleteComponent ], imports: [ EmployeeRoutingModule, ReactiveFormsModule, CommonModule ] }) export class EmployeeModule { }
Employee.ts export interface Employee { id : number, firstName : string, lastName : string, street : string, city : string, state : string, createAt : Date }
import { Injectable } from '@angular/core'; import { Router, Routes } from '@angular/router'; import { HttpClient } from '@angular/common/http' import { Employee } from '../shared/modules/Employee'; import { map } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class EmployeeService { baseUrl = 'https://localhost:8080/api'; constructor(private http : HttpClient ,private router : Router ) { } CreateEmployee(values:any){ return this.http.post<Employee>(this.baseUrl + '/Employee/',values).pipe( map(employee=> { alert("Employee Created Successfully...!" + employee); }) ) } GetEmployee(){ return this.http.get<Employee>(this.baseUrl + '/Employee/') } GetEmployeeById(id:number){ return this.http.get<Employee>(this.baseUrl + '/Employee/'+ id) } UpdateEmployee(values:any){ return this.http.put<Employee>(this.baseUrl + '/Employee/', values).pipe( map(emp=>{ alert("Employee Updated Successfully...!" + emp); }) ) } RemoveEmployee(id:number){ return this.http.delete(this.baseUrl + '/Employee/' + id); } }
# Create a component ng g c Employee/Read --skip-tests ng g c Employee/Create--skip-tests ng g c Employee/Update --skip-tests ng g c Employee/Delete --skip-tests
import { Component, OnInit } from '@angular/core'; import { EmployeeService } from '../employee.service'; import { ActivatedRoute } from '@angular/router'; import { Employee } from 'src/app/shared/modules/Employee'; @Component({ selector: 'app-read', templateUrl: './read.component.html', styleUrls: ['./read.component.scss'] }) export class ReadComponent implements OnInit { employee? :any; constructor(private employeeServices: EmployeeService, private router:ActivatedRoute){} ngOnInit(): void { this.loadEmployee(); } loadEmployee(){ this.employeeServices.GetEmployee().subscribe({ next : emp => this.employee=emp, error: error=> alert(error) }); } }
<div> <table class="table table-success table-striped"> <thead> <tr> <th>Id</th> <th>First Name</th> <th>Last Name</th> <th>Street</th> <th>City</th> <th>State</th> <th>Created At</th> <th>Action</th> </tr> </thead> <tbody *ngFor="let emp of employee"> <tr> <td>{{emp.id}}</td> <td>{{emp.firstName}}</td> <td>{{emp.lastName}}</td> <td>{{emp.street}}</td> <td>{{emp.city}}</td> <td>{{emp.state}}</td> <td>{{emp.createAt}}</td> <td> <h5 class="mb-0"> <a routerLink="/delete/{{emp.id}}" class="text-dark text-decoration-none"> <span class="fa fa-trash"></span> </a> </h5> <h5 class="mb-0"> <a routerLink="/update/{{emp.id}}" class="text-dark text-decoration-none"> <span class="fa fa-edit"></span> </a> </h5> </td> </tr> </table> </div>
import { Component } from '@angular/core'; import { FormControl, FormGroup, Validators } from '@angular/forms'; import { EmployeeService } from '../employee.service'; import { Router } from '@angular/router'; @Component({ selector: 'app-create', templateUrl: './create.component.html', styleUrls: ['./create.component.scss'] }) export class CreateComponent { title : string ='Employee Registeration Form'; EmpForm = new FormGroup({ firstName : new FormControl('',Validators.required), lastName: new FormControl('',Validators.required), street: new FormControl('',Validators.required), city: new FormControl('',Validators.required), state: new FormControl('',Validators.required) }); constructor(private employeeService: EmployeeService, private router: Router){} onSubmit(){ this.employeeService.CreateEmployee(this.EmpForm.value).subscribe({ next:()=> this.router.navigateByUrl('/'), error:()=> alert("Please check ...!") }) } }
<div class="d-flex justify-content-center mt-5"> <div class="col-3"> <form [formGroup]="EmpForm" (ngSubmit)="onSubmit()"> <div class="text-center mb-4"> <h1 class="mb-3"> Employee </h1> </div> <div class="form-floating mb-3"> <input type="firstName" formControlName="firstName" class="form-control" id="floatingInput" placeholder="first Name"> <label for="floatingInput">firstName</label> </div> <div class="form-floating"> <input type="lastName" formControlName="lastName" class="form-control" id="floatingPassword" placeholder="last Name"> <label for="floatingPassword">lastName</label> </div> <div class="form-floating"> <input type="street" formControlName="street" class="form-control" id="floatingPassword" placeholder="street"> <label for="floatingPassword">street</label> </div> <div class="form-floating"> <input type="city" formControlName="city" class="form-control" id="floatingPassword" placeholder="city"> <label for="floatingPassword">city</label> </div> <div class="form-floating"> <input type="state" formControlName="state" class="form-control" id="floatingPassword" placeholder="state"> <label for="floatingPassword">state</label> </div> <div class="d-grid"> <button class="btn btn-lg btn-primary mt-3" type="submit"> Submit </button> </div> </form> </div> </div>
import { Component, OnInit } from '@angular/core'; import { EmployeeService } from '../employee.service'; import { ActivatedRoute, Router } from '@angular/router'; import { FormControl, FormGroup, Validators } from '@angular/forms'; @Component({ selector: 'app-update', templateUrl: './update.component.html', styleUrls: ['./update.component.scss'] }) export class UpdateComponent implements OnInit{ employee?:any; id?:any; constructor(private employeeService:EmployeeService, private router:ActivatedRoute,private route:Router) { this.id = this.router.snapshot.paramMap.get('id'); } EmpForm = new FormGroup({ firstName : new FormControl('',Validators.required), lastName: new FormControl('',Validators.required), street: new FormControl('',Validators.required), city: new FormControl('',Validators.required), state: new FormControl('',Validators.required), id: new FormControl('',Validators.required) }); ngOnInit(): void { this.getEmployee(); } getEmployee(){ if(this.id) this.employeeService.GetEmployeeById(this.id).subscribe({ next : emp => this.employee = emp, error : error=>alert(error) }); } onSubmit(){ this.employeeService.UpdateEmployee(this.EmpForm.value).subscribe({ next:()=>this.route.navigateByUrl('/'), error:()=>alert("Please check...!") }) } }
<p>update works!</p> <div class="d-flex justify-content-center mt-10"> <div class="col-10"> <div > <form *ngIf="employee" [formGroup]="EmpForm" (ngSubmit)="onSubmit()"> <fieldset> <div class="mb-3"> <label for="disabledTextInput" class="form-label">First Name</label> <input type="text" id="firstName" formControlName="firstName" class="form-control" [(ngModel)]="employee.firstName" > </div> <div class="mb-3"> <label for="disabledTextInput" class="form-label">Last Name</label> <input type="text" id="lastName" formControlName="lastName" class="form-control" [(ngModel)]="employee.lastName"> </div> <div class="mb-3"> <label for="disabledTextInput" class="form-label">Street</label> <input type="text" id="street" formControlName="street" class="form-control" [(ngModel)]="employee.street"> </div> <div class="mb-3"> <label for="disabledTextInput" class="form-label">City</label> <input type="text" id="city" formControlName="city" class="form-control" [(ngModel)]="employee.city"> </div> <div class="mb-3"> <label for="disabledTextInput" class="form-label">State</label> <input type="text" id="state" formControlName="state" class="form-control" [(ngModel)]="employee.state"> </div> <input type="hidden" id="id" formControlName="id" class="form-control" [(ngModel)]="employee.id" > <div class="d-grid"> <button class="btn btn-lg btn-primary mt-3" type="submit"> Submit </button> </div> </fieldset> </form> </div>
import { Component, OnInit } from '@angular/core'; import { EmployeeService } from '../employee.service'; import { ActivatedRoute, Router } from '@angular/router'; @Component({ selector: 'app-delete', templateUrl: './delete.component.html', styleUrls: ['./delete.component.scss'] }) export class DeleteComponent implements OnInit { employee?:any; id?:any; constructor(private employeeService:EmployeeService, private router : ActivatedRoute, private route:Router) { this.id =this.router.snapshot.paramMap.get('id'); } ngOnInit(): void { this.getEmployee(); } getEmployee(){ if(this.id) this.employeeService.GetEmployeeById(this.id).subscribe({ next : emp => this.employee = emp, error : error=>alert(error) }); } onSubmit(){ this.employeeService.RemoveEmployee(this.id).subscribe({ next : ()=>this.route.navigateByUrl('/'), error :()=>alert("Please check..!") }); } }
<div class="d-flex justify-content-center mt-10"> <div class="col-10"> <div *ngIf="employee"><form> <fieldset disabled> <div class="mb-3"> <label for="disabledTextInput" class="form-label">First Name</label> <input type="text" id="" class="form-control" placeholder="{{ employee.firstName }}"> </div> <div class="mb-3"> <label for="disabledTextInput" class="form-label">Last Name</label> <input type="text" id="" class="form-control" placeholder="{{ employee.lastName }}"> </div> <div class="mb-3"> <label for="disabledTextInput" class="form-label">Street</label> <input type="text" id="" class="form-control" placeholder="{{ employee.street }}"> </div> <div class="mb-3"> <label for="disabledTextInput" class="form-label">City</label> <input type="text" id="" class="form-control" placeholder="{{ employee.city }}"> </div> <div class="mb-3"> <label for="disabledTextInput" class="form-label">State</label> <input type="text" id="" class="form-control" placeholder="{{ employee.state }}"> </div> </fieldset> </form> <div class="d-grid"> <button class="btn btn-lg btn-primary mt-3" type="submit" (click)="onSubmit()"> Submit </button> </div> </div>
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; const routes: Routes = [ {path:'',loadChildren:()=>import('./Employee/employee.module').then(emp=>emp.EmployeeModule)}, ]; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { }
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css'> <div class="d-flex justify-content-center mt-5"> <div class="col-0"> <h5 class="mb-0"> <a routerLink="/Create/" class="text-dark text-decoration-none"> <button class="btn btn-primary">Add Employee</button> </a> </h5> <br> <router-outlet></router-outlet> </div> </div>
Related Article – How to Create a Complete Login Page using Angular and .NET Core
Get List
Update record
Delete Record
The post How to Create CRUD operation using Angular and ASP.NET Core Web API appeared first on Tech Insights.
]]>