Click here to Skip to main content
15,885,985 members
Articles / Web Development / HTML

Angular 2 with ASP.NET Core Web API – Build a Simple Notebook App – Part 1

Rate me:
Please Sign up or sign in to vote.
4.67/5 (5 votes)
24 Nov 2016CPOL9 min read 38.5K   824   17   2
Build step by step an Angular 2 application running on IIS and ASP.NET Core. The project also has live samples. This is the first part of building an Angular 2 Notebook WebApp.

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 Choose 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.

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 to 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 the 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 locally download all the required packages. Once these are complete, probably in a 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 file

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.
    JavaScript
    platformBrowserDynamic().bootstrapModule(AppModule);
  • Angular 2 modules and the new NgModule decorator lets 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.
    JavaScript
    @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 as selector.
    JavaScript
    @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:
    JavaScript
    <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 things simple, we will have all the fields, including date, as strings for the moment. Component is named: NotesComponent

JavaScript
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:

JavaScript
<ul>
    <li *ngFor="let note of noteItems">
      {{note.Body}}
    </li>
  </ul>

And now, we update the component NotesComponent and display the data:

JavaScript
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 (example: 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:

JavaScript
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:
    JavaScript
    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:
    JavaScript
    @NgModule({
        imports: [BrowserModule],
        declarations: [NotesComponent],
        providers: [Configuration],
        bootstrap: [NotesComponent]
    }

    These updates allow us to inject Settings, via constructor, into our component.

    JavaScript
    export class NotesComponent {
        constructor(private _dataService: NoteService) {

See this live in Plunker: Preview C – Angular 2 – Injectable.

Using Angular 2 Component lLifecycle

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.

JavaScript
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 allows us to receive the json details. The class is also marked as injectable to be accessed and used more easily.

JavaScript
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<noteitem[]>. Once the details are received asynchronously, we fill in the local variable myItems.

JavaScript
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:

JavaScript
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 run and test more easily, using a single solution.

JavaScript
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 connects all the concepts presented above and simulates a basic Notebook application. This application connects to local controller as a REST service (Web API controller), and then display the notes received.

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. Then, we will be able to add, edit or remove notes.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Denmark Denmark
My name is Petru Faurescu and I am a solution architect and technical leader. Technical blog: QAppDesign.com

Comments and Discussions

 
Questionovercomplicated Pin
ovisariesdk24-Jan-18 5:07
ovisariesdk24-Jan-18 5:07 
AnswerRe: overcomplicated Pin
Petru Faurescu27-Jan-18 9:03
professionalPetru Faurescu27-Jan-18 9:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.