JavascriptServices: ASP.NET Core meets node.js

JavascriptServices In the past, I talked about how to integrate Angular 2 and ASP.NET Core just by using gulp tasks and configuring ASP.NET Core. In one of those post, I used the Microsoft.AspNet.SpaServices NuGet package to create a fallback route. This package is part of a set of tools named JavascriptServices which provides infrastructure that helps you to create awesome React/Angular 2/Knockout/etc sites, as well as, integrate with existing node.js code into your ASP.NET Core apps.

Introducing JavascriptServices

JavascriptServices is a set of tools that currently includes three components/NuGets: Microsoft.AspNetCore.NodeServices, Microsoft.AspNetCore.SpaServices and Microsoft.AspNetCore.AngularServices. In the past, there was also a ReactServices package, but this package is no more needed as you can use the SpaServices package instead. Now, let’s see them in more detail.

NodeServices

First, NodeServices, which is the base package. This package provides a way to run JavaScript in the server from a .NET application. To do this, it takes advantage of the Node.js environment.

In order to consume NodeServices, you need to add the using Microsoft.AspNetCore.NodeServices; statement and enable it inside the ConfigureServices method of your Startup class.

public void ConfigureServices(IServiceCollection services)
{
    // ... all your existing configuration is here ...

    // Enable Node Services
    services.AddNodeServices();
}

Now, you can use this service from any action by adding the nodeServices parameter to it and calling the nodeServices’ InvokeAsync method. Just pass the name of the node.js script file as first parameter and then the JavaScript function’s parameters if you need to.

public async Task<IActionResult> MyAction([FromServices] INodeServices nodeServices)
{
    var result = await nodeServices.InvokeAsync<int>("./addNumbers", 1, 2);
    return Content("1 + 2 = " + result);
}

In this example, the addNumbers.js script should be placed at the root of your ASP.NET Core app and look something like the following. Note that function should have a callback parameter in the first position which expect and error and the result. As a result of this, you might want to wrap your existing code in a new script that calls it.

module.exports = function (callback, first, second) {
    var result = first + second;
    callback(/* error */ null, result);
};

For more details on the API, you can check the repository, which also includes some extra use cases and samples.

SpaServices

The second package is SpaServices, which is built on top of NodeServices. This package includes a lot of tools that are generally useful when building Single Page Applications (SPAs). I already mentioned the routing helpers (the MapSpaFallbackRoute extension method).

One of the most interesting tools included in the SpaServices package is the Webpack middleware. This middleware enables you to hook your webpack configuration in ASP.NET Core in a similar way as you can do with express in node.js.

Another interesting feature included in SpaServices, is the support for hot module replacement. By using this feature, you can reduce the amount of time reloading the page after changes which is very useful for big SPAs.

Lastly, you can create universal (a.k.a. isomorphic) applications thanks for the support for server-side rendering. This is especially interesting for improving SEO (Search engine optimization) and client-side performance.

As this package is a bit more complex than the previous one, I will try to create a new post in the near future to show how to configure Angular 2 and/or React using it. In the meantime, you can read the documentation and the samples at the repository.

AngularServices

The last package is AngularServices, which provides some extra tools for Angular including some validation helpers and a “cache priming” feature.

The yeoman generator

Finally, there is a yeoman generator called generator-aspnetcore-spa which includes templates using these packages configured with Angular 2, React, React + Redux and Knockout.

JavascriptServices: generator-aspnetcore-spa

Wrapping up

To wrap up, these are a great set of tools if you plan to create SPA sites using the latest frameworks. Moreover, this is just the beginning for these tools as they are in heavy development.

Angular 2 Http with ASP.NET Core APIs

In my previous post, I explained how to configure routing in an application with Angular 2 and ASP.NET Core (if you need more information about how to configure a project with Angular 2 using TypeScript and ASP.NET Core in Visual Studio you can read the first post). This was one of the key elements to create Single Page Applications (SPA). Another key element is to consume REST APIs from your Angular 2 application, so now is the time to show you how to configure your project to use the Angular 2 Http service in ASP.NET Core in order to be able to do so. ASP.NET Core and Angular 2 with TypeScript

First of all, lets configure the Angular 2 Http service in the site. The Http service, as well as the Router Component, are not part of the Angular 2 core, they are in their own libraries which you can find as part of the bundles included when installing the npm package. In order to make the Angular 2 Http service available in the application, you need to include the script in the layout in the same way you did with the router library. To do so, open the _Layout.cshtml file located at Views/Shared/ and add the following code right after the script element that loads Angular 2 core.

