CRUD Operation With Angular 5 HTTP Client And ASP.NET Core Web API

HTTP is the messaging system between the client and the server-client that sends the request and the server responds with the proper message. Angular HTTP client is the toolkit that enables us to send and receive the data over the RESTful HTTP endpoints. In Angular 4.3, this Angular HTTP API was provided which in the extension to the existing API provides some new features and added to its own package of the @angular/common/HTTP.

Let’s divide this article into two sections - the first one being the Angular part and UI part while the second one is the Server-side code which will hold the API part of the project.

Client-side setup

To make the HTTP client module available in the application, we must make sure it is included and configured properly in the application. Let’s see step by step how we can do this.

Import the HTTP client module into the application module or root module. So, our root module is app.module.ts.

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';

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

Now, we have imported the HTTP Client into our application. We can use them in our component easily. For this demo, we are using the simple Employee as an entity and we are going to demo the Get, Post, Put and Delete Requests. For this demo purpose, let's add one component in our Angular application.

In my case, I have added the component Employee. The component looks like below.

<div class="container">
  <h3>Employee List</h3>
  <table class="table table-condensed">
    <thead>
      <tr>
        <td>    </td>
        <td>     </td>
        <td>     </td>
        <td>     </td>
        <td>  <a (click)="ShowRegForm(e)">Add New</a></td>
      </tr>
      <tr>
        <th>ID</th>
        <th>First Name</th>
        <th>Last Name</th>
        <th>Email</th>
        <th>Edit</th>
      </tr>
    </thead>
    <tbody>
      <tr class="success" *ngFor="let e of employeelist ">
        <td> {{e.id}}</td>
        <td>{{e.fname}}</td>
        <td>{{e.lname}}</td>
        <td>{{e.email}}</td>
        <td><a (click)="ShowRegForm(e)">Edit</a></td>
        <td><a (click)="ShowRegFormForDelete(e)">Delete</a></td>
      </tr>
    </tbody>
  </table>
</div>
<hr >

<form #regForm="ngForm">
  <div class="container" *ngIf="editCustomer">
    <h3>{{FormHeader}}</h3>
    <table class="table table-condensed">
      <tbody>
        <tr>
          <td>First Name</td>
          <td><input type="text" name="fname" [(ngModel)]='fname' ></td>
        </tr>
        <tr>
          <td>Last Name</td>
          <td><input type="text" name="lname" [(ngModel)]='lname'></td>
        </tr>
        <tr>
          <td> Email</td>
          <td><input type="text" name="email" [(ngModel)]='email'></td>
        </tr>
        <tr>
          <td><input type="hidden" name="id" [(ngModel)]='id'></td>
          <td><input type="button" value="Save" (click)="Save(regForm)"></td>
        </tr>
      </tbody>
    </table>
  </div>
</form>

Code Description

Here, we have an HTML page that has provision to display the List of the employees present in the database and then the Options to Add, Edit, List, and Delete.

Here based on the Button input the Form Header will be set according to the operation such as delete, add, and edit.

The next step is the component itself and we have done the code for that.

Import Statements

import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { FormsModule } from '@angular/forms';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';

import { EmployeeDataService } from '../DataServices/EmployeeDataService';
import { employee } from '../Models/Employee';

These are the basic imports that we can see here out of them, the others being the basic imports. We have some interesting imports like do, filter, and map -- these are the operators that are used to transform the result that we get from the service

Another section we have is the Data Service part and the Modal part we have EmployeeDataService which we have created to handle the Data related operations .

Constructor and inject the Data Service

Here we have used the Employee Data Service in our application it we have used the DI and injected it in the constructor like the below:

constructor(private dataservice: EmployeeDataService) // Available at imports
{
}

The next section is the code that we are using to call the data services as below:

ngOnInit() {
  this.dataservice.getEmployee().subscribe((tempdate) => {
    this.employeelist = tempdate;
  }), err => {
    console.log(err);
  }
}

ShowRegForm = function(employee) {
  this.editCustomer = true;
  if (employee != null) {
    this.SetValuesForEdit(employee)
  } else {
    this.ResetValues();
  }
}

