This article presents a step by step approach to create an Angular2 application, consuming an ASP.NET Core REST WebAPI. It continues the earlier post Using MongoDB with ASP.NET Core WebAPI and presents a gentle introduction to Angular 2 framework.
This is the first part and the scope of the series is to present step by step how to build
a web application to store your ideas in an easy way, adding text notes, either from desktop or mobile, with few characteristics: run fast, save on the fly whatever you write, and be reasonably reliable and secure.
Topics covered:
- Angular 2 Module
- Angular 2 Component
- Angular 2 Dependency Injection
- Angular 2 Lifecycle
- Angular 2 Service and Observable
- Make an Angular 2 application connected to an ASP.NET Core WebApi project
Why choosing Angular 2 ?
Angular2 is a framework that provides lots of functionality out of the box. It has libraries for routing, webapi calls, dependency management and so on. Angular2 has also embraced TypeScript. TypeScript is a superset of JavaScript. It is very well integrated with Visual Studio, helping while you type with suggestions, and spotting errors as you type the code.
New version of Angular provides a more consistent and compact development experience. It’s also faster, provides server-side rendering out of the box, is cross-platform, supports legacy browsers, etc, etc.
Live code samples using Plunker
Even if Angular 2 framework has advantages, starting a solution combined with ASP.NET Core seems difficult at the beginning. To make things easier, each section comes together with a live Angular 2 sample. These evolve from a simple “hello world” type, to reading the data from WebAPI. You could view them while reading the article, or quick access from this summary:
- Preview A – Angular 2 – Starter application This is just a Hello world application using Angular 2.
- Preview B – Angular 2 – First component This makes the first Angular2 component, display few notes.
- Preview C – Angular 2 – Injectable Dependency injection in Angular 2.
- Preview D – Angular 2 – Connect to a REST WebAPI This retrieves and display the notes from a WebAPI.
Easy access the code
The blog starts, with a pre-configured ASP.NET Core solution, and finalizes with an application that connects to WebAPI. You can access both projects, using the link below:
- Download the starter project (Github).
- Download the project, including all code samples presented here (GitHub).
To install
Here are all the things needed to be installed locally:
- Visual Studio Community 2015 and then Visual Studio 2015 Update 3 and .NET Core 1.0.1 – VS 2015 Tooling Preview 2. Update 3 is better, because it fixes some issues with NPM, plus it’s a prerequisite for TypeScript 2.0.
- NPM
Getting Started With Angular 2 and TypeScript
The best way to get started learning Angular 2 and TypeScript is to clone an application starter, a minimalist Angular 2 app that has the full set up for Angular 2, with TypeScript and the module loader.
First things first. Once all the items presented above are installed, we would need to be sure that node and npm versions are correct. The Angular 2 runs with node v4.x.x or higher and npm 3.x.x or higher.
To be able to check the version, I have opened a command prompt and ran:
c:\windows\system32>npm --version 3.10.8 c:\windows\system32>node --version v6.9.1
My local settings fulfill the minimum requirements. If you have issues with the npm version, please refer to next article.
Once these versions are correct, we could further proceed to clone the initial project from Github (or simpler download it).
Last thing before opening the initial solution, would be to install Gulp. Run this command in command prompt, in the project folder:
npm install gulp --save-dev
This command will install locally Gulp. The starting project has all the configurations in place, with a fully configured Gulp file.
Open the solution in Visual Studio. Depending on the speed of the internet connection, it could take a little while to download locally all the required packages. Once these are complete, probably in few minutes, build the solution and run it.
Here are the files added or updated, enabling us to run Angular 2 with an ASP.NET Core MVC
// Angular 2 source code details - app folder # Angular2 source folder - /css & /js # Folders for CSS & additional Java script files - note.app.module.ts # The Angular module & sample component // ASP.NET Core - Updated files - Controllers/HomeController.cs # Default ASP.NET MVC Controller, at the beginning with no change - Views/Home/Index.cshtml # Default ASP.NET MVC View, loads the Angular2 module - Startup.cs # Make the static files servable // TypeScript configuration - gulpfile.js # Gulp configuration file for automating the deployment flow - hosting.js # Configuration file added to run the application on a specific port - package.json # NPM could identify the project as well as handle the project's dependencies. - systemjs.config.js # Allows to configure SystemJS to load modules compiled using the TypeScript compiler. - tsconfig.json # TypeScript compiler configuration - typings.json # TypesScript declaration files
Module, Bootstrapping, Components
- In Angular 1 we used the ng-app directive to point Angular to the starting point of your application. In Angular 2 we use a bootstrapper. Angular 2 is platform agnostic. We can run it in the browser, but we could also run on a web worker, in the server and potentially native in mobile devices using different bootstrappers.
platformBrowserDynamic().bootstrapModule(AppModule);
@NgModule({ imports: [BrowserModule], declarations: [App], bootstrap: [App] }) export class AppModule { }
@Component({ selector: 'notes-app', template: `<div> <h2>NotebookApp with {{name}}</h2> </div>` }) export class App { name: string; constructor() { this.name = 'Angular 2'; } }
<notes-app></notes-app> <script> System.import('dist/note.app.module') .catch(function (err) { console.error(err); }); </script>
You can see the results by running the solution, or use first sample from Plunker: Preview A – Angular 2 – Starter application
Adding the first component: Listing the notes
The first thing that we are going to do is not going to require services, not yet. We are going to create our first component to display a list of notes and we will start faking out that data.
It’s good practice to start by defining the domain model of our problem space, in this case a NoteItem. We’ll take advantage of TypeScript interface and create a NoteItem within the noteModel.ts file. To keep the things simple, we will have all the fields, including date, as strings for the moment. Component is named: NotesComponent
export interface NoteItem { Id: string, Body: string, UpdatedOn: string, CreatedOn: string, UserId: number }
To iterate through a list of notes, we will use *ngFor, which is a repeater directive. The code snippet will show like this
<ul> <li *ngFor="let note of noteItems"> {{note.Body}} </li> </ul>
And now we update the component NotesComponent and display the data
import { Component } from '@angular/core' import { NoteItem } from './note.model' @Component({ selector: 'notes-app', template: ` <ul> <li *ngFor="let note of noteItems"> {{note.Body}} </li> </ul> ` }) export class NotesComponent { noteItems: NoteItem[] = [ {Id:'1', Body: 'First note', UpdatedOn: '2016-11-21 10:20:23', CreatedOn: '2016-11-21 10:20:23', UserId: 1}, {Id:'2', Body: 'Second note with more details', UpdatedOn: '2016-11-21 10:20:23', CreatedOn: '2016-11-21 10:20:23', UserId: 1}, {Id:'3', Body: 'Third note, and the last sample', UpdatedOn: '2016-11-21 10:20:23', CreatedOn: '2016-11-21 10:20:23', UserId: 1}, ]; }
You can see the same Angular 2 code in Plunker: Preview B – Angular 2 – First component.
Dependency Injection and common settings
To easier to present the Dependency Injection (DI) in Angular 2, let’s use a common settings class, that needs to be accessed by other components. The way it is built could be further extended (ex: read from a configuration file), but the simpler model helps us better to present the Dependency injection in Angular 2.
Let’s start from a simple class:
export class Configuration { public ApiServer: string = "http://localhost:6001/"; public ApiUrl: string = "api/notes"; public ServerWithApiUrl: string = this.ApiServer + this.ApiUrl; }
To make it accessible by other components via DI, we make two changes:
- Make the class injectable
import { Injectable } from '@angular/core'; @Injectable() export class Configuration { public ApiServer: string = "http://localhost:6001/"; public ApiUrl: string = "api/notes"; public ServerWithApiUrl: string = this.ApiServer + this.ApiUrl; }
@NgModule({ imports: [BrowserModule], declarations: [NotesComponent], providers: [Configuration], bootstrap: [NotesComponent] })
These updates allow us to inject Settings, via constructor, into our component.
export class NotesComponent { constructor(private _dataService: NoteService) { }
See this live in Plunker: Preview C – Angular 2 – Injectable
Using Angular 2 component lifecycle
When a component is created, its constructor is called, and we initialize our component. If we rely on properties or data from other components, then we need to wait for the other components to initialize first. To be able to do this we use ngOnInit lifecycle. This will allow us to call the WebApi, whenever this service is initialized.
import { Component, OnInit } from '@angular/core'; ... export class NotesComponent implements OnInit { ngOnInit() { // access the WebAPI service } }
Creating an Angular 2 service
Angular 2 Service is just an ES6 class that encapsulates functionality. It is used by the rest of the application, and it is referred as a service.
In the example below, we create a service that uses a native Angular 2 http service, and allow us to receive the json details. The class is also marked as injectable to be easier accessed and used.
import { Injectable } from "@angular/core"; import { Http } from "@angular/http"; import "rxjs/add/operator/map"; import { Observable } from "rxjs/Observable"; import { NoteItem } from "../../models/note/noteModel"; import { Configuration } from "../../app.constants"; @Injectable() export class NoteService { constructor(private _http: Http, private _configuration: Configuration) { } public getAll = (): Observable<NoteItem[]> => { return this._http.get(this._configuration.ServerWithApiUrl) .map(data => data.json()); }; }
We use more terms in the above code snippet, and here are few details:
- Angular 2 http client service provides the support to make HTTP requests, and comes with all methods corresponding to HTTP verbs like: get, post, put etc.
- Observable is the asynchronous pattern used in Angular 2. The concept of observable comes from the observer design pattern as an object that notifies interested set of observers when something happens. In RxJs it has been generalized to manage sequences of data or events, to become composable with other observables and to provide a lot of utility functions known as operators.
- map transforms the items within a sequence into the domain model of our application – in our case noteItems.
To use the pattern, we should subscribe to the observable. We do this with .subscribe to Observable
export class NotesComponent implements OnInit { public myItems: NoteItem[]; constructor(private _dataService: NoteService) { } ngOnInit() { this._dataService .getAll() .subscribe((data: NoteItem[]) => this.myItems = data, () => console.log("getAllItems() complete from init")); } }
Making just a retrieval (GET), we could simulate the external service by reading a JSON file. See in Plunker the concept of Angular 2 service: Preview D – Angular 2 service connected to a REST WebAPI.
Error handling with Observables
First level of error handling should happen at the service level. At this lower level could be managed problems related to HTTP requests. In this simple application, we will just log the error, and transform it into an application level error:
export class NotesComponent implements OnInit { public myItems: NoteItem[]; constructor(private _dataService: NoteService) { } ngOnInit() { this._dataService .getAll() .subscribe((data: NoteItem[]) => this.myItems = data) .catch(handleException) () => console.log("getAllItems() complete from init")); } } function handleException(error: any) { // log error let errorMsg = error.message || `Problem accessing the data!` console.error(errorMsg); // throw an application level error return Observable.throw(errorMsg); }
Let’s add an internal rest service, using an ASP.NET Core WebAPI controller
Before accessing the other ASP.NET Core project, we could easily simulate by adding a new controller in our ASP.NET project. This helps us to easier run and test, using a single solution. The full source code of this controller is included here (you could also download the full project).
using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; namespace NotebookAppWeb.Controllers { [Produces("application/json")] [Route("api/[controller]")] public class NotesController : Controller { private class NoteItem { public string Id; public string Body; public string UpdatedOn; public string CreatedOn; public int UserId; } // GET: api/values [HttpGet] public string Get() { NoteItem[] arrayOfNotes = new NoteItem[] { new NoteItem() { Id = "1", Body = "Hello note !", UpdatedOn = "2016-11-16 10:50:23", CreatedOn = "2016-11-16 10:50:23", UserId = 1 }, new NoteItem() { Id = "2", Body = "Hello 2 should come after", UpdatedOn = "2016-11-16 10:50:23", CreatedOn = "2016-11-16 10:50:23", UserId = 2 }, new NoteItem() { Id = "3", Body = "Hello 3 should come latest", UpdatedOn = "2016-11-17 10:50:23", CreatedOn = "2016-11-17 10:50:23", UserId = 3 }}; return JsonConvert.SerializeObject(arrayOfNotes); } } }
Putting things together
We can now create an application, which connect all the concepts presented above and simulate a basic Notebook application. This application connects to local controller as a REST service (Web API controller), and then display the notes received.
Download the full ASP.NET Core project (GitHub).
Connecting to the project ASP.NET Core WebAPI and MongoDB
Connect to the ASP.NET Core WebAPI project. Open the Github page – https://github.com/fpetru/WebApiMongoDB, and in the project description you can find how to run the project.
Once this is setup, change the configurations to point to this REST service (instead of using local controller). Run the project.
What’s next
This will continue with a new part, presenting all the actions on the notes. We will be able then to add, edit or remove notes.
3 comments On Angular 2 with ASP.NET Core Web API – Build a simple Notebook app – Part 1
thank you for your good article.
Thanks for reading it 😉 I agree with your comment.
Good article, it helped me recap the concepts, the plunker samples are great. Angular 2 is awsome but many moving parts go into it. I consider looking into Ionic 2, a mobile framework based on Angular 2 and Cordova. But picking which technology to invest time in is difficult these days with the plethora of choices