<environment names="Development">
    <script src="~/lib/npmlibs/angular2/http.dev.js"></script>
</environment>

<environment names="Staging,Production">
    <script src="~/lib/npmlibs/angular2/http.min.js"></script>
</environment>

By doing this, we added the http component’s requirements to the application. Now, its time to configure your Angular 2 application to use it. First of all, add the http providers to the bootstrap, by importing the HTTP_PROVIDERS from angular2/http and passing it to Angular’s bootstrap function.

import {bootstrap}  from "angular2/platform/browser";
import {AppComponent} from './app.component'
import {HTTP_PROVIDERS} from "angular2/http";

bootstrap(AppComponent, [HTTP_PROVIDERS]);

Now, you need to update your custom components to make use of the Angular 2 Http service. In a real project, you should create an injectable service that consume the Http service in order to make it easier to test and update. However, in this post I will update the main component in order to make things easier to follow.

First, you need to import Http and Response from angular2/http. You will also need to import rxjs/Rx because of the map function that I used.

Now, update the template to show a list of values using the ngFor directive and add the values property to the AppComponent class. Implement OnInit, in order to load the values when the component trigger the init event. Finally, add a constructor passing private http: Http as parameter, in order to have access to an instance of Angular 2 Http that is automatically injected.

In the ngOnInit method is where you will be performing a GET request to the /api/values endpoint. To do this, you just need to call the get method of the http instance passing the endpoint as parameter: this.http.get("/api/values"). After doing this, you will map the result (which is an observer) to json by appending .map((res: Response) => res.json()). Finally, you will use the subscribe method to do something when the values are received. In this case, you will assign the values to the property that you are showing in the templates (in my case values).

import {Component, OnInit} from "angular2/core";
import {Http, Response} from "angular2/http";
import "rxjs/Rx";

@Component({
    selector: "my-app",
    template: `
        <h1>My First Angular 2 App</h1>
        <ul>
          <li *ngFor="#value of values">
           {{value}}
          </li>
        </ul>
        `
})
export class AppComponent implements OnInit {
    private values: string[];

    constructor(private http: Http) {
    }

    ngOnInit() {
        return this.http.get("/api/values")
            .map((res: Response) => <string[]>res.json())
            .subscribe((data:string[]) => this.values = data);
    }
}

Now that you have everything in place in the front end, you need to configure the backend. First, open the Startup.cs file and locate the ConfigureServices method. In that method update the AddMvc call appending a call to the AddJsonOptions method to configure the JSON serializer to use camelCase and including default values to easily parse the results in the front end. In order to do this, add the following code as well as the missing using statements (Newtonsoft.Json.Serialization and Newtonsoft.Json).

services.AddMvc().AddJsonOptions(options =>
    {
        options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        options.SerializerSettings.DefaultValueHandling = DefaultValueHandling.Include;
        options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
    });

Then, create a new NoCache attribute to indicate to the browser that the responses of the actions where you use this attribute are no cacheable. This is required because the browser might save the result in the cache and you will not be able to see the updated responses.

namespace MyAngular2BaseApp.Infrastructure
{
    using System;
    using Microsoft.AspNet.Mvc.Filters;

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public sealed class NoCacheAttribute : ActionFilterAttribute
    {
        public override void OnResultExecuting(ResultExecutingContext context)
        {
            context.HttpContext.Response.Headers["Cache-Control"] = "no-cache, no-store, max-age=0";
            context.HttpContext.Response.Headers["Pragma"] = "no-cache";
            context.HttpContext.Response.Headers["Expires"] = "-1";

            base.OnResultExecuting(context);
        }
    }
}

Create an ASP.NET Core API Controller, which is a simple Controller. In this controller, add the Get method with the HttpGet attribute that returns the list of string values. Make sure to include the [Produces("application/json")] attribute in your controller and the [NoCache] attribute in your GET methods.

namespace MyAngular2BaseApp.Controllers
{
    using System.Collections.Generic;
    using Microsoft.AspNet.Mvc;
    using MyAngular2BaseApp.Infrastructure;

    [Produces("application/json")]
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        // GET: api/values
        [NoCache]
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }
}

If you run the solution now, you will be able to see the following image. Note that there is a request to the Controller API that get the values.

