Monday, July 18, 2016

Building a web application using ASP.NET Core 1.0, Aurelia, TypeScript, Webpack in Visual Studio Code – Part 4

Introduction

YouTube Video Link for Part 4:

This is the fourth part of Building a web application using ASP.NET Core 1.0, Aurelia, TypeScript, Webpack in Visual Studio Code.

The source code for this tutorial is available on GitHub.

In Part 3 of this series, we setup TypeScript, Typings, created a tsconfig.json and wrote our first TypeScript class. In this part, we’ll focus on setting up Aurelia and Webpack. Let us get started.

Prerequisites

Please create a new folder named “part4” under “C:\tutorial”. You’ll need the source code from part3 to practice this part of the series. You can pull the source code from my github repository: https://github.com/rajajhansi/aspnetcore-aurelia-tutorial . After you got the source code, delete the “.git” directory.

Aurelia

Aurelia is developed by Duranda Inc., a company founded by Rob Eisenberg (popular for his blog Eisenberg Effect)  who has proven track record on front end frameworks like Caliburn.Micro, DurandalJs and now Aurelia.  Aurelia is a modern, forward-thinking, conventions based JavaScript framework leveraging web  standards. Aurelia itself is developed using ES2016 and comprises of smaller, focused modules. If you are someone who is more comfortable using an enterprise support and consulting, Durandal Inc., the company that develops Aurelia offers those services as well. I’ve been very impressed with the way they have been developing this framework in open, taking active feedback, involving the community and most importantly quickly releasing beta and RC versions. At the time of this writing, Aurelia is in its RC release.

Aurelia TypeScript-Webpack-Skeleton-Navigation Project

If you would like to setup Aurelia project using TypeScript and Webpack, you can get started real quick using the aurelia-tyepscript-webpack skeleton navigation project. In this part of the series, we are going to use that skeleton project as our base, clean up unwanted files and start building our application. To setup the skeleton project, you need to either clone or download the aurelia/skeleton-navigation project from aurelia’s github repository url: https://github.com/aurelia/skeleton-navigation 

We do not want to clone/download the skeleton-navigation project into “c:\tutorial\part3\modern”. Instead, let us create a staging folder “c:\staging” for the skeleton-navigation and then run git clone from within “c:\staging’'” from cmder as follows:

mkdir staging

cd staging

git clone https://github.com/aurelia/skeleton-navigation

fig1_thumb[1]

Adding skeleton-navigation into our source code

In part 2, we started our development by copying the source code from part 1. In this part, we will copy the skeleton-navigation source code into “c:\tutorial\part3\modern” first and then copy only the asp.net core 1.0 server side code and the associated project.json file. Doing it the other way i.e., first copying the source code from part2 and then copying selected folders/files from skeleton-navigation would be cumbersome and error prone. Please follow these steps to successfully add skeleton-navigation into our source to create the source code for part3:

1. Copy the contents of “C:\staging\skeleton-navigation\skeleton-typescript-webpack” into C:\tutorial\part4\modern”:

fig2_thumb[2].

2. Copy all files and folders from C:\tutorial\part3\modern except the following files/folders into C:\tutorial\part4\modern:

.vscode, bin, node_modules, obj, src, .gitignore, package.json, project.lock.json, tsconfig.json

fig3_thumb[4]

3. While you are copying, if you get conflicts about the files: README.md and tsconfig.json , just go ahead and overwrite them.

4. Copy launch.json and tasks.json from part3\modern\.vscode into into part4\modern\.vscode

5. If you would like to check in the source code in part 3 into github, then you need to merge the .gitignore file from part3 with .gitignore file from part4. Since part3\.gitignore has more entries, it makes total sense to copy the contents of part3\.gitignore into VSCode or any other text editor and copy everything but node_modules from the contents of part3\.gitignore and save the merged content as part4\.gitignore

Running the integrated skeleton-navigation source code without using Kestrel web server

Open up cmder and change your directory to “C:\tutorial\part4nnp\modern”. Then, run the following commands in the same order:

npm install 
npm start

That should start the webpack-dev-server on localhost:9000 after bundling the modules. You can launch chrome browser and visit the url: http://localhost:9000 to see the aurelia-skeleton-navigation application in action. Now, it is time for us to use our Greeter class that we built in part 3. Copy greeter.ts from c:\tutorial\part3\modern\app\src into C:\tutorial\part4\modern\app folder.