ShowRegFormForDelete = function(employee) {
  this.editCustomer = true;
  if (employee != null) {
    this.SetValuesForDelete(employee)
  }
}

SetValuesForDelete = function(employee) {
  this.fname = employee.fname;
  this.lname = employee.lname;
  this.email = employee.email;
  this.id = employee.id;
  this.FormHeader = "Delete"
}

SetValuesForEdit = function(employee) {
  this.fname = employee.fname;
  this.lname = employee.lname;
  this.email = employee.email;
  this.id = employee.id;
  this.FormHeader = "Edit"
}

ResetValues() {
  this.fname = "";
  this.lname = "";
  this.email = "";
  this.id = "";
  this.FormHeader = "Add"
}

Save(regForm: NgForm) {
  this.GetDummyObject(regForm);

  switch (this.FormHeader) {
    case "Add":
      this.Addemployee(this.Dummyemployee);
      break;
    case "Edit":
      this.UpdateEmployee(this.Dummyemployee);
      break;
    case "Delete":
      this.DeleteEmployee(this.Dummyemployee);
      break;
    default:
      break;
  }
}

GetDummyObject(regForm: NgForm): employee {
  this.Dummyemployee = new employee;
  this.Dummyemployee.Email = regForm.value.email;
  this.Dummyemployee.Fname = regForm.value.fname;
  this.Dummyemployee.Lname = regForm.value.lname;
  this.Dummyemployee.ID = regForm.value.id;
  return this.Dummyemployee;
}

Addemployee(e: employee) {
  this.dataservice.AddEmployee(this.Dummyemployee).subscribe(res =>
    {
      this.employeelist.push(res);
      alert("Data added successfully !!")
      this.editCustomer = false;
    }),
    err => {
      console.log("Error Occured " + err);
    }
}

UpdateEmployee(e: employee) {
  this.dataservice.EditEmployee(this.Dummyemployee).subscribe(res =>
    {
      this.editCustomer = false;
      this.dataservice.getEmployee().subscribe(res => {
        this.employeelist = res;
      });
      alert("Employee data Updated successfully !!")
    });
}

DeleteEmployee(e: employee) {
  this.dataservice.DeleteEmployee(this.Dummyemployee).subscribe(res =>
    {
      this.editCustomer = false;
      this.dataservice.getEmployee().subscribe(res => {
        this.employeelist = res;
      });
      alert("employee Deleted successfully !! ")
    });
}

We can see that we have called the get employee method from the ngOnInit Event of the component instead of calling in the constructor we have specifically done this to avoid the delay in loading the component

Next, we have methods like Addemployee(), DeleteEmployee(), and UpdateEmployee() which are used for the calling the Data service methods from the application like Add Edit and Delete Employees

Other methods are the supplementary methods which are used to clear the inputs and set the object.

The next thing that we have used in our application is the Config.ts file Code for the same is as follows.

export const ROOT_URL: string = "http://localhost:39029/api/";

Here in this code, we have defined the Root_URL as the constant that holds the value of the API address. Next is the Model employee.ts which we use to map the Data that we are sending and receiving from the API code snippet for the same is

export interface Employee {
    ID: string;
    Fname: string;
    Lname: string;
    Email: string;
}

The main and most important part of the application is the Data service which we have used.

The code snippet for the same is as follows.

import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/retry';
import 'rxjs/add/observable/of';
import 'rxjs/Rx';

import { employee } from '../Models/Employee';
import { ROOT_URL } from '../Models/Config';
import { Injectable } from '@angular/core';

@Injectable()
export class EmployeeDataService {

    employees: Observable<employee[]>;
    newemployee: Observable<employee>;

    constructor(private http: HttpClient) {

    }

    getEmployee() {
        return this.http.get<employee[]>(ROOT_URL + '/Employees');
    }

    AddEmployee(emp: employee) {

        const headers = new HttpHeaders().set('content-type', 'application/json');
        var body = {
            Fname: emp.Fname, Lname: emp.Lname, Email: emp.Email
        };

        return this.http.post<employee>(ROOT_URL + '/Employees', body, { headers });

    }