Angular 2 HTTP request result page

Now you have the two keys elements in place for a Single Page Application using Angular 2 and ASP.NET Core. You can find the full code in my Angular2ASPNETCoreBaseApp repository at the http-sample branch. In case you want both, routing and http, configure you can take a look at the full-sample.

Routing in Angular 2 with ASP.NET Core

In my previous post, I explained how to configure Angular 2 with TypeScript in a ASP.NET Core project created with Visual Studio. The idea was to explain the minimum steps that you need in order to have a basic application working. However, you will generally create more complex apps using Angular, for example, a Single Page Application (SPA). That kind of applications, generally take advantages of the routing features that are incorporated in Angular nowadays. In this post, I will show you how to configure routing in an Angular 2 application with ASP.NET Core.Routing in Angular 2 with ASP.NET Core

First of all, lets configure the Angular 2’s Router component in the site. The Router component is not part of the Angular 2 core, it’s in its own library which you can find as part of the bundles included when installing the npm package. In order to make it available in the application, you need to include the script in the layout. To do so, open the _Layout.cshtml file located at Views/Shared/ and add the following code right after the script element that loads Angular 2 core.

<environment names="Development">
    <script src="~/lib/npmlibs/angular2/router.dev.js"></script>
</environment>

<environment names="Staging,Production">
    <script src="~/lib/npmlibs/angular2/router.min.js"></script>
</environment>

Now, in the same file, we must add a <base> element tag to make pushState routing work. The browser also needs the base href value to prefix relative URLs when downloading and linking to css files, scripts, and images. Add this tag after the <head> tag using as value for the href attribute the base url, which will usually be “/”. Note that if you don’t use the application root for your Angular app, you’ll need to update this value accordingly.

<html>
<head>
     <base href="/" />
     <!-- ... -->

By doing this, we added the routing component’s requirements to the application. Now, it’s time to configure your Angular 2 application to use it. First of all, add the Router providers to the bootstrap, by importing the ROUTER_PROVIDERS from angular2/router and passing it to Angular’s bootstrap function.

import {bootstrap}    from 'angular2/platform/browser'
import {AppComponent} from './app.component'
import {ROUTER_PROVIDERS} from 'angular2/router'

bootstrap(AppComponent, [ROUTER_PROVIDERS]);

Now, open the app.component.ts file and import RouteConfig and ROUTER_DIRECTIVES from angular2/router. Additionally, update the component’s template to use the routerLink directive and the router-outlet component. Moreover, add the RouterConfig attribute to configure the links.

The following code shows an example that uses two buttons to redirect to SampleComponent and AnotherSampleComponent components, using the first one as default and redirecting any other urls to that path. My idea is not to explain Angular 2 routing in this post, just focus on the structure needed to integrate it with ASP.NET Core, so if you need more information at this point, you can try on the official documentation.

import {Component} from 'angular2/core';
import { RouteConfig, ROUTER_DIRECTIVES } from 'angular2/router';
import { SampleComponent, AnotherSampleComponent } from './sample.components';

@Component({
    selector: 'my-app',
    template: `
         <h1>My First Angular 2 App</h1>
         <nav class="btn-group" role="group" aria-label="...">
            <a href="" [routerLink]="['Sample']" class="btn ban-default">Sample</a>
            <a href="" [routerLink]="['AnotherSample']" class="btn ban-default">Another Sample</a>
         </nav>
         <router-outlet></router-outlet>
    `,
    directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
    { path: '/sample', name: 'Sample', component: SampleComponent, useAsDefault: true },
    { path: '/another-sample', name: 'AnotherSample', component: AnotherSampleComponent },
    { path: '/**', redirectTo: ['Sample'] }
])
export class AppComponent { }

If you run the solution now, you will be able to navigate using the buttons without any issues. The following image shows you the experience.

Routing result

However, you can notice that if you refresh your browser or navigate to a specific path, you will not be able to get to the same page. That’s because in that scenario, the url is first resolved by the server as you are performing a direct request to it and the front-end (the Angular part) can’t handle it at this point. The solution for this is to add a new route configuration in ASP.NET Core.

In the Startup.cs file, locate the app.UseMvc method call and add a new route using {*url} as template and redirecting to the controller that you are using for your Angular 2 application.

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");

    routes.MapRoute(
        name: "spa-fallback",
        template: "{*url}",
        defaults: new { controller = "Home", action = "Index" });
});