Note: Make sure to delete Page.aspx.cs and Redirect.aspx.cs from c:\tutorial\part4\modern\node_modules\selenium-webdriver\lib\test\data because VSCode will try to compile those files and will throw errors because those are Selenium’s ASP.NET pages developed using ASP.NET and not Asp.Net Core 1.0.

Power of easy-webpack

In my previous part, you should have noticed how difficult it is to create a working webpack.config.js. Although Webpack is very powerful, it is changing quickly and the documentation and samples aren’t catching up with the implementation as fast as we would like. This is not a complaint because open source software like Webpack needs more contributors and help. Instead, what we see in their github.io page is developers posting harsh comments about the documentation and demanding everything, which is not correct. Luckily, Aurelia core team member Bazyli Brzóska created Easy Webpack, a project to simplify and modularize Webpack configuration. I want to give a shout-out to Bazyli for his awesome Easy Webpack project. Easy Webpack allows anyone to use the default configuration or augment or completely override the default.

Creating our first Aurelia Component

In MVVM frameworks, UI components have two parts: a view, written in HTML and a view-model that provides data and behavior to the view. Aurelia’ components also use the concept of view and view-model and uses databinding to link them together. Follow these steps to turn our greeter class into an Aurelia view model class and render “greetingMessage” accessor in a view:

