Angular 2 with ASP.NET Core Web API – Build a simple Notebook app – Part 1

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:

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:

To install

Here are all the things needed to be installed locally:

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);
    
  • Angular 2 modules and the new NgModule decorator let us declare in one place all the dependencies and components of our application without the need to do it on a per-component basis (like we used to in previous versions). Here we tell that component App should be loaded first.
  • @NgModule({
        imports: [BrowserModule],
        declarations: [App],
        bootstrap: [App]
    })
    
    export class AppModule { }
    
  • The component is a reusable piece of UI, displayed by a custom html element. It is self contained and is constituted by at least a piece of html code that is known as template, a class that encapsulates the data and interactions available to that template, and the aforementioned html element also known selector.
  • @Component({
        selector: 'notes-app',
        template: `<div>
                  <h2>NotebookApp with {{name}}</h2>
                   </div>`
    })
    
    export class App {
        name: string;
        constructor() {
            this.name = 'Angular 2';
        }
    }
    
  • To be displayed, we include the new HTML tag in the ASP.NET Core View
  • <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;
    } 
    
  • and then make it available as a provider, in the module configuration
  • @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. Once the details are received asynchronously, we fill in the local variable myItems.

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.

Product lead, software developer & architect

3 comments On Angular 2 with ASP.NET Core Web API – Build a simple Notebook app – Part 1

Leave a reply:

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.