The problem with this rule is that you will not have 404s for non-existent assets like images, css or js files as the SPA HTML will be returned instead. To avoid this, you can install the Microsoft.AspNet.SpaServices NuGet package and replace the spa-fallback with a call to the MapSpaFallbackRoute method. This will match all the request that doesn’t appear to have a filename extension (defined as ‘having a dot in the last URI segment’). However, it means requests like /customers/isaac.newton will not be mapped into the SPA.

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");

    routes.MapSpaFallbackRoute("spa-fallback", new { controller = "Home", action = "Index" });
});

With this, you have everything you need to create complex Angular 2 applications using ASP.NET Core as backend. You can find the full code in my Angular2ASPNETCoreBaseApp repository at the routing-sample branch.

Updated: I created a new post explaining how to configure Angular2’s Http service and ASP.NET to consume the MVC APIs.

ASP.NET Core and Angular 2

ASP.NET Core and Angular 2 with TypeScript Writing web applications nowadays is becoming a bit more complex as the frameworks evolve taking advantage of other frameworks/tools. That’s the case of Angular 2 (which was developed using TypeScript) and ASP.NET Core with take advantage of npm and bower for the dependencies as well as gulp for performing some tasks. In this article, I will show you how to configure ASP.NET Core and Angular 2 using TypeScript to create your rich client-side apps.

ASP.NET Core is a new open-source and cross-platform framework for building modern cloud-based Web applications using .NET. It was built from the ground up to provide an optimized development framework for apps that are either deployed to the cloud or run on-premises. It consists of modular components with minimal overhead, so you retain flexibility while constructing your solutions. It has evolve taking concepts from node.js and other platforms.

Angular is a development platform for building mobile and desktop web applications using modern web standards. Is an open-source JavaScript framework that augments browser-based applications with Model-View-Controller (MVC) capability, facilitating both development and testing. If you know the previous version, Angular 2 might seems to be a completely different framework, but the main concepts are there. One of the main differentiators is that Angular 2 is written in TypeScript, a superset of JavaScript that compiles to clean JavaScript output. Because its transcompiled to JavaScript, you can use the framework from JavaScript as well as from TypeScript itself.

Now, let’s start configuring a project with both technologies, ASP.NET Core and Angular 2. I’ll assume that you have an ASP.NET Core project created, with MVC configured, although this is not a requirement for using both technologies together. If you need to create a new project, just use the Web Application template in Visual Studio or using the aspnet’s Yeoman generator.

In order to have ASP.NET Core and Angular 2 running together, you’ll need to have the Angular 2 dependencies in place. Angular 2 is distributed using the npm package manager. Open the npm’s package.json file located at the root of your project and add the following dependencies to it.

  "dependencies": {
    "angular2": "2.0.0-beta.9",
    "systemjs": "0.19.24",
    "es6-shim": "^0.33.3",
    "rxjs": "5.0.0-beta.2"
  },

If you are using Visual Studio, after saving the file, it will download the new dependencies (else, just run npm install in the same folder). The files will be downloaded in the node_modules folder, which is not served as default by ASP.NET. You could configure ASP.NET to serve this folder, but it’s better to just copy the files to the wwwroot folder using a gulp tasks. Add the following code in the gulpfile.js. This will add a few tasks to copy each of the dependencies to the wwwroot/lib/npmlibs folder, as well as a task named copy-deps that will run all the others.

paths.npmSrc = "./node_modules/";
paths.npmLibs = paths.webroot + "lib/npmlibs/";

gulp.task("copy-deps:systemjs", function () {
    return gulp.src(paths.npmSrc + '/systemjs/dist/**/*.*', { base: paths.npmSrc + '/systemjs/dist/' })
         .pipe(gulp.dest(paths.npmLibs + '/systemjs/'));
});

gulp.task("copy-deps:angular2", function () {
    return gulp.src(paths.npmSrc + '/angular2/bundles/**/*.js', { base: paths.npmSrc + '/angular2/bundles/' })
         .pipe(gulp.dest(paths.npmLibs + '/angular2/'));
});

gulp.task("copy-deps:es6-shim", function () {
    return gulp.src(paths.npmSrc + '/es6-shim/es6-sh*', { base: paths.npmSrc + '/es6-shim/' })
         .pipe(gulp.dest(paths.npmLibs + '/es6-shim/'));
});

