Building a Robust .NET 5 CRUD API with Angular and Entity Framework

In this article, we will create a .NET 5 Web API and Angular application to perform CRUD operations with the help of Entity Framework Core.

To demonstrate CRUD operation with .NET 5 Web API, we will use sample Product data.

What is .NET Web API?

.Net Web API is a framework for building, and consuming HTTP-based service. The advantage of Web API is that it can be consumed by a wide range of clients like a web browser and mobile applications.

Pre-requisites

  • .NET 5 Framework
  • Visual Studio 2019
  • Angular 7 and above
  • SQL Server 2008 and above

Database Design

Create Table

CREATE TABLE [dbo].[Product_Master](
	[Id] [int] IDENTITY(1,1) NOT NULL,
	[ProductName] [varchar](250) NULL,
	[ProductDescription] [varchar](250) NULL,
	[ProductCost] [decimal](18, 0) NULL,
	[Stock] [int] NULL,
 CONSTRAINT [PK_Product_Master] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

Add few records

What is .NET 5?

Dot Net 5 or .NET 5 is one of the major releases after .NET Core 3.1. It was released in November 2020.

Microsoft, dropped the word “Core” from the name to indicate that this is the future of .NET. It supports more platforms and apps than .NET Core and .NET Framework.

Create .NET 5 API Project in Visual Studio 2019

Let’s create a .NET 5 Web API project in Visual Studio 2019. There is no big issue in creating a project in Visual Studio 2019. Follow the below steps –

  • Open Visual Studio 2019.
  • Click on Create a new Project.
  • Select ASP.Net Core Web API from the Project template. Click Next
  • Give a name to your project. Click Next.
  • Select .NET 5.0 as the Target framework.
How to create .NET 5 Web API in Visual Studio 2019?

Add a Model class to your project.

Model Class (Product.cs)

    public class Product
    {
        [Key]
        public int Id { get; set; }
        public string ProductName { get; set; }
        public string ProductDescription { get; set; }
        public decimal ProductCost { get; set; }
        public int Stock { get; set; }
    }

Install packages related to Entity Framework

You need to install a few packages. You can do this either via the Packager Manager console or from the Nuget Packager Manager Wizard.

  • Microsoft.EntityFrameworkCore
  • Microsoft.EntityFrameworkCore.SqlServer (Install-Package Microsoft.EntityFrameworkCore.SqlServer)
  • Microsoft.EntityFrameworkCore.Tools (Install-Package Microsoft.EntityFrameworkCore.Tools)

Add Data Context Class

MyDataContext.cs File

    public class MyDataContext:DbContext
    {
        public MyDataContext(DbContextOptions<MyDataContext> options) : base(options)
        {
        }
        public DbSet<Product> Products { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Product>().ToTable("Product_Master");
        }
    }

Add Database Connection String

In appsettings.json file, add a connection string

  "ConnectionStrings": {
    "DefaultConnection": "Data Source=localhost\\sqlexpress;Initial Catalog=ProductDataBase;Trusted_Connection=True;"
  }

Get Database Connection String in Startup.cs file

Add the below line to the ConfigureServices() method in startup.cs file:

 services.AddDbContext<MyDataContext>(options =>
         options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

Allow Origins and Header

Add the below line to the Configure() method in startup.cs file. This will help us to avoid a ‘CORS’ related issue in the browser.

app.UseCors(options => options.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());

Add a Controller class to your project. (ProductController.cs)

    public class ProductController : ControllerBase
    {
        private readonly MyDataContext _context;

        public ProductController(MyDataContext context)
        {
            _context = context;
        }

        
        [HttpGet]
        [Route("List")]
        public async Task<ActionResult<IEnumerable<Product>>> Get()
        {
            return await _context.Products.ToListAsync();
        }

         
        [HttpGet]
        [Route("Details")]
        public async Task<ActionResult<Product>> Get(int id)
        {
            var data = await _context.Products.FindAsync(id);
            return data;
        }

        
        [HttpPost]
        //public async void Post(Product product)
        [Route("CreateRecord")]
        public async Task<ActionResult<Product>> POST(Product product)
        {
            _context.Products.Add(product);
            await _context.SaveChangesAsync();

            return CreatedAtAction(nameof(Get), new { id = product.Id }, product);
        }

        // PUT api/<ProductController>/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody] string value)
        {
        }

        
        [HttpPost]
        [Route("DeleteProduct")]
        public async Task<ActionResult<IEnumerable<Product>>> Delete(int id)
        {
            var product = await _context.Products.FindAsync(id);
            if (product == null)
            {
                return NotFound();
            }
            _context.Products.Remove(product);
            await _context.SaveChangesAsync();

            return await _context.Products.ToListAsync();
        }

        
        [HttpPost]
        [Route("UpdateProduct")]
        public async Task<ActionResult<IEnumerable<Product>>> Update(int id, Product product)
        {
            if (id != product.Id)
            {
                return BadRequest();
            }

            var productData = await _context.Products.FindAsync(id);
            if (productData == null)
            {
                return NotFound();
            }

            productData.ProductCost = product.ProductCost;
            productData.ProductDescription = product.ProductDescription;
            productData.ProductName = product.ProductName;
            productData.Stock = product.Stock;

            await _context.SaveChangesAsync();
            return await _context.Products.ToListAsync();

        }

    }

Test .NET 5 Web API with POSTMAN Tool

Once you have created .NET 5 Web API, you need to test it before you integrate it with an Angular application.

Create Angular Project

Now, create an Angular project with the below command.

ng new Net5Demo

Model File


export class Products {
    id: number;
    productName: string;
    productCost: number;
    productDescription: string;
    stock: number;
  }

Service File

Add a service file with the below command

ng g s net5-service
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { Products } from './Products';

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

  url = 'https://localhost:44303/api/Product/';
  constructor(private http: HttpClient) { }
  getProductList(): Observable<Products[]> {
    return this.http.get<Products[]>(this.url + 'List');
  }
  postProductData(productData: Products): Observable<Products> {
    const httpHeaders = { headers:new HttpHeaders({'Content-Type': 'application/json'}) };
    return this.http.post<Products>(this.url + 'CreateRecord', productData, httpHeaders);
  }
  updateProduct(product: Products): Observable<Products> {
    const httpHeaders = { headers:new HttpHeaders({'Content-Type': 'application/json'}) };
    return this.http.post<Products>(this.url + 'UpdateProduct?id=' + product.id, product, httpHeaders);
  }
  deleteProductById(id: number): Observable<number> {
    return this.http.post<number>(this.url + 'DeleteProduct?id=' + id, null);
  }
  getProductDetailsById(id: string): Observable<Products> {
    return this.http.get<Products>(this.url + 'Details?id=' + id);
  }
}

Component file

Let’s create a component file with the below command. (net5-apicall is the component file)

ng g c net5-apicall
<form class="form-horizontal" [formGroup]="productForm">
  <h1>Welcome to Angular CRUD with .NET 5</h1>
  <div class="form-group">
    <label class="control-label col-sm-2" for="pwd">Name of Product :</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" id="txtProductName" formControlName="productName"
        placeholder="Name of Product">
    </div>
  </div>
  <div class="form-group">
    <label class="control-label col-sm-2" for="pwd">Cost of Product :</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" id="txtProductCost" formControlName="productCost" placeholder="Cost of Product">
    </div>
  </div>
  <div class="form-group">
    <label class="control-label col-sm-2" for="pwd">Product Description :</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" id="txtProductDescription" formControlName="productDescription"
        placeholder="Product Description">
    </div>
  </div>
  <div class="form-group">
    <label class="control-label col-sm-2" for="pwd"># of Stock Available :</label>
    <div class="col-sm-2">
      <input type="text" class="form-control" id="txtStock" formControlName="stock" placeholder="Stock Available">
    </div>
  </div>
   <div class="form-group">
    <div class="container">
      <div class="row">
        <div class="col-sm">
          <button type="submit" class="btn btn-primary" (click)="PostProduct(productForm.value)">Submit</button> 
        </div>
        <div class="col-sm">
          <button type="submit" class="btn btn-primary" (click)="UpdateProduct(productForm.value)">Update</button>
        </div>
      
      </div>
    </div>

  </div>
  <div>
    <div class="alert alert-info"><b>Product List</b></div>
    <div class="table-responsive">
      <table class="table">
        <tr>
          <th>Product Name</th>
          <th>Cost</th>
          <th># of Stock</th>
          <th>Description</th>
          <th>Action</th>
        </tr>
        <tr *ngFor="let prd of ProductList | async">
          <td>{{prd.productName}}</td>
          <td>{{prd.productCost}}</td>
          <td>{{prd.stock}}</td>
          <td>{{prd.productDescription}}</td>
          <td><button type="button" matTooltip="Click Edit Button" (click)='ProductDetailsToEdit(prd.id)'>Edit</button>
            |
            <button type="button" matTooltip="Click Delete Button" (click)="DeleteProduct(prd.id)">Delete</button>
          </td>
        </tr>
      </table>
    </div>
  </div>
</form>

Component Type Script File

import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { FormBuilder, Validators } from '@angular/forms';
import { Observable } from 'rxjs';
import { Net5ServiceService } from '../net5-service.service';
import { Products } from '../Products';

@Component({
  selector: 'app-net5-apicall',
  templateUrl: './net5-apicall.component.html',
  styleUrls: ['./net5-apicall.component.css']
})
export class Net5APICallComponent implements OnInit {

  ProductList: Observable<Products[]>;
  ProductList1: Observable<Products[]>;
  productForm: any;
  massage = "";
  prodCategory = "";
  productId = 0;
  constructor(private formbulider: FormBuilder, private httpClient: HttpClient, private productService: Net5ServiceService) { }

  ngOnInit() {
    this.prodCategory = "0";
    this.productForm = this.formbulider.group({
      productName: ['', [Validators.required]],
      productCost: ['', [Validators.required]],
      productDescription: ['', [Validators.required]],
      stock: ['', [Validators.required]]
    });
    this.getProductList();
  }
  getProductList() {
    this.ProductList1 = this.productService.getProductList();
    this.ProductList = this.ProductList1;
  }
  PostProduct(product: Products) {
    debugger;
    const product_Master = this.productForm.value;
    this.productService.postProductData(product_Master).subscribe(
      () => {
        this.massage = 'Data Saved Successfully';
        this.getProductList();
      }
    );
  }
  ProductDetailsToEdit(id: string) {
    debugger;
    this.productService.getProductDetailsById(id).subscribe(productResult => {
      this.productId = productResult.id;
      this.productForm.controls['productName'].setValue(productResult.productName);
      this.productForm.controls['productCost'].setValue(productResult.productCost);
      this.productForm.controls['productDescription'].setValue(productResult.productDescription);
      this.productForm.controls['stock'].setValue(productResult.stock);
      // this.productForm.controls['product_category'].setValue(productResult.productCost);
    });
  }
  UpdateProduct(product: Products) {
    debugger;
    product.id = this.productId;
    const product_Master = this.productForm.value;
    this.productService.updateProduct(product_Master).subscribe(() => {
      this.massage = 'Record Updated Successfully';
      this.getProductList();
    });
  }
  DeleteProduct(id: number) {
    if (confirm('Do you want to delete this product?')) {
      this.productService.deleteProductById(id).subscribe(() => {
        this.getProductList();
      });
    }
  }
}

Add Routing

const routes: Routes = [
  {path: 'crud', component: Net5APICallComponent}
];

Import HttpClientModule, FormsModule and ReactiveFormsModule in app.module.ts file

import {HttpClientModule} from '@angular/common/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';

Add modules in the imports array in app.module.ts the file

imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    FormsModule,
    ReactiveFormsModule
  ],

Change app.component.html file

Remove everything from the app.component.html file and put it below the line.

<router-outlet></router-outlet>

Run your Project

Compile your project with the below command

ng serve 

Your screen should look like this.

Watch this Video which demonstrates the .NET 5 API CRUD with Angular

This demonstration will work with .NET Core 2.1 and .NET Core 3.1 as well.

Hope you like this article. Please share your feedback in the comment box below.

You may read this article – ASP.Net Core Interview Questions and Answers

Leave a Comment

RSS
YouTube
YouTube
Instagram