Build An App Using Angular 11, .NET Core And SQL Server

In this article, we’ll implement Asp.Net Core 5.0 Web API CRUD Operations with Angular 11.
 
Step 1
 
Let's first open  Visual Studio 2019 and from the new project window, select Asp.Net Core Web Application as shown below.

 
After providing the project name and location a new window will be opened as follows, Select Target Framework. The above steps will create a brand new ASP.NET Core    Web  API project
 
 
Step 2
 
Let's install Entity Framework Core NuGet packages to interact with the database 

 
Step 3
 
Create Folder Models and let's add DB model class file,

 
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.ComponentModel.DataAnnotations;  
  4. using System.ComponentModel.DataAnnotations.Schema;  
  5. using System.Linq;  
  6. using System.Threading.Tasks;  
  7.   
  8. namespace InventoryAPI.Models  
  9. {  
  10.     public class InventoryDetail  
  11.     {  
  12.   
  13.         [Key]  
  14.         public int InventoryDetailId { getset; }  
  15.   
  16.         [Column(TypeName = "nvarchar(100)")]  
  17.         public string ProductName { getset; }  
  18.   
  19.         [Column(TypeName = "nvarchar(12)")]  
  20.         public string SKU { getset; }  
  21.   
  22.         [Column(TypeName = "nvarchar(5)")]  
  23.         public string ExpirationDate { getset; }  
  24.   
  25.         [Column(TypeName = "nvarchar(3)")]  
  26.         public string Quantity { getset; }  
  27.     }  
  28. }  
  1. using Microsoft.EntityFrameworkCore;  
  2. using System;  
  3. using System.Collections.Generic;  
  4. using System.Linq;  
  5. using System.Threading.Tasks;  
  6.   
  7. namespace InventoryAPI.Models  
  8. {  
  9.     public class InventoryDetailContext:DbContext  
  10.     {  
  11.         public InventoryDetailContext(DbContextOptions<InventoryDetailContext> options) : base(options)  
  12.         {  
  13.   
  14.         }  
  15.   
  16.         public DbSet<InventoryDetail> InventoryDetails { getset; }  
  17.     }  
  18. }  
DB Migration will be done with this InventoryDetailContext. So we have added the DbSet property for the Detail Model class, after migration PaymentDetails table will be created in SQL Server Database.

Into this model class constructor parameter- options, we have to pass which DbProvider (SQL Server, MySQL, PostgreSQL, etc) to use and corresponding DB connection string also. For that, we’ll be using dependency injection in ASP.NET Core with Startup. cs file as below.
  1. using Microsoft.AspNetCore.Builder;  
  2. using Microsoft.AspNetCore.Hosting;  
  3. using Microsoft.AspNetCore.Mvc;  
  4. using Microsoft.EntityFrameworkCore;  
  5. using Microsoft.Extensions.Configuration;  
  6. using Microsoft.Extensions.DependencyInjection;  
  7. using Microsoft.Extensions.Hosting;  
  8. using Microsoft.Extensions.Logging;  
  9. using Microsoft.OpenApi.Models;  
  10. using InventoryAPI.Models;  
  11. using System;  
  12. using System.Collections.Generic;  
  13. using System.Linq;  
  14. using System.Threading.Tasks;  
  15.   
  16.   
  17. namespace InventoryAPI  
  18. {  
  19.   
  20.     public class Startup  
  21.     {  
  22.         public Startup(IConfiguration configuration)  
  23.         {  
  24.             Configuration = configuration;  
  25.         }  
  26.   
  27.         public IConfiguration Configuration { get; }  
  28.   
  29.         // This method gets called by the runtime. Use this method to add services to the container.  
  30.         public void ConfigureServices(IServiceCollection services)  
  31.         {  
  32.   
  33.             services.AddControllers();  
  34.             services.AddSwaggerGen(c =>  
  35.             {  
  36.                 c.SwaggerDoc("v1"new OpenApiInfo { Title = "InventoryAPI", Version = "v1" });  
  37.             });  
  38.   
  39.             services.AddDbContext<InventoryDetailContext>(options =>  
  40.             options.UseSqlServer(Configuration.GetConnectionString("DevConnection")));  
  41.   
  42.             services.AddCors();  
  43.         }  
  44.   
  45.         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.  
  46.         public void Configure(IApplicationBuilder app, IWebHostEnvironment env)  
  47.         {  
  48.             app.UseCors(options =>  
  49.             options.WithOrigins("http://localhost:4200")  
  50.             .AllowAnyMethod()  
  51.             .AllowAnyHeader());  
  52.   
  53.             if (env.IsDevelopment())  
  54.             {  
  55.                 app.UseDeveloperExceptionPage();  
  56.                 app.UseSwagger();  
  57.                 app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json""PaymentAPI v1"));  
  58.             }  
  59.   
  60.             app.UseRouting();  
  61.   
  62.             app.UseAuthorization();  
  63.   
  64.             app.UseEndpoints(endpoints =>  
  65.             {  
  66.                 endpoints.MapControllers();  
  67.             });  
  68.         }  
  69.     }  
  70. }  