    EditEmployee(emp: employee) {
        const params = new HttpParams().set('ID', emp.ID);
        const headers = new HttpHeaders().set('content-type', 'application/json');
        var body = {
            Fname: emp.Fname, Lname: emp.Lname, Email: emp.Email, ID: emp.ID
        };
        return this.http.put<employee>(ROOT_URL + '/Employees/' + emp.ID, body, { headers, params });

    }



    DeleteEmployee(emp: employee) {
        const params = new HttpParams().set('ID', emp.ID);
        const headers = new HttpHeaders().set('content-type', 'application/json');
        var body = {
            Fname: emp.Fname, Lname: emp.Lname, Email: emp.Email, ID: emp.ID
        };
        return this.http.delete<employee>(ROOT_URL + '/Employees/' + emp.ID);

    }
}

This is the Data service class that we use to call the API. Let's see the methods and code descriptions of the methods that are present in this class.

To make the HTTP Client available in the class we have imported the HTTP packages from the common/http package which are as follows.

import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';

In this HTTP client has the HTTP method like get, post, put.

HttpParams for sending the parameter to methods like Put and delete.

Another is the HttpHeaders which we can use to pass the Headers which can be used to pass the values.

Next is as every call to the HTTP client methods returns the Observable so we need to get the Observable package and some Transform methods as well like below.

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/retry';
import 'rxjs/add/observable/of';
import 'rxjs/Rx';

The next section is bringing the Employee model into application along with the App URL constant and @Injectable attribute so that we can inject this class as Dependency Injection to another class,

import { employee } from '../Models/Employee';
import { ROOT_URL } from '../Models/Config';
import { Injectable } from '@angular/core';

After making the class injectable we have Added the Http Client service as a dependency in the application using Constructor in that we have created the private variable HTTP which is of type HttpClient.

The first method we will see is the method getEmployee().

getEmployee() {
  return this.http.get<employee[]>(ROOT_URL + '/Employees');
}

This method returns the Observable of the employee after getting it from the API.

One thing to notice here is that we are directly mapping the Response that we are getting from the API to the employee[] so Http Client allows us to map the response as a typed Response.

The next Method is the AddEmployee.

AddEmployee(emp: employee) {
  const headers = new HttpHeaders().set('content-type', 'application/json');
  var data = { Fname: emp.Fname, Lname: emp.Lname, Email: emp.Email };
  return this.http.post<employee>(ROOT_URL + '/Employees', data, { headers });
}

This method accepts the employee object which is our model object and receiving from the component.

In this Method, we have used the HttpHeaders to set the content type for the request which is application/json. Next, we converted the data from the Employee object in the JSON and then passed it to the Post method of the HTTP which is the verb of the HTTP.

The post method has a signature.

Post(URL, DataBody, {OptionDataLikeHeaders})

Another Operation is the EditEmployee which accepts the employee object as a parameter body of the method as follows.

EditEmployee(emp: employee) {
    const params = new HttpParams().set('ID', emp.ID);
    const headers = new HttpHeaders().set('content-type', 'application/json');
    var body = {
        Fname: emp.Fname,
        Lname: emp.Lname,
        Email: emp.Email,
        ID: emp.ID
    };
}
return this.http.put<employee>(
    ROOT_URL + '/Employees/' + emp.ID,
    body,
    { headers, params }
);

In this method, we need the emp id as a parameter for the operation and we are passing it using the attribute HttpParams . we have set the Headers to the Application/JSON and converted the object to the JSON.

Next is the call the Put method of the http and it accepts the URL along with the Body header and parameter.

The last method to complete our CRUD application is the Delete Method which has the following structure.

DeleteEmployee(emp: employee) {
  const params = new HttpParams().set('ID', emp.ID);
  const headers = new HttpHeaders().set('content-type', 'application/json');
  var body = { Fname: emp.Fname, Lname: emp.Lname, Email: emp.Email, ID: emp.ID };
  return this.http.delete<employee>(ROOT_URL + '/Employees/' + emp.ID);
}

Here we again used the parameter for passing and for the delete the record we have set the headers and called the delete method of the HTTP which will return the observable of the employee type and we can use it in the application

This was about the angular Code that we have used; let’s see some web API code that we will be using in our application.

