To demonstrate the fundamentals, I have created a table given below to the database. The column Id is defined as Primary and it is auto-incremented.
- CREATE TABLE [dbo].[MyDetails](
- [Id] [int] IDENTITY(1,1) NOT NULL,
- [FirstName] [varchar](50) NULL,
- [LastName] [varchar](50) NULL,
- [AdharNumber] [varchar](50) NULL,
- [Email] [varchar](250) NULL,
- [PhoneNumber] [varchar](50) NULL,
- CONSTRAINT [PK_MyDetails] 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]
The next step is to create an Entity model and an entity.
EntityMoidel.cs
- namespace test
- {
- using Microsoft.EntityFrameworkCore;
-
- public class EntityModelContext : DbContext
- {
- public EntityModelContext(DbContextOptions<EntityModelContext> options) : base(options)
- {
-
- }
- public DbSet<MyDetails> MyDetails { get; set; }
- }
- }
MyDetails.cs
- namespace test
- {
- public class MyDetails
- {
- public int Id { get; set; }
- public string FirstName { get; set; }
- public string LastName { get; set; }
- public string AdharNumber { get; set; }
- public string Email { get; set; }
- public string PhoneNumber { get; set; }
- }
- }
Now, I am adding appsettings.json file, which holds various settings for the Application. I have added the database connection string in this file.
appsettings.json
- {
- "ConnectionStrings": {
- "DefaultConnection": "Data Source=.\\SqlExpress;Initial Catalog=Test;User ID=sa; Password=Passwd@12"
- },
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Debug",
- "System": "Information",
- "Microsoft": "Information"
- }
- }
- }
Next step is to register various Services like MVC, EF in startup class and also configure some global setting such as the connection string assigned to dbcontext.
Startup.cs
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.AspNetCore.SpaServices.Webpack;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Logging;
- using Microsoft.EntityFrameworkCore;
- using Microsoft.EntityFrameworkCore.Infrastructure;
-
- namespace test
- {
- public class Startup
- {
- public Startup(IHostingEnvironment env)
- {
- var builder = new ConfigurationBuilder()
- .SetBasePath(env.ContentRootPath)
- .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
- .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
- .AddEnvironmentVariables();
- Configuration = builder.Build();
- }
-
- public IConfigurationRoot Configuration { get; }
-
-
- public void ConfigureServices(IServiceCollection services)
- {
-
- services.AddMvc();
- services.AddEntityFramework()
- .AddDbContext<EntityModelContext>(
- options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"]));
- }
-
-
- public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
- {
-
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions {
- HotModuleReplacement = true
- });
- }
- else
- {
- app.UseExceptionHandler("/Home/Error");
- }
-
- app.UseStaticFiles();
-
- app.UseMvc(routes =>
- {
- routes.MapRoute(
- name: "default",
- template: "{controller=Home}/{action=Index}/{id?}");
-
- routes.MapSpaFallbackRoute(
- name: "spa-fallback",
- defaults: new { controller = "Home", action = "Index" });
- });
- }
- }
- }
All the configuration related to an entity frame and MVC is done. It now ready to be used for CRUD operation.
In this example, I have created a client side model, which contains all the properties as Server side model (defined in the above section). The definition of client side model is given.
mydetails.model.ts
- export class MyDetails {
- id: number;
- firstName: string;
- lastName: string;
- adharNumber: string;
- email: string;
- phoneNumber: string
- }
I have added MydetailsController class and injected our entity model as a dependency, so that we can perform CRUD operations, using an Entity model.
The code given below is used to retrieve the list of all the available records from the database and get perticular record based on an Id.
MyDetailsController.cs
- using System.Collections.Generic;
- using System.Linq;
- using Microsoft.AspNetCore.Mvc;
-
- namespace test.Controllers
- {
- [Route("api/[controller]")]
- [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]
- public class MyDetailsController : Controller
- {
- private EntityModelContext _context = null;
- public MyDetailsController(EntityModelContext context)
- {
- _context = context;
- }
- [HttpGet("[action]")]
- public List<MyDetails> GetData()
- {
- List<MyDetails> data = null;
- data = _context.MyDetails.ToList();
- return data;
- }
-
- [HttpGet]
- [Route("GetDetails/{id?}")]
- public MyDetails GetDetails(int? id)
- {
- MyDetails data = new MyDetails();
- if (id.HasValue)
- {
- data = _context.MyDetails.Where(p => p.Id == id.Value).FirstOrDefault();
- if (data == null)
- {
- data = new MyDetails();
- }
- }
- return data;
- }
- }
The next step is to create an Angular side Service, which calls this method and passes the collection of data to the component and componet renders this data on to the view. In the Service, I have make a call to Web API methods, using Angular “http” Service.
mydetails.Services.ts
- import { Injectable } from '@angular/core';
- import { Http, Response, RequestOptions, Headers } from '@angular/http';
- import { Observable } from 'rxjs/Observable';
- import 'rxjs/add/operator/map';
-
- import { MyDetails } from './mydetails.model'
-
- @Injectable()
- export class MyDetailService {
-
- public myDetail: MyDetails;
- public headers: Headers
-
- constructor(private http: Http) {
- this.headers = new Headers();
- this.headers.append('Content-Type', 'application/json; charset=utf-8');
- }
-
- getData() {
- return this.http.get('/api/MyDetails/GetData');
- }
-
- getDetail(id: number) {
- return this.http.get('/api/MyDetails/getdetails/' + id);
- }
-
- }
In the component, I have injected the Service “mydetails.Services” as dependency and call the Service methods to retrieve the data.
myDetails.Component.ts
- import { Component } from '@angular/core';
-
- import { MyDetailService } from '../../mydetails.services'
- import { MyDetails } from '../../mydetails.model';
-
- @Component({
- selector: 'mydetail',
- templateUrl: './mydetails.Component.html',
- providers: [MyDetailService],
- styleUrls: ['./myDetails.component.css']
- })
- export class MyDetailsComponent {
- public myDetails: MyDetails[];
-
- constructor(private myDetailService: MyDetailService) {
- this.getListData();
- }
-
- getListData() {
- this.myDetailService.getData().subscribe(data => {
- this.myDetails = null;
- this.myDetails = data.json() as MyDetails[];
- },
- error => console.log(error)
- );
- }
- }
myDetails.Component.html
- <h1>
- List of People
- </h1>
-
- <p *ngIf="!myDetails"><em>Loading...</em></p>
-
- <table class='table' *ngIf="myDetails">
- <thead>
- <tr>
- <td colspan="7">
- <button class="btn btn-primary" [routerLink]="['/detail/0']">
- <span class="glyphicon glyphicon-pencil paddingRight"></span> Add
- </button>
- </td>
- </tr>
- <tr>
- <th>Id</th>
- <th>First Name</th>
- <th>Last Name</th>
- <th>Adhar Number</th>
- <th>Email</th>
- <th>Phone Number</th>
- <th></th>
- </tr>
- </thead>
- <tbody>
- <tr *ngFor="let myDetail of myDetails">
- <td>{{ myDetail.id }}</td>
- <td>{{ myDetail.firstName }}</td>
- <td>{{ myDetail.lastName }}</td>
- <td>{{ myDetail.adharNumber }}</td>
- <td>{{ myDetail.email }}</td>
- <td>{{ myDetail.phoneNumber }}</td>
- <td>
- <button class="btn btn-primary" [routerLink]="['/detail/' + myDetail.id]">
- <span class="glyphicon glyphicon-pencil paddingRight"></span> Edit
- </button>
- <button class="btn btn-primary" (click)="onDelete(myDetail.id)">
- <span class="glyphicon glyphicon-remove"></span> Delete
- </button>
- </td>
- </tr>
- </tbody>
- </table>
Output
To add and edit, I have added another component and its View, as shown below. This component retrieves the data based on an Id from the Web API and the associated data with View.
detail.component.ts
- import { Component } from '@angular/core';
- import { Router, ActivatedRoute, Params } from '@angular/router';
-
- import { MyDetailService } from '../../mydetails.services'
- import { MyDetails } from '../../mydetails.model';
-
- @Component({
- selector: 'detail',
- templateUrl: './detail.Component.html',
- providers: [MyDetailService],
- styleUrls: ['./myDetails.component.css']
- })
- export class DetailComponent {
-
-
- public detail: MyDetails = new MyDetails();
- private id: number;
- constructor(private myDetailService: MyDetailService, private route: ActivatedRoute, private redirect: Router) {
-
- this.route.params.subscribe((params: Params) => {
- this.id = params['id'];
- console.log(this.id)
- });
-
- this.myDetailService.getDetail(this.id).subscribe(data => {
- this.detail = null;
- this.detail = data.json();
- },
- error => console.log(error)
- );
- }
- }
detail.component.html
- <div class="row margin-top-05">
- <h1>Add / Edit Detail</h1>
- </div>
- <div class="margin-top-05">
- <div class="row margin-top-05">
- <div class="col-xs-2"><strong> First Name : </strong></div>
- <div class="col-xs-6"><input [(ngModel)]="detail.firstName" required /> </div>
- </div>
- <div class="row margin-top-05">
- <div class="col-xs-2"><strong> Last Name : </strong></div>
- <div class="col-xs-6"><input [(ngModel)]="detail.lastName" /> </div>
- </div>
- <div class="row margin-top-05">
- <div class="col-xs-2"><strong> Adhar Number : </strong></div>
- <div class="col-xs-6"><input [(ngModel)]="detail.adharNumber" /> </div>
- </div>
- <div class="row margin-top-05">
- <div class="col-xs-2"><strong> Email : </strong></div>
- <div class="col-xs-6"><input [(ngModel)]="detail.email" /> </div>
- </div>
- <div class="row margin-top-05">
- <div class="col-xs-2"><strong> Phone Number : </strong></div>
- <div class="col-xs-6"><input [(ngModel)]="detail.phoneNumber" /> </div>
- </div>
- <div class="row margin-top-05">
- <div class="col-xs-12">
- <button class="btn btn-primary" (click)="save()">
- <span class="glyphicon glyphicon-saved"></span> Save
- </button>
- <button class="btn btn-primary" (click)="list()">
- <span class="glyphicon glyphicon-list"></span> List
- </button>
- </div>
- </div>
- </div>
To perform add and edit operation, I have added the methods given below to component class, which is called on the click of Save button click. This function internally calls Service “postData” method. This postData method posts the data to the Web API, using Angular http Service.
detail.component.ts
- save() {
- this.myDetailService.postData(this.detail)
- .subscribe(
- (response) => {
- console.log(response);
- this.list();
- },
- (error) => console.log(error)
- );
- }
mydetails.Services.ts
- postData(detail: MyDetails) {
- return this.http.post('/api/MyDetails/Save', detail);
- }
MyDetailsController.cs
- [HttpPost("[action]")]
- public IActionResult Save([FromBody] MyDetails myDetail)
- {
- bool isNew = false;
- MyDetails data = _context.MyDetails.Where(p => p.Id == myDetail.Id).FirstOrDefault();
- if (data == null)
- {
- data = new MyDetails();
- isNew = true;
- }
- data.FirstName = myDetail.FirstName;
- data.LastName = myDetail.LastName;
- data.AdharNumber = myDetail.AdharNumber;
- data.Email = myDetail.Email;
- data.PhoneNumber = myDetail.PhoneNumber;
- if (isNew)
- {
- _context.Add(data);
- }
- _context.SaveChanges();
- return Ok(data);
- }
I have used the code given above to insert or update the data into the database. If the record is found in the database, then perform an update operation, else perform an add operation.
Once the data is committed to the database, system will redirect to the list page. Using the code given below, we can do redirection. I have added this function to detail.component.
detail.component.ts
- list() {
- this.redirect.navigateByUrl('/my-detail');
- }
To perform delete operation, I have added the code given below to Web API. This method only accepts an Id as a parameter and it deletes the data from the database, which is based on an id.
MyDetailsController.cs
- [HttpDelete("[action]")]
- public IActionResult Delete([FromBody] int id)
- {
- MyDetails data = _context.Set<MyDetails>().FirstOrDefault(c => c.Id == id);
- _context.Entry(data).State = Microsoft.EntityFrameworkCore.EntityState.Deleted;
- _context.SaveChanges();
- return Ok(true);
- }
I have added function given below to the Service and the component to perform delete operation.
mydetails.Services.ts
- deleteData(id: number) {
- return this.http.delete('/api/MyDetails/Delete/', new RequestOptions({
- headers: this.headers,
- body: id
- }));
- }
mydetails.Component.ts
- onDelete(id: number) {
- this.myDetailService.deleteData(id).subscribe(data => {
- this.getListData();
- },
- error => console.log(error)
- );
- }
After the successful deletion, I just call the list method to synchronize up the list data on the page.
Summary
In this article, we learned how to do CRUD operation, using ASP.NET MVC Core and Angular 2.