Step 4
 
Let's make use of dependency injection for DbContext class, through which SQL Server is set as a DbProvider with a connection string, Now save the connection string in the appsettings.json file using the UATConnection key as follows.
  1. {  
  2.   "Logging": {  
  3.     "LogLevel": {  
  4.       "Default""Information",  
  5.       "Microsoft""Warning",  
  6.       "Microsoft.Hosting.Lifetime""Information"  
  7.     }  
  8.   },  
  9.   "AllowedHosts""*",  
  10.   "ConnectionStrings": {  
  11.     "UATConnection""Server=.;Database=InventoryDetailDB;Trusted_Connection=True;MultipleActiveResultSets=True;"  
  12.   }  
  13. }  
Step 5
 
Select the project from solution explorer, then go to Tools > NuGet Package Manager > Package Manager Console. Then execute the following commands one by one.
  1. Add-Migration "InitialCreate"  
  2. Update-Database  
 
 
 
 
Step 6
 
Now let's create API controller right-click on Controllers folder Add > Controller, Select API Controller with actions, using Entity Framework.


  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Threading.Tasks;  
  5. using Microsoft.AspNetCore.Http;  
  6. using Microsoft.AspNetCore.Mvc;  
  7. using Microsoft.EntityFrameworkCore;  
  8. using InventoryAPI.Models;  
  9.   
  10. namespace InventoryAPI.Controllers  
  11. {  
  12.     [Route("api/[controller]")]  
  13.     [ApiController]  
  14.     public class InventoryDetailController : ControllerBase  
  15.     {  
  16.         private readonly InventoryDetailContext _context;  
  17.   
  18.         public InventoryDetailController(InventoryDetailContext context)  
  19.         {  
  20.             _context = context;  
  21.         }  
  22.   
  23.         // GET: api/InventoryDetail  
  24.         [HttpGet]  
  25.         public async Task<ActionResult<IEnumerable<InventoryDetail>>> GetInventoryDetails()  
  26.         {  
  27.             return await _context.InventoryDetails.ToListAsync();  
  28.         }  
  29.   
  30.         // GET: api/InventoryDetail/5  
  31.         [HttpGet("{id}")]  
  32.         public async Task<ActionResult<InventoryDetail>> GetInventoryDetail(int id)  
  33.         {  
  34.             var inventoryDetail = await _context.InventoryDetails.FindAsync(id);  
  35.   
  36.             if (inventoryDetail == null)  
  37.             {  
  38.                 return NotFound();  
  39.             }  
  40.   
  41.             return inventoryDetail;  
  42.         }  
  43.   
  44.         // PUT: api/InventoryDetail/5  
  45.         // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754  
  46.         [HttpPut("{id}")]  
  47.         public async Task<IActionResult> PutInventoryDetail(int id, InventoryDetail inventoryDetail)  
  48.         {  
  49.             if (id != inventoryDetail.InventoryDetailId)  
  50.             {  
  51.                 return BadRequest();  
  52.             }  
  53.   
  54.             _context.Entry(inventoryDetail).State = EntityState.Modified;  
  55.   
  56.             try  
  57.             {  
  58.                 await _context.SaveChangesAsync();  
  59.             }  
  60.             catch (DbUpdateConcurrencyException)  
  61.             {  
  62.                 if (!InventoryDetailExists(id))  
  63.                 {  
  64.                     return NotFound();  
  65.                 }  
  66.                 else  
  67.                 {  
  68.                     throw;  
  69.                 }  
  70.             }  
  71.   
  72.             return NoContent();  
  73.         }  
  74.   
  75.         // POST: api/InventoryDetail  
  76.         // To protect from overposting attacks, see https://go.microsoft.com/fwlink/?linkid=2123754  
  77.         [HttpPost]  
  78.         public async Task<ActionResult<InventoryDetail>> PostInventoryDetail(InventoryDetail inventoryDetail)  
  79.         {  
  80.             _context.InventoryDetails.Add(inventoryDetail);  
  81.             await _context.SaveChangesAsync();  
  82.   
  83.             return CreatedAtAction("GetInventoryDetail"new { id = inventoryDetail.InventoryDetailId }, inventoryDetail);  
  84.         }  
  85.   
  86.         // DELETE: api/InventoryDetail/5  
  87.         [HttpDelete("{id}")]  
  88.         public async Task<IActionResult> DeleteInventoryDetail(int id)  
  89.         {  
  90.             var inventoryDetail = await _context.InventoryDetails.FindAsync(id);  
  91.             if (inventoryDetail == null)  
  92.             {  
  93.                 return NotFound();  
  94.             }  
  95.   
  96.             _context.InventoryDetails.Remove(inventoryDetail);  
  97.             await _context.SaveChangesAsync();  
  98.   
  99.             return NoContent();  
  100.         }  
  101.   
  102.         private bool InventoryDetailExists(int id)  
  103.         {  
  104.             return _context.InventoryDetails.Any(e => e.InventoryDetailId == id);  
  105.         }  
  106.     }  
  107. }  
