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.

Manifoldjs, a tool to create hosted apps

Modern web technologies are evolving not only to create faster and complex websites but also to create apps. There are plenty of examples for this. First of all, node.js, which is the one of the best examples, moving JavaScript to the server side. Then, you have electron, which is the technology behind Visual Studio Code, atom, the slack client and kitematic. Furthermore, you can think of frameworks that enables to create mobile apps using web technologies like apache cordova, ionic and React Native. However, you can go a step further creating a website and apps all in one using Manifoldjs.

Manifoldjs creates hosted web apps and some polyfill apps for Android, iOS, Windows 8.1, Windows Phone 8.1, Windows 10, FirefoxOS, Chrome, and the web, all based on the W3C Manifest for Web Apps. In addition to these platforms, the new version of manifoldjs supports creating your own platforms.

manifoldjs

So, what is a “Hosted Web App”? It’s a store app (i.e. apps that can be downloaded from Google Play or Windows Store), whose content is hosted on a web server. In other words, it’s a website converted into an installable app. You can find more information about hosted web apps in this post.

A W3C Manifest for web apps is a standardized JSON-based manifest that provides developers a centralized place to put metadata associated with a web application. With this manifest, you can forget about using all the platform-specific meta tags that set the different size icons for each platform and other settings. In order to support this manifest on your site, you just need to add a single <link> tag:

<link rel="manifest" href="manifest.json">

An example of a manifest.json could be something like:

{
    "name": "manifold.js",
    "short_name": "mjs",
    "icons": [{
        "src": "images/tiny.png",
        "sizes": "70x70",
        "type": "image/png"
    }],
    "start_url": "/",
    "scope":"http://www.manifoldjs.com/*"
    "display": "standalone",
    "orientation": "landscape"
}

If you want to generate a manifest.json for your site, there are several sites that can help you, for example, you can use the manifoldjs generator site or this one.

Of course, like most cool new features on the block, not every browser supports it yet. However, you can use the ManUp.js polyfill, for example, which will create the required meta tags on your site based on the manifest.json file. You can find more information about W3C Manifest and ManUp.js in this post.

Manifoldjs provides three ways to create your apps:

  • A node-based command-line interface (CLI) which you can install with npm and is easy to use.
  • A node.js module interface, which you can use to create your own tool just by adding the module as a common npm dependency in your node.js app.
  • A website that generates the apps for you: http://www.manifoldjs.com/generator

I will try to explain each scenario in more detail in future posts, but for now, the website is the easiest option.

To sum up, with your site, a W3C Manifest JSON file and manifoldjs, you can easily leverage your site in a cool way, creating Store apps for today’s most important platforms.

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.