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.

Creating a simple API with ASP.NET Core

I posted about ASP.NET Core in the past. In this opportunity, I would like to share a simpler introduction to it using the nodejs’ approach. This approach consists in showing how to create a simple Web API (first with the http module and then using the express framework).

ASP.NET Core

ASP.NET Core is the new web framework in the .NET world, which is open-source (at GitHub) and cross-platform. It was created with focus on modern web development which are generally deployed in clouds environments and serves as backends for mobile apps or IoT apps as well as web apps. Additionally, as part of the redesign of ASP.NET, ASP.NET Core apps can run on .NET Core or on the full .NET Framework and ships entirely as NuGet packages (in a similar way as, for example, node.js apps).

In order to start working with ASP.NET Core, you should install .NET Core first. To do this, visit the oficial site and follow the instructions based on your preferred platform. Furthermore, you will need an editor for which I suggest Visual Studio Code (which is also cross-platform) along with the C# extension.

Creating the base app

Now that you have your environment ready, the first thing that you usually do in node.js is to create the package.json file. To do this, you would run the npm start command to create that file. In a similar way, for a new .NET Core app you will execute dotnet new. By executing this command, you will get the base structure for the app, which consist in two files: project.json and Program.cs. The first one contains the program metadata, including frameworks versions as well as dependencies. The other one is the program code itself.

Similar to node’s npm install, you should now restore the dependencies by executing dotnet restore. This will generate a new file, project.lock.json, which contains all the required information for running the app. At this point, you can see your first “Hello World!” output by running the dotnet run command. Note that this command checks the project source every time to determine if a re-build is necessary. Because of this, this command is intended for active development scenarios. In other scenarios you can execute dotnet build and then run the generated .dll file.

Adding the ASP.NET Core magic

After having the running .NET Core app, you will need to add the Microsoft.AspNetCore.Server.Kestrel dependency in order to run a simple web server similar to what the nodejs’s http module can do. In order to do this, open the project.json file and update the dependencies section as shown below.

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0"
  },
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.0"
        }
      },
      "imports": "dnxcore50"
    }
  }
}

Again, you will need to execute dotnet restore to restore the new dependency and update the project.lock.json file accordingly. After doing that, open the Project.cs file to add the following using statements at the top.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting;

Update the content of the Main function with the following. This will create the web host, configure it to use Kestrel and return to every request the “Hello World!” message.

public static void Main(string[] args)
{
   var host = new WebHostBuilder()
       .UseKestrel()
       .Configure(app => app.Run(context => context.Response.WriteAsync("Hello World!")))
       .Build();

   host.Run();
}

Same as you did before, execute the updated code with dotnet run. Then, open a browser and navigate to localhost:5000. As result, you should be able to see the new “Hello World!” message in your browser.

Adding the MVC framework

At this point in any node.js introduction you would include express, which facilites you creating routes as well as getting the request information. For ASP.NET Core we will include Microsoft.AspNetCore.Mvc as dependency.

{
  "version": "1.0.0-*",
  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true
  },
  "dependencies": {
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
    "Microsoft.AspNetCore.Mvc": "1.0.0"
  },
  "frameworks": {
    "netcoreapp1.0": {
      "dependencies": {
        "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.0"
        }
      },
      "imports": "dnxcore50"
    }
  }
}

Now, create new file named Startup.cs and add the following content, replacing the aspnetcoreapp namespace with the one use have in the Program.cs file. This configure the MVC services that take advantage of the build-in dependency injection feature. Additionally, configure the application itself to use the MVC framework, adding support for Controllers.

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;

namespace aspnetcoreapp
{
  public class Startup
  {
    public void ConfigureServices(IServiceCollection services)
    {
      services.AddMvc();
    }

    public void Configure(IApplicationBuilder app)
    {
      app.UseMvc();
    }
  }
}

After creating this file, you will need to update the Program.cs again, using the following code which configures the Startup class that you just created instead of a custom configuration.

public static void Main(string[] args)
{
  var host = new WebHostBuilder()
    .UseKestrel()
    .UseStartup<Startup>()
    .Build();

  host.Run();
}

Creating the first Controller

Create a new folder named Controllers and then create a new file named ValuesController.cs in it. Add the following content to the new file to have a simple API that returns a list of values as json.

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;

namespace aspnetcoreapp.Controllers
{
  [Route("api/[controller]")]
  public class ValuesController : Controller
  {
    [HttpGet]
    public IEnumerable<string> Get()
    {
      return new string[] { "value1", "value2" };
    }
  }
}

Once this is ready, you just need to execute dotnet run again and navigate to localhost:5000 in your browser to see the list values.

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.