Now we have web methods POST, GET, PUT and DELETE for Create, Retrieve, Update and Delete operations respectively. As a constructor parameter we’ve context of the type InventoryDetailContext. The instance/value for this parameter will be passed from dependency injection from StartUp class.
 
Step 7
 
Now let's create Angular Project for front-end client-side app
  1. ng new app_name  
  2. # after project creation.  
  3. # navigate inside project folder  
  4. cd app_name  
  5. # open in vs code  
  6. code .  
  7. # from vs code terminal  
  8. # command to open the app in default web browser  
  9. ng serve --o  
Now we have two components, inventroy-details component to show the list of records and it has a child component inventory-detail-form, a form for insert and update operation can be designed.
 
To create these 2 components, Lets'execute the below commands.
  1. ng g c inventory-details -s --skipTests  
  2. ng g c inventory-details/payment-detail-form -s --skipTests  
For this application, we’ll be using Bootstrap and Font Awesome Icons. so let’s add their stylesheet reference in index.html.
  1. <!--  Add following stylesheets to <head> tag  -->    
  2. <link rel="preload" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">    
  3. <link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" data-rocket-async="style" as="style" onload="this.onload=null;this.rel='stylesheet'" integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog==" crossorigin="anonymous" />     
Step 8
 
Let's create a modal class for Inventory Details 
  1. ng g class shared/inventory-detail --type=model --skipTests  
  1. export class InventoryDetail {  
  2.     InventoryDetailId: number=0;  
  3.     ProductName: string='';  
  4.     SKU: string='';  
  5.     ExpirationDate: string='';  
  6.     Quantity: string='';  
  7. }  
Step 9
 
Create service class as below
  1. ng g s shared/inventory-detail --skipTests  
  1. import { Injectable } from '@angular/core';  
  2. import { InventoryDetail } from './inventory-detail.model';  
  3. import { HttpClient } from "@angular/common/http";  
  4.   
  5. @Injectable({  
  6.   providedIn: 'root'  
  7. })  
  8. export class InventoryDetailService {  
  9.   constructor(private http: HttpClient) { }  
  10.   
  11.   readonly baseURL = 'http://localhost:61236/api/InventoryDetail';      
  12.   formData: InventoryDetail= new InventoryDetail();  
  13.   list : InventoryDetail[];  
  14.   
  15.   
  16.   postnventoryDetail() {  
  17.     return this.http.post(this.baseURL, this.formData);  
  18.   }  
  19.   putInventoryDetail() {  
  20.     return this.http.put(`${this.baseURL}/${this.formData.InventoryDetailId}`, this.formData);  
  21.   }  
  22.   deleteinventoryDetail(id: number) {  
  23.     return this.http.delete(`${this.baseURL}/${id}`);  
  24.   }  
  25.   
  26.   refreshList() {  
  27.     this.http.get(this.baseURL)  
  28.       .toPromise()  
  29.       .then(res =>this.list = res as InventoryDetail[]);  
  30.   }  
  31. }  