Export the class by adding the keyword export before “class Greeter {

We need to export the class so Aurelia and other parts of the application can use our class. If we don’t export the class, it is a private class that no one can access from other classes or html pages. Since Aurelia will invoke this view model, let us add a default value to the message field like this:

constructor(private message: string =”World”) {

}

Let us create a view page that has the same name as the class with .html extension i.e., greeter.html as follows:

<template>
    <div>
       <h1>${greetingMessage}</h1>
       <h2 value.bind="greetingMessage"></h2>
    </div>
</template>

Aurelia leverages the Web Components standards. HTML templates defined using <template> tag is a part of Web Components standard. It allows us to define inert DOM subtrees i.e., HTML chunks that the browser will not act upon. You need to write code to read the chunk and render it. The process of activating that chunk is called “stamping out a template”. In our case, Aurelia takes care of rendering this chunk in browser. If you’re curious about how to do it yourself, check out http://www.html5rocks.com/en/tutorials/webcomponents/template/

Now that we have defined our view model and view, let us focus on wiring them into Aurelia.

Bootstrapping Aurelia

As always, index.html page is where we’ll define the bundle.js, that comprises of all js files that constitute the application.  For Webpack users, aurelia had implemented a package named aurelia-bootstrapper-webpack. There are two kinds of bootstrapping in Aurelia: declarative and manual. In declarative bootstrapping, we need to designate a HTML element using the aurelia-app attribute, where Aurelia’s bootstrapper will load an app and app.html by convention, databind them together and inject them into that HTML element. In our index.html, we have added “aurelia-app” attribute to the <body> tag to indicate the bootstrapper to load our app view-model and its view, conventionally located in app.ts and app.html.

In manual bootstrapping,  you’ll invoke the aurelia bootstrapper’s bootstrap method that takes a function as an argument. That function receives an instance of Aurelia class. Using that instance we can specify the startup configurations like plugins, logging etc., and then invoke the start() function, which is a promise. Upon starting, aurelia sets the Root component of our aurelia application using the setRoot functions that takes 2 arguments: viewmodel and the HTML element where the view should be injected.

Since we are using aurelia with Webpack and Webpack has a way to specify the entry class, we’ll use main.ts as our entry point and use manual bootstrapping as follows:

import {Aurelia} from 'aurelia-framework';
import {bootstrap} from 'aurelia-bootstrapper-webpack';
import 'bootstrap'; bootstrap(async (aurelia: Aurelia) => {
  aurelia.use
    .standardConfiguration()
    .developmentLogging();   const rootElement = document.body;
  rootElement.setAttribute('aurelia-app', '');   await aurelia.start();
  aurelia.setRoot('greeter’, rootElement);
  });

Wiring Greetings API controller into Aurelia

A simple greeter class is a good staring point to understand Aurelia. As you all know, SPA (Single Page Applicatios) build their business logic as RESTfule APIs and invoke them from client side using client side frameworks like Aurelia and then dynamically inject markup into browser’s DOM. It is time for us to wire our GreetingsController’s API method into our greeter class and render the API method’s return value inside the browser;

To invoke a Web API, Aurelia provides two modules: aurelia-http-client and aurelia-fetch-client. Both of them define the class HttpClient but with a different implementation.

aurelia-http-client

aurelia-http-client is a basic HttpClient that provides a nice wrapper interface to the browser’s XMLHttpRequest obect. It provides methods that match the HTTP verbs like GET, POST, DELETE, PUT, PATCH besides supporting a configure method where we can define base url, headers etc., for all requests as well as a createRequest method that we can define base url, headers etc., for each request. It also provides hooks into request and response using interceptors.

aurelia-fetch-client

aurelia-fetch-client embrace and implement the new Fetch API,  a specification that you can find in Mozilla Developer Network (MDN) documentation. This client library also provides default configuration of request parameters, interceptors and centralized request tracking.

Enabling CORS in our API Controllers

Since Asp.Net Core’s Kestrel web server uses port 5000 to serve the APIs and our client webpack-dev-server is running on port 9000, we can’t invoke calls to the API unless we enable Cross Origin Resource Sharing. Using CORS, a server can explicitly allow some cross-origin requests. We should enable cross-origin requests coming from http://localhost:9000 in our APIs. To enable CORS,

1. We need to add reference to “Microsoft.AspNet.Cors

2. Call services.AddCors() extension method in Startup.cs’s ConfigureServices method

3. Call UseCors with required parameters inside Configure method in Startup.cs  like this:

app.UseCors(builder =>
               builder.WithOrigins("http://localhost:9000")
                   .AllowAnyHeader().AllowAnyMethod());

Invoking GreetingsController’s Get method from Aurelia

We are going to aurelia-fetch-client’s HttpClient class to invoke the GreetingsController API’s Get method. Aurelia has DI (Dependency Injection) at its core implemented using @inject decorator. Decorators are defined in ECMScript 7 and TypeScript already implements decorators. Aurelia support Lazy initialization using the Lazy class. Like we did in earlier parts, we need to import those classes defined in the aurelia modules. inject is defined in ‘aurelia-framework’ and HttpClient is defined in ‘aurelia-fetch-client’. Let us import them like this:

import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-fetch-client';

To inject an instance of HttpClient, let us the inject decorator with Lazy.of method right above the like where greeter is defined like this:

@inject(HttpClient)
export class Greeter { 

We need to define a parameter that receives the injected instance of HttpClient like this:

constructor(private httpClient: HttpClient, private message: string = “World”){
http.configure(config => {
     config
       .useStandardConfiguration()
       .withBaseUrl("http://localhost:5000/api/")
   });
}

We are going to leverage Aurelia’s Screen Activation Lifecycle’s activate() hook to wire our web Api. activate() hook allows us to perform custom logic before our view-model is displayed. Our activate() method should be defined like this:

async activate(): Promise<void> {
      this.httpClient.configure( (config: any) => {
      config
     .useStandardConfiguration()
     .withBaseUrl("http://localhost:5000/api/")
      });       const http = this.httpClient;
      const response = await http.fetch("greetings");
      this.greetingMessageViaApi= await response.json();
  }

We have added a new field named “greetingMessageViaApi” in our Greeter class to store the return value from our GreetingsController Web Api’s Get() method. Now, lets change the view to render the greetingMessageViaApi field like this:

<h2>${greetingMessageViaApi}</h2>        
<input type="text" value.bind="greetingMessageViaApi"></input>

value.bind attribute is used for two way binding in Aurelia. To see the two way binding in action, if you modify the text inside the text box, you’ll see the <h2> tag also shows the modified value because both <input> and <h2> are data bound to greetingMessageViaApi field of Greeter view-model.

In this part of the series, we have seen a quick introduction to Aurelia, easy-webpack and wrote our first Aurelia component and saw the two way data binding in action. In the next part of the series, I’ll show you how we can build a simple ToDoMvc application from the ground up using Aurelia. Happy coding!

3 comments:

  1. Hi Raja,

    Very nice blog.

    RE: "Note: Make sure to delete Page.aspx.cs and Redirect.aspx.cs..."

    You can exclude node_modules and other folders like typings etc from dotnet build by adding following build options in project.json.


    "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true,
    "debugType": "portable",
    "compile": {
    "exclude": [
    "node_modules",
    "custom_typings"
    ]
    }
    }

    ReplyDelete
  2. @moon, just got back from my vacation. Thank you for your appreciation and the nice suggestion to exclude those files using project.json.

    ReplyDelete
  3. Raja,
    Your tutorials are excellent. I am coming from Node/non-.net background and find your explanations very helpful, BUT this all seems much more convoluted than just straight Node.

    ReplyDelete