For this, I have added a new ASP.net core application enabling the web API without going into the details of adding the Web API and the rest of the stuff will demonstrate some basic settings we dd to allow the angular app and avoid any CORS issues that may arise; for that we can check the Startup. cs which is as follows,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.EntityFrameworkCore;

namespace AngularWebAPI
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();
            services.AddCors();
            services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer("Your Connection string"));
            services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder.AllowAnyOrigin()
                                      .AllowAnyMethod()
                                      .AllowAnyHeader()
                                      .AllowCredentials());
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseCorsMiddleware();
            app.UseMvc();
            app.UseCors("CorsPolicy");
        }
    }
}

In this startup, we have added the MVC Entity Framework and other stuff to run the application along with we have added one policy for the CORS which will allow the request from any origin.

Also, we have added one middleware that will handle the incoming request. CORS issues code for the same can be like below.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

public class CorsMiddleware
{
    private readonly RequestDelegate _next;

    public CorsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext httpContext)
    {
        httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
        httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
        httpContext.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept");
        httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
        return _next(httpContext);
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class CorsMiddlewareExtensions
{
    public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<CorsMiddleware>();
    }
}

This is middleware which adds the Headers in the incoming request and adds it in the Request pipeline.

In this API we are Using the Code First Approach of the Entity framework; here our model class will be employee which will be like the below.

namespace AngularWebAPI.Models
{
    public class Employee
    {
        public int ID { get; set; }
        public string Fname { get; set; }
        public string Lname { get; set; }
        public string email { get; set; }
    }
}

Next is Adding the controller which will be a Web API controller and we can use this class to map all the operations and use them accordingly.

namespace AngularWebAPI.Controllers
{
    [Produces("application/json")]
    [Route("api/Employees")]
    public class EmployeesController : Controller
    {
        private readonly ApplicationDbContext _context;

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

        // GET: api/Employees
        [HttpGet]
        public IEnumerable<Employee> Getemployee()
        {
            return _context.employee;
        }

        // GET: api/Employees/5
        [HttpGet("{id}")]
        public async Task<IActionResult> GetEmployee([FromRoute] int id)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var employee = await _context.employee.SingleOrDefaultAsync(m => m.ID == id);

            if (employee == null)
            {
                return NotFound();
            }

            return Ok(employee);
        }

        // PUT: api/Employees/5
        [HttpPut("{id}")]
        public async Task<IActionResult> PutEmployee([FromRoute] int id, [FromBody] Employee employee)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            if (id != employee.ID)
            {
                return BadRequest();
            }

            _context.Entry(employee).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!EmployeeExists(id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return NoContent();
        }

        // POST: api/Employees
        [HttpPost]
        public async Task<IActionResult> PostEmployee([FromBody] Employee employee)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            _context.employee.Add(employee);
            await _context.SaveChangesAsync();

            return CreatedAtAction("GetEmployee", new { id = employee.ID }, employee);
        }

        // DELETE: api/Employees/5
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteEmployee([FromRoute] int id)
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var employee = await _context.employee.SingleOrDefaultAsync(m => m.ID == id);
            if (employee == null)
            {
                return NotFound();
            }

            _context.employee.Remove(employee);
            await _context.SaveChangesAsync();

            return Ok(employee);
        }

        private bool EmployeeExists(int id)
        {
            return _context.employee.Any(e => e.ID == id);
        }
    }
}

This is the web API controller that we use for all the database operations, as we are using the database we can apply the migration and generate the table in the database.

Note. We can use a better approach for handling the database operation like repository and using DTO this is just for the explanation and to check how it works .

When we run the application we can see the output like below.

 output

When we click the Add New it will Open this form.

Add New

The same form will be used for the rest of the Operation.

This was about the using Http Client to read, add, delete and update the employee data in the database. We have used the Asp.net web API core for the Web API we have added the Middleware to avoid the CORS issues in this we have used the EF Code first approach for interacting with the database.

Source code can be found at the following locations.

  1. Angularcode
  2. web API

References

  • https://blog.angularindepth.com/the-new-angular-httpclient-api-9e5c85fe3361
  • https://medium.com/codingthesmartway-com-blog/angular-4-3-httpclient-accessing-rest-web-services-with-angular-2305b8fd654b
  • https://Angular.io