Lets import HttpClient Module in app.Module.ts file
  1. import { BrowserModule } from '@angular/platform-browser';  
  2. import { NgModule } from '@angular/core';  
  3. import { FormsModule } from "@angular/forms";  
  4. import { BrowserAnimationsModule } from '@angular/platform-browser/animations';  
  5. import { ToastrModule } from 'ngx-toastr';  
  6.   
  7. import { AppComponent } from './app.component';  
  8. import { InventoryDetailsComponent } from './inventory-details/inventory-details.component';  
  9. import { InventoryDetailFormComponent } from './inventory-details/inventory-detail-form/inventory-detail-form.component';  
  10. import { HttpClientModule } from '@angular/common/http';  
  11.   
  12. @NgModule({  
  13.   declarations: [  
  14.     AppComponent,  
  15.     InventoryDetailsComponent,  
  16.     InventoryDetailFormComponent  
  17.   ],  
  18.   imports: [  
  19.     BrowserModule,  
  20.     FormsModule,  
  21.     HttpClientModule,  
  22.     BrowserAnimationsModule,  
  23.     ToastrModule.forRoot()  
  24.   ],  
  25.   providers: [],  
  26.   bootstrap: [AppComponent]  
  27. })  
  28. export class AppModule { }  
Step 10
 
Create a form for all crud operations inventory-detail-form.component.html
  1. <form novalidate autocomplete="off" #form="ngForm" (submit)="onSubmit(form)">    
  2.     <input type="hidden" name="inventoryDetailId" [value]="service.formData.inventoryDetailId" />    
  3.     <div class="form-group">    
  4.         <label>Product NAME</label>    
  5.         <input class="form-control form-control-lg" placeholder="Full Name" name="ProductName"    
  6.             #cardOwnerName="ngModel" [(ngModel)]="service.formData.ProductName"    
  7.             required [class.invalid]="ProductName.invalid && ProductName.touched">    
  8.     </div>    
  9.     <div class="form-group">    
  10.         <label>SKU</label>    
  11.         <input class="form-control form-control-lg" placeholder="12 Digit SKU Number" name="SKU"    
  12.             #cardNumber="ngModel" [(ngModel)]="service.formData.SKU"    
  13.             required maxlength="12" minlength="16" [class.invalid]="SKU.invalid && SKU.touched">    
  14.     </div>    
  15.     <div class="form-row">    
  16.         <div class="form-group col-md-6">    
  17.             <label>QUANTITY</label>    
  18.             <input type="password" class="form-control form-control-lg" placeholder="QUANTITY" name="Quantity"    
  19.                 #securityCode="ngModel" [(ngModel)]="service.formData.Quantity"    
  20.                 required maxlength="3" minlength="3" [class.invalid]="Quantity.invalid && Quantity.touched">    
  21.         </div>    
  22.         <div class="form-group col-md-6">    
  23.             <label>Expiry Date</label>    
  24.             <input class="form-control form-control-lg" placeholder="MM/YY" name="ExpirationDate"    
  25.                 #expirationDate="ngModel" [(ngModel)]="service.formData.ExpirationDate"    
  26.                 required maxlength="5" minlength="5" [class.invalid]="ExpirationDate.invalid && ExpirationDate.touched">    
  27.         </div>    
  28.     </div>    
  29.     <div class="form-group">    
  30.         <button class="btn btn-info btn-lg btn-block" type="submit" [disabled]="form.invalid">SUBMIT</button>    
  31.     </div>    
  32. </form>     

Conclusion


In this article, we discussed how to build an application using .Net core angular 11 and SQL server. I hope you all enjoyed reading this and learned from it. For better understanding download the source code and find all the form validations and CSS.