Introduction
In this session, we will learn,
- How to consume Todo in-memory database using TodoRepository.
- How to create custom ASP.NET custom API controller with CRUD operations.
- List of Objects
- Create a new insert item
- Update an Item
- Delete an Item
- Write HttpPost Create API method
- Write HttpPut Edit API method.
- Write HttpPost Delete API method.
- Loose Coupling
- Dependency Injection
- Singleton
- Route
- Responsive Web Design
A lab exercise for you to demonstrate what have you learned from this training material to create your own Employee CRUD operation using EmployeeRepository included in this training material.
Pre-Requirements
In order to be able to run the example from the download or build it from scratch, you need to have the following tools,
- Visual Studio 2017 latest version
- .NET Core 2.0 or above
- TypeScript 1.8 or above
- Node.js
- Angular 4.0 or above
Create a new solution and name it TodoAspNetCoreMvcAngular4Vs2017Solution
Add a new ASP.NET Core Web Application project and name it TodoAngular.Ui
Visual Studio 2017 ASP.NET Core 2.0 comes with an Angular project template.
Next screen select Angular Web Application project template.
Compile and run the application and we’ll see the home page.
Lets change to home page content
Go to the home.component.html in the ClientApp directory.
Replace the home content with below lines when the project is still running. Angular has change detection functionally and reflects your changes on the running application.
Home content will change on the run time.
<h1>To-do Angular 4.0 .NETCore CRUD Application </h1>
<p>Provided by -SmartIT, John Kocer!</p>
We want to create below single page application with CRUD operation, Add, Update and Remove functionality with in-memory TodoRepository Database.
We need to do below tasks,
- Set TodoRepository
- Create TodoController
- Add Dependency Injection
- Create todoService.ts
- Create todo.component.html
- Create todo.component.ts
- Add new created component into ApModule
- Update Angular routing to go Todo page.
Set TodoRepository
Use SmartIT.Employee.MockDB which has TodoRepository in it with in-memory MOCK database which has dependency injection interfaces implemented . You may go to below web site and read the usage examples.
https://www.nuget.org/packages/SmartIT.Employee.MockDB/
Use Nuget Package manager to Install SmartIT.Employee.MockDB from nugget.org.
Create TodoController
On the controllers directory add a new controller select Full Dependencies and Add.
Select API Controler with read/write actions from the list and click Add
Name it TodoController and Click Add.
TodoController will be created.
- namespace TodoAngular.Ui.Controllers
- {
- [Produces("application/json")]
- [Route("api/Todo")]
- public class TodoController : Controller
- {
-
- [HttpGet]
- public IEnumerable<string> Get()
- {
- return new string[] { "value1", "value2" };
- }
-
-
- [HttpGet("{id}", Name = "Get")]
- public string Get(int id)
- {
- return "value";
- }
-
-
- [HttpPost]
- public void Post([FromBody]string value)
- {
- }
-
-
- [HttpPut("{id}")]
- public void Put(int id, [FromBody]string value)
- {
- }
-
-
- [HttpDelete("{id}")]
- public void Delete(int id)
- {
- }
- }
- }
Add Dependency Injection
Go to the Startup page ConfigureServices method
- public class Startup
- {
- public Startup(IConfiguration configuration)
- {
- Configuration = configuration;
- }
-
- public IConfiguration Configuration { get; }
-
-
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddMvc();
- }
Add the SmartIT.Employee.MockDB using statement top of the Startup page.
- using SmartIT.Employee.MockDB;
Add the AddSigleton service. Why we chose as Sigleton? Because our service is an In-memory repository data services. We want only a single instance will be created.
- services.AddSingleton<ITodoRepository, TodoRepository>();
-
- using SmartIT.Employee.MockDB;
-
- namespace TodoAngular_Ui
- {
- public class Startup
- {
- public Startup(IConfiguration configuration)
- {
- Configuration = configuration;
- }
-
- public IConfiguration Configuration { get; }
-
-
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddMvc();
- services.AddSingleton<ITodoRepository, TodoRepository>();
- }
Add top of the TodoController page
using SmartIT.Employee.MockDB;
Add private readonly ITodoRepository _todoRepository; readonly ItodoRepositor Interface member.
Add a Todo Constructor
- using SmartIT.Employee.MockDB;
-
- namespace TodoAngular.Ui.Controllers
- {
- [Produces("application/json")]
- [Route("api/Todo")]
- public class TodoController : Controller
- {
- private readonly ITodoRepository _todoRepository;
- public TodoController(ITodoRepository todoRepository)
- {
- _todoRepository = todoRepository;
- }
Add GetAllTodos Httpget mehot with [Route("~/api/GetAllTodos")]
Here is the final changes in below on the TodoController
- using SmartIT.Employee.MockDB;
-
- namespace TodoAngular.Ui.Controllers
- {
- [Produces("application/json")]
- [Route("api/Todo")]
- public class TodoController : Controller
- {
- private readonly ITodoRepository _todoRepository;
- public TodoController(ITodoRepository todoRepository)
- {
- _todoRepository = todoRepository;
- }
-
- [Route("~/api/GetAllTodos")]
- [HttpGet]
- public IEnumerable<Todo> GetAllTodos()
- {
- return _todoRepository.GetAll();
- }
Compile and run the application.
Test get all todos with calling to API
http://localhost:61190/api/GetAllTodos
Note
Your port number may be different than ours, use your local port number.
Update the remainder of the TodoController like below.
- using System.Collections.Generic;
- using Microsoft.AspNetCore.Mvc;
- using SmartIT.Employee.MockDB;
-
- namespace TodoAngular.Ui.Controllers
- {
- [Produces("application/json")]
- [Route("api/Todo")]
- public class TodoController : Controller
- {
- private readonly ITodoRepository _todoRepository;
- public TodoController(ITodoRepository todoRepository)
- {
- _todoRepository = todoRepository;
- }
-
- [Route("~/api/GetAllTodos")]
- [HttpGet]
- public IEnumerable<Todo> GetAllTodos()
- {
- return _todoRepository.GetAll();
- }
-
- [Route("~/api/AddTodo")]
- [HttpPost]
- public Todo AddTodo([FromBody]Todo item)
- {
- return _todoRepository.Add(item);
- }
-
- [Route("~/api/UpdateTodo")]
- [HttpPut]
- public Todo UpdateTodo([FromBody]Todo item)
- {
- return _todoRepository.Update(item);
- }
-
- [Route("~/api/DeleteTodo/{id}")]
- [HttpDelete]
- public void Delete(int id)
- {
- var findTodo = _todoRepository.FindById(id);
- if (findTodo != null)
- _todoRepository.Delete(findTodo);
- }
- }
- }
Create todoService.ts
Add a Todo folder under components directory.
Add a TypeScript file todoService.ts into Todo directory.
yo
Paste the below code into your todoService.ts
- import { Injectable } from "@angular/core";
- import { Http, Response, Headers } from "@angular/http";
- import "rxjs/add/operator/map";
- import 'rxjs/add/operator/do';
- import { Observable } from "rxjs/Observable";
- import { BehaviorSubject } from 'rxjs/BehaviorSubject';
-
- @Injectable()
- export class TodoService {
-
- public todoList: Observable<Todo[]>;
- private _todoList: BehaviorSubject<Todo[]>;
- private baseUrl: string;
- private dataStore: {
- todoList: Todo[];
- };
-
- constructor(private http: Http) {
- this.baseUrl = '/api/';
- this.dataStore = { todoList: [] };
- this._todoList = <BehaviorSubject<Todo[]>>new BehaviorSubject([]);
- this.todoList = this._todoList.asObservable();
- }
-
- getAll() {
- this.http.get(`${this.baseUrl}GetAllTodos`)
- .map(response => response.json())
- .subscribe(data => {
- this.dataStore.todoList = data;
- this._todoList.next(Object.assign({}, this.dataStore).todoList);
- }, error => console.log('Could not load todo.'));
- }
- public addTodo(newTodo: Todo) {
- console.log("addTodo");
- var headers = new Headers();
- headers.append('Content-Type', 'application/json; charset=utf-8');
- console.log('add todo : ' + JSON.stringify(newTodo));
-
-
- this.http.post(`${this.baseUrl}AddTodo/`, JSON.stringify(newTodo), { headers: headers })
- .map(response => response.json()).subscribe(data => {
- this.dataStore.todoList.push(data);
- this._todoList.next(Object.assign({}, this.dataStore).todoList);
- }, error => console.log('Could not create todo.'));
- };
-
- public updateTodo(newTodo: Todo) {
- console.log("updateTodo");
- var headers = new Headers();
- headers.append('Content-Type', 'application/json; charset=utf-8');
- console.log('add todo : ' + JSON.stringify(newTodo));
-
-
- this.http.put(`${this.baseUrl}UpdateTodo/`, JSON.stringify(newTodo), { headers: headers })
- .map(response => response.json()).subscribe(data => {
- this.dataStore.todoList.forEach((t, i) => {
- if (t.id === data.id) { this.dataStore.todoList[i] = data; }
- });
- }, error => console.log('Could not update todo.'));
- };
-
- removeItem(todoId: number) {
- var headers = new Headers();
- headers.append('Content-Type', 'application/json; charset=utf-8');
- console.log("removeItem:" + todoId);
- this.http.delete(`${this.baseUrl}DeleteTodo/${todoId}`, { headers: headers }).subscribe(response => {
- this.dataStore.todoList.forEach((t, i) => {
- if (t.id === todoId) { this.dataStore.todoList.splice(i, 1); }
- });
-
- this._todoList.next(Object.assign({}, this.dataStore).todoList);
- }, error => console.log('Could not delete todo.'));
- }
- private _serverError(err: any) {
- console.log('sever errorOK:', err);
- if (err instanceof Response) {
- return Observable.throw(err.json().error || 'backend server error');
-
-
-
- }
- return Observable.throw(err || 'backend server error');
- }
- }
-
- export class Todo {
- public id: number;
- public name: string;
- }
Create todo.component.html
Add an HTML page into Todo directory and name it todo.component.html
Paste the below code in your todo.component.html
- <div id="summary" class="section panel panel-primary">
- <div class="panel-heading"> Todo Summary</div>
- <div class="container">
- <!--{{todoList | json}}-->
- <table class="table table-striped table-condensed" >
- <thead>
- <tr>
- <th>Id</th>
- <th>Name</th>
- <th></th>
- </tr>
- <tr>
- <th> </th>
- <th>
- <input id="newName" [(ngModel)]='newTodo.name' type="text" placeholder="newName" />
- </th>
- <th>
- <button class="btn btn-primary" (click)="addTodo(newTodo)">Add </button>
- </tr>
- </thead>
- <tbody *ngFor="let item of todoList | async">
- <tr>
- <td>{{item.id}} </td>
- <td><input type="text" [(ngModel)]='item.name' /></td>
- <td>
- <button class="btn btn-xs btn-primary" (click)="updateTodo(item)">Update</button>
- </td>
- <td>
- <button class="btn btn-xs btn-primary" (click)="deleteTodo(item.id)">Remove</button>
- </tr>
- </tbody>
- </table>
-
- </div>
- </div>
Create todo.component.ts
Add TypeScript file called to.component.ts into Todo directory.
Paste below code into your to.component.ts .
- import { Component, OnInit } from '@angular/core';
- import 'rxjs/add/operator/catch';
- import { TodoService } from "./todoService";
- import { Observable } from "rxjs/Observable";
- import { Todo } from "./todoService"
-
- @Component({
- selector: 'todo',
- providers: [TodoService],
- templateUrl: './todo.component.html'
- })
- export class TodoComponent implements OnInit {
- public todoList: Observable<Todo[]>;
-
- showEditor = true;
- myName: string;
- newTodo: Todo;
- constructor(private dataService: TodoService) {
- this.newTodo = new Todo();
- }
-
- ngOnInit() {
-
- this.todoList = this.dataService.todoList;
- this.dataService.getAll();
- }
- public addTodo(item: Todo) {
-
- let todoId = this.dataService.addTodo(this.newTodo);
- }
- public updateTodo(item: Todo) {
-
-
- this.dataService.updateTodo(item);
-
- }
- public deleteTodo(todoId: number) {
- this.dataService.removeItem(todoId);
- }
- }
Add new created component into ApModule
- import { CounterComponent } from './components/counter/counter.component';
- import { TodoComponent } from './components/todo/todo.component';
-
- @NgModule({
- declarations: [
- AppComponent,
- NavMenuComponent,
- CounterComponent,
- FetchDataComponent,
- HomeComponent,
- TodoComponent
- ],
- imports: [
- CommonModule,
- HttpModule,
- FormsModule,
- RouterModule.forRoot([
- { path: '', redirectTo: 'home', pathMatch: 'full' },
- { path: 'todo', component: TodoComponent },
- { path: 'home', component: HomeComponent },
- { path: 'counter', component: CounterComponent },
- { path: 'fetch-data', component: FetchDataComponent },
- { path: '**', redirectTo: 'home' }
- ])
- ]
- })
- export class AppModuleShared {
Lets update the menu
Change this line from <a class='navbar-brand' [routerLink]="['/home']">TodoAngular_Ui</a>
To <a class='navbar-brand' [routerLink]="['/home']">SmartIT by John Kocer</a>
Add new menu Item Todo
- <li [routerLinkActive]="['link-active']">
- <a [routerLink]="['/todo]">
- <span class='glyphicon glyphicon-user'></span> Todo
- </a>
- </li>
Here is updated menu
- <div class='main-nav'>
- <div class='navbar navbar-inverse'>
- <div class='navbar-header'>
- <button type='button' class='navbar-toggle' data-toggle='collapse' data-target='.navbar-collapse'>
- <span class='sr-only'>Toggle navigation</span>
- <span class='icon-bar'></span>
- <span class='icon-bar'></span>
- <span class='icon-bar'></span>
- </button>
- <a class='navbar-brand' [routerLink]="['/home']">SmartIT by John Kocer</a>
- </div>
- <div class='clearfix'></div>
- <div class='navbar-collapse collapse'>
- <ul class='nav navbar-nav'>
- <li [routerLinkActive]="['link-active']">
- <a [routerLink]="['/todo']">
- <span class='glyphicon glyphicon-user'></span> Todo
- </a>
- </li>
-
- <li [routerLinkActive]="['link-active']">
- <a [routerLink]="['/home']">
- <span class='glyphicon glyphicon-home'></span> Home
- </a>
- </li>
- <li [routerLinkActive]="['link-active']">
- <a [routerLink]="['/counter']">
- <span class='glyphicon glyphicon-education'></span> Counter
- </a>
- </li>
- <li [routerLinkActive]="['link-active']">
- <a [routerLink]="['/fetch-data']">
- <span class='glyphicon glyphicon-th-list'></span> Fetch data
- </a>
- </li>
- </ul>
- </div>
- </div>
- </div>
Update the RouteModule
- RouterModule.forRoot([
- { path: '', redirectTo: 'home', pathMatch: 'full' },
- { path: 'todo', component: TodoComponent },
- { path: 'home', component: HomeComponent },
- { path: 'counter', component: CounterComponent },
- { path: 'fetch-data', component: FetchDataComponent },
- { path: '**', redirectTo: 'home' }
- ])
Here is the updated RouteModule
- import { NgModule } from '@angular/core';
- import { CommonModule } from '@angular/common';
- import { FormsModule } from '@angular/forms';
- import { HttpModule } from '@angular/http';
- import { RouterModule } from '@angular/router';
-
- import { AppComponent } from './components/app/app.component';
- import { NavMenuComponent } from './components/navmenu/navmenu.component';
- import { HomeComponent } from './components/home/home.component';
- import { FetchDataComponent } from './components/fetchdata/fetchdata.component';
- import { CounterComponent } from './components/counter/counter.component';
- import { TodoComponent } from './components/todo/todo.component';
-
- @NgModule({
- declarations: [
- AppComponent,
- NavMenuComponent,
- CounterComponent,
- FetchDataComponent,
- HomeComponent,
- TodoComponent
- ],
- imports: [
- CommonModule,
- HttpModule,
- FormsModule,
- RouterModule.forRoot([
- { path: '', redirectTo: 'todo', pathMatch: 'full' },
- { path: 'todo', component: TodoComponent },
- { path: 'home', component: HomeComponent },
- { path: 'counter', component: CounterComponent },
- { path: 'fetch-data', component: FetchDataComponent },
- { path: '**', redirectTo: 'todo' }
- ])
- ]
- })
- export class AppModuleShared {
- }
Here is the final result of responsive web design result.
Summary
In this article, we will learned,
- How to consume Todo in-memory database using TodoRepository.
- How to create custom ASP.NET MVC custom controller with CRUD operations.
- List of Objects
- Create a new insert object
- Update an item
- Delete an Item
- Write HttpPost Create API method.
- Write HttpPut Edit API method.
- Write HttpPost Delete API method.
- Loose Coupling
- Dependency Injection
- Singleton
- Route
- Responsive Web Design
Lab Exercise
A lab exercise for you to demonstrate what have you learned from this training material to create your own Employee Angular CRUD Responsive Design SPA application. The EmployeeRepository included in this training material.
You can follow above steps to create your own Employee CRUD ASP.NET MVC Angular 4.0 application.
-
- EmployeeRepository _employeeRepository= new EmployeeRepository();
- _employeeRepository.Add(new Employee() { Name = "Mat Stone", Gender = "Male", DepartmentId = 2, Salary = 8000 });
- _employeeRepository.CDump("Employees");
-
-
-
-
-
For ASP.NET MVC Core Angular 4 CRUD Application
NOTE
If you need to copy and paste the code download the pdf file locally.
Download source code from GitHub.