gulp.task("copy-deps:rxjs", function () {
    return gulp.src(paths.npmSrc + '/rxjs/bundles/*.*', { base: paths.npmSrc + '/rxjs/bundles/' })
         .pipe(gulp.dest(paths.npmLibs + '/rxjs/'));
});

gulp.task("copy-deps", ["copy-deps:rxjs", 'copy-deps:angular2', 'copy-deps:systemjs', 'copy-deps:es6-shim']);

Now that you have the Angular 2 dependencies ready to be served in your project, you need to add them to your site so you can start using it. Open the _Layout.cshtml file located at Views/Shared/ and add the following code at the end of your head tag. Note that the polyfills and shims are declared before system.js and angular2. Additionally, in this case I added the router bundle to show you that you need to add additional bundles like Http and router (if you don’t need it, you can remove it).

<environment names="Development">
  <script src="~/lib/npmlibs/es6-shim/es6-shim.js"></script>
  <script src="~/lib/npmlibs/systemjs/system-polyfills.src.js"></script>
  <script src="~/lib/npmlibs/angular2/angular2-polyfills.js"></script>

  <script src="~/lib/npmlibs/systemjs/system.src.js"></script>
  <script src="~/lib/npmlibs/rxjs/Rx.js"></script>
  <script src="~/lib/npmlibs/angular2/angular2.js"></script>
  <script src="~/lib/npmlibs/angular2/router.js"></script>
</environment>

<environment names="Staging,Production">
  <script src="~/lib/npmlibs/es6-shim/es6-shim.min.js"></script>
  <script src="~/lib/npmlibs/systemjs/system-polyfills.js"></script>
  <script src="~/lib/npmlibs/angular2/angular2-polyfills.min.js"></script>

  <script src="~/lib/npmlibs/systemjs/system.src.js"></script>
  <script src="~/lib/npmlibs/rxjs/Rx.min.js"></script>
  <script src="~/lib/npmlibs/angular2/angular2.min.js"></script>
  <script src="~/lib/npmlibs/angular2/router.min.js"></script>
</environment>

Now, you have the dependencies in place for your ASP.NET Core and Angular 2 application, but if you plan to use TypeScript in your project you need to perform a few steps more. Create a tsconfig.json file in the root of your project to configure the compiler to include decorators and specify the use of system.js for module resolution.

{
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "es5",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "system",
    "moduleResolution": "node"
  },
  "exclude": [
    "node_modules",
    "wwwroot/lib"
  ]
}

If you try to compile the project now, you might find some TypeScript issues because Promise and other types are not defined. Add the es6-shim’s TypeScript definitions to your project. To do this, download the one from the DefinitelyTyped repository and add it to your project (you don’t need to serve this file, so you can have a ts folder with it in the root of the project).

Finally, let’s create the base structure for an Angular 2 application. We’ll create two TypeScript files inside a new folder named app under wwwroot. The first file will be the component, which will be a basic Hello World component. Create a file named app.component.ts inside the wwwroot/app folder and add the following code.

import {Component} from 'angular2/core';

@Component({
    selector: 'my-app',
    template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }

Now, create a file named boot.ts also inside the wwwroot/app folder and add the following code. This file is the one that you will load as start point of your app.

import {bootstrap}    from 'angular2/platform/browser'
import {AppComponent} from './app.component'

bootstrap(AppComponent);

Open the view where you plan to add your Angular app, I will choose the Views/Home/Index.cshtml view. Add the angular component tag (e.g. <my-app></my-app>) to the html and add the following script section to the end of the file. This script will configure System.js (specifying to use js files whenever the extension it’s not defined) as well as initialize the Angular 2 app by importing the boot.js file located at the app folder.

@section Scripts {
    <script>
        System.config({
            packages: {
                'app': { defaultExtension: 'js' },
                'lib': { defaultExtension: 'js' },
            },
        });

        System.import('app/boot')
            .then(null, console.error.bind(console));
    </script>
}

You have the base structure for an ASP.NET Core and Angular 2 application. You can find the full code in my Angular2ASPNETCoreBaseApp repository. Now, you just need to start developing your awesome ideas.

Updated: I created a new post explaining how to configure routing to use Angular 2 Routing component.

Updated 2: I created a new post explaining how to configure Angular2’s Http service and ASP.NET to consume the MVC APIs.