JavaScript

React: Contact Detail

Last week’s post covered adding a React project to the ASP.NET Core Basics solution. As I stated last week the goal is to get the React project’s features in line with the Aurelia and Angular samples. This week we will be adding a read-only view of a contact’s details. The code before any changes can be found here.

Contact Class

The Contact interface in the ContactList.tsx should be deleted and in its please we will add a Contact class. As part of this change, I also moved the contact related items to a contact directory. Add a contact.ts file to the ClientApp/components/contacts/ directory with the following contents.

export class Contact {
    id: number;
    name: string;
    address: string;
    city: string;
    state: string;
    postalCode: string;
    phone: string;
    email: string;

    constructor(data?: any) {
        if (data == null) return;
        (<any>Object).assign(this, data);
    }

    getAddress(): string {
        return `${this.address} ${this.city}, ${this.state} ${this.postalCode}`;
    }

}

This class is very simple and will be used later to show how a function call can be used as part of rendering.

Contact Service

Since the application will now have two places that need to access the ASP.NET Core API I decided to refactor the API access behind a service. This is the same style used by the Aurelia and Angular applications. Add a contactService.ts file to the Contacts directory. The service will provide functions to get all contacts or a single contact using its ID. The following is the full class.

import 'isomorphic-fetch';
import { Contact } from './contact';

export class ContactService {

    private baseUrl = 'http://localhost:13322/api/contactsApi/';

    getAll(): Promise<Contact[]> {
        return fetch(this.baseUrl)
            .then(response => response.json() as Promise<Contact[]>)
            .then(contacts => Array.from(contacts, c => new Contact(c)));
    }

    getById(id: string): Promise<Contact> {
        return fetch(`${this.baseUrl}${id}`)
            .then(response => response.json())
            .then(contact => new Contact(contact));
    }

}

The final step in this refactor is to use the new service in the ContactList class. First, add imports for the service and Contact class.

import { Contact } from './contact';
import { ContactService } from './contactService';

Then, replace the fetch call with the service.

Before:
fetch('http://localhost:13322/api/contactsApi/')
    .then(response => response.json() as Promise<Contact[]>)

After:
let contactService = new ContactService();
contactService.getAll()

Contact Detail Component

Add a ContactDetail.tsx file which will be used to show the details of a contact including using the getAddress function of the Contact class. The following is the full contents of the file.

import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import { Link, NavLink } from 'react-router-dom';
import 'isomorphic-fetch';
import { Contact } from './contact';
import { ContactService } from './contactService';

interface ContactDetailState {
    id: string;
    contact: Contact | undefined;
    loading: boolean;
}

export class ContactDetail extends React.Component<RouteComponentProps<{}>, ContactDetailState> {

    constructor(props: any) {
        super();
        this.state = { id: props.match.params.id, contact: undefined, loading: true };

        let contactService = new ContactService();
        contactService.getById(this.state.id)
            .then(data => {
                this.setState({ contact: data, loading: false });
            });
    }

    public render() {
        let contents = this.state.loading
            ? <p><em>Loading...</em></p>
            : this.state.contact
                ? ContactDetail.renderContactsTable(this.state.contact)
                : <p>No contacts</p>;

        return <div>
            <h1>Contact Detail</h1>
            <hr />
            {contents}
            <NavLink to={'/contactlist'}>Back to List</NavLink>
            <hr />
        </div>;
    }

    private static renderContactsTable(contact: Contact) {
        return <dl className="dl-horizontal">
                   <dt>ID</dt>
                   <dd>{contact.id}</dd>
                   <dt>Name</dt>
                   <dd>{contact.name}</dd>
                   <dt>Address</dt>
                   <dd>{contact.getAddress()}</dd>
                   <dt>Phone</dt>
                   <dd>{contact.phone}</dd>
                   <dt>Email</dt>
                   <dd>{contact.email}</dd>
               </dl>;
    }
}

This is all very similar to the things I have covered before. Now that we have a contact detail component we need a way to display it.

Routing with a Parameter

Import the contact detail in the route.tsx file.

import { ContactDetail } from './components/contacts/ContactDetail';

Next, add a route path for contact detail that expects an ID.

<Route path='/contactdetail/:id' component={ContactDetail} />

Back in the ContactList component change the ID to be a link to the new contact detail route using the ID of the contact.

Before:
<td>{contact.id}</td>

After:
<td><Link to={`contactdetail/${contact.id}`}>{contact.id}</Link></td>

The code for pulling the route parameter was in the ContactDetail component above, but I am going to show it again just so all the route with parameter information is together. The route parameters can be accessed using props.match.params.{parameter name} which in this case ends up being props.match.params.id. The following is the constructor of the ContactDetail component which is using a route parameter.

constructor(props: any) {
    super();
    this.state = { id: props.match.params.id, contact: undefined, loading: true };

    let contactService = new ContactService();
    contactService.getById(this.state.id)
        .then(data => {
            this.setState({ contact: data, loading: false });
        });
}

Wrapping Up

This brings the projects one step closer to being on the same level feature-wise. I expect at least one more post to get the project features lined up so make sure and keep a lookout for the next post.

Keep in mind that this is my first look at React and my examples may or may not be idiomatic. So far I am really enjoying working with React.

The code in a finished state can be found here.

ASP.NET Core Basics: React with an API

In the past, I have done some exploration on Aurelia and Angular via the ASP.NET Core Basics series. This post is going to take a similar approach as I start doing some exploration with React. The code for the project will be in the same repo as the previous basics examples and will be utilizing the same API to pull data. The code before adding the React project can be found here.

This post is going to cover adding a React project to the existing using the React template that is now built into Visual Studio. The same thing can be accomplished using the .NET CLI so don’t feel like Visual Studio is required. The goal for the React project in this initial post will be to connect to the contacts API and download a list of contacts and render that to the screen. In future posts, I hope to expand this functionality to match that of the Aurelia and Angular projects.

Project Creation

Right-click and select Add > New Project.

In the Add New Project dialog select the ASP.NET Core Web Application. In the case of the sample, the project will be named React. Click OK to continue.

On the next screen make sure and select ASP.NET Core 2.0 and the React.js template. Then click OK.

The following is the resulting React project in the context of the full solution.

Next, make sure and run npm install from a command prompt in the React project’s directory to ensure all the npm packages get restored.

Adding the Contact List

Inside the ClientApp/components/ directory add a file name ContactList.tsx. TSX is the TypeScript version of the React JSX file type. The official docs on JSX can be found here. Since this is my first time working with React I took the FetchData.tsx file and copied the contents and used that as the starting point for my contact list. To lead with there is an interface for what should define a contact.

interface Contact {
    id: number;
    name: string;
    address: string;
    city: string;
    state: string;
    postalCode: string;
    phone: string;
    email: string;
}

Next, we have an interface for the state of this component with contains a loading flag and an array of contacts.

interface ContactListState {
    contacts: Contact[];
    loading: boolean;
}

In the constructor for the component is where the data is pulled from the API using fetch. The data from the API is then saved to the state of the component using the setState function.

constructor() {
    super();
    this.state = { contacts: [], loading: true };

    fetch('http://localhost:13322/api/contactsApi/')
        .then(response => response.json() as Promise<Contact[]>)
        .then(data => {
            this.setState({ contacts: data, loading: false });
        });
}

Next, the component has a function named renderContactsTable which takes an array of contacts and returns how they should be rendered. In this case, the contacts are rendered to a table that displays the contact ID and Name.

private static renderContactsTable(contacts: Contact[]) {
    return <table className='table'>
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
            </tr>
        </thead>
        <tbody>
            {contacts.map(contact =>
                <tr key={contact.id}>
                    <td>{contact.id}</td>
                    <td>{contact.name}</td>
                </tr>
            )}
        </tbody>
    </table>;
}

Finally, there is the render function. As you can guess this is what gets called to render the component. In this case, either “Loading” or the contact list gets displayed depending on if the contact list data has been loaded or not.

public render() {
    let contents = this.state.loading
        ? <p><em>Loading...</em></p>
        : ContactList.renderContactsTable(this.state.contacts);

    return <div>
        <h1>Contact List</h1>
        {contents}
    </div>;
}

The following is the full file for reference.

import * as React from 'react';
import { RouteComponentProps } from 'react-router';
import 'isomorphic-fetch';

interface ContactListState {
    contacts: Contact[];
    loading: boolean;
}

export class ContactList extends React.Component<RouteComponentProps<{}>, ContactListState> {
    constructor() {
        super();
        this.state = { contacts: [], loading: true };

        fetch('http://localhost:13322/api/contactsApi/')
            .then(response => response.json() as Promise<Contact[]>)
            .then(data => {
                this.setState({ contacts: data, loading: false });
            });
    }

    public render() {
        let contents = this.state.loading
            ? <p><em>Loading...</em></p>
            : ContactList.renderContactsTable(this.state.contacts);

        return <div>
            <h1>Contact List</h1>
            {contents}
        </div>;
    }

    private static renderContactsTable(contacts: Contact[]) {
        return <table className='table'>
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Name</th>
                </tr>
            </thead>
            <tbody>
                {contacts.map(contact =>
                    <tr key={contact.id}>
                        <td>{contact.id}</td>
                        <td>{contact.name}</td>
                    </tr>
                )}
            </tbody>
        </table>;
    }
}

interface Contact {
    id: number;
    name: string;
    address: string;
    city: string;
    state: string;
    postalCode: string;
    phone: string;
    email: string;
}

Add Contact List to Navigation

Now that we have the contact list component it needs to be added to the navigation menu. The first step is to add it to the application’s router. This can be found in the routes.tsx file. The file is short so I am going to include the full content. Lines 7 and 13 are the ones added to handle our contact list.

import * as React from 'react';
import { Route } from 'react-router-dom';
import { Layout } from './components/Layout';
import { Home } from './components/Home';
import { FetchData } from './components/FetchData';
import { Counter } from './components/Counter';
import { ContactList } from './components/ContactList';

export const routes = <Layout>
    <Route exact path='/' component={Home} />
    <Route path='/counter' component={Counter} />
    <Route path='/fetchdata' component={FetchData} />
    <Route path='/contactlist' component={ContactList} />
</Layout>;

The last change is to add a navigation link to the NavMenu found in the NavMenu.tsx file. As I am sure most of us are used to adding an item to the nav menu is just adding a new li, but with the React specific NavLink bit.

<li>
  <NavLink to={'/contactlist'} activeClassName='active'>
      <span className='glyphicon glyphicon-th-list-alt'></span> Contact List
  </NavLink>
</li>

Wrapping Up

React is different than both Aurelia and Angular. Don’t take that as a good or bad thing. I don’t plan to pick on a side on the Angular vs React debate I just want to get a good feel for the different frameworks. So far the React experience has been pretty nice and I look forward to doing more exploration.

You can find the finished code for this post here.

Pass ASP.NET Core Appsettings Values to Angular

As part of getting my set of Identity Server 4 sample applications to run in Azure, I needed a way in the Client Application to pass some configuration values from appsettings.json to the Angular front end that could be used both during server-side rendering and client-side rendering. This application is using JavaScriptServices. This solution may need tweaking if your application isn’t using JavaScriptServices. The code for the client application can be found here.

Settings

In this example, we need to pass the address of our Identity Server and API from appsettings.json to Angular. The following is the settings file for this example.

{
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  },
  "IdentityServerAddress": "http://localhost:5000",
  "ApiAddress": "http://localhost:5001/"
}

Providing Configuration Data to Angular

In this application, Angular is loaded from the index action of the home controller. This view can be found in the Views/Home folder in the Index.cshtml file. The following is the file before any changes.

@{
    ViewData["Title"] = "Home Page";
}

<app asp-prerender-module="ClientApp/dist/main-server">Loading...</app>

<script src="~/dist/vendor.js" asp-append-version="true"></script>
@section scripts {
    <script src="~/dist/main-client.js" asp-append-version="true"></script>
}

The first change needed is to inject the configuration data using ASP.NET Core’s DI system. Add the following two lines at the top of the file.

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration

Now the configuration data from the application is available to this view. Next, we need to pull a couple of values out of the configuration data and pass it to the Angular application. To do this we are going to use the asp-prerender-data tag helper. You can read more about it in the official docs. The idea is you construct an object which is then serialized and stored in params.data. In our example, we are passing the URLs for the Identity and API Applications.

<app asp-prerender-module="ClientApp/dist/main-server"
     asp-prerender-data='new {
    apiUrl = Configuration["ApiAddress"],
    identityUrl = Configuration["IdentityServerAddress"]
}'>Loading...</app>

The above is creating a new object with an apiUrl property and an identityUrl property. The following is the full completed view for reference.

@using Microsoft.Extensions.Configuration
@inject IConfiguration Configuration
@{
    ViewData["Title"] = "Home Page";
}

<app asp-prerender-module="ClientApp/dist/main-server"
     asp-prerender-data='new {
    apiUrl = Configuration["ApiAddress"],
    identityUrl = Configuration["IdentityServerAddress"]
}'>Loading...</app>

<script src="~/dist/vendor.js" asp-append-version="true"></script>
@section scripts {
    <script src="~/dist/main-client.js" asp-append-version="true"></script>
}

Angular Server-Side Boot

When Angular gets prerendered on the server-side it runs the code in the boot.server.ts file. This is where we will set up the providers needed on for the server side prerender. This is the bit that I missed for the longest time when trying to get this example going. I kept trying to find a way to add the providers in the app.module.server.ts file. Add any providers you need to the providers constant. For example, the following is passing URLs for an API and Identity Server in addition to the defaults provided by JavaScriptServices.

const providers = [
    { provide: INITIAL_CONFIG, useValue: { document: '<app></app>', url: params.url } },
    { provide: APP_BASE_HREF, useValue: params.baseUrl },
    { provide: 'BASE_URL', useValue: params.origin + params.baseUrl }
    { provide: 'API_URL', useValue: params.data.apiUrl },
    { provide: 'IDENTITY_URL', useValue: params.data.identityUrl }
];

Lower in the same file we can pass through the configuration values to the client side render as globals on the window object. To do this add a globals property to the object being passed to the resolve call.

return new Promise<RenderResult>((resolve, reject) => {
    zone.onError.subscribe((errorInfo: any) => reject(errorInfo));
    appRef.isStable.first(isStable => isStable).subscribe(() => {
        // Because 'onStable' fires before 'onError', we have to delay slightly before
        // completing the request in case there's an error to report
        setImmediate(() => {
            resolve({
                html: state.renderToString(),
                globals: {url_Config: params.data}
            });
            moduleRef.destroy();
        });
    });
});

The above will have the URLs as part of a single object, but you could have each URL as its own property if you prefer.

Angular Client-Side

Now that the server-side has providers for API URL and Identity URL we need to provide the client-side with the same capabilities. These changes will be in the app.module.browser.ts file. The first step is to add providers for each.

providers: [
    { provide: 'ORIGIN_URL', useFactory: getBaseUrl },
    { provide: 'API_URL', useFactory: apiUrlFactory },
    { provide: 'IDENTITY_URL', useFactory: identityUrlFactory },
    AppModuleShared
]

Next, we need functions to return the URLs from the url_Config property of the window object which the following two functions do.

export function apiUrlFactory() {
    return (window as any).url_Config.apiUrl;
}

export function identityUrlFactory() {
    return (window as any).url_Config.identityUrl;
}

Wrapping Up

With the above, you can now use your configuration values from ASP.NET Core and pass them through to your Angular application. In hindsight, the process is pretty simple, but getting to that point took me much longer to figure out than I would like to admit. I hope this post saves you some time!

JavaScriptServices: What happen to Aurelia, Vue, and Knockout Templates

With the release of Visual Studio 2017 version 15.3 there are now built in web application templates for Angular, React, and React and Redux.

This is an awesome addition and makes creating new applications with the most popular frameworks simple. What do you do if your framework isn’t one of the top 3 options? JavaScriptServices can help out here and has provided templates for Aurelia, Vue, and Knockout in the past.

Where have they gone?

This is where it gets a little tricky as the templates still exist and are still being maintained, but finding them is a little harder at the moment for some reason. Yeoman was how JavaScriptServices was used in the past, but that has now transitioned to using the .NET CLI and can be added using the following.

dotnet new --install Microsoft.AspNetCore.SpaTemplates::*

After that is complete you will see a list of templates that are now available.

Now you can create an Aurelia project using the following command.

dotnet new aurelia

Wrapping up

I was very happy to see that support for the other frameworks hadn’t been dropped. There are a ton of other templates available for dotnet new which can be found here.

 

Identity Server: Introduction

In the SPA based sample applications, this blog has used so far user authentication has either been completely ignored in order to keep the examples simpler or the sites have used ASP.NET Core’s built in identity to encapsulate the whole SPA. In this post (or series of posts) I am going to share what I learn along the way of creating an Angular (2+) application that utilizes ASP.NET Core as its host/API/backend.

This post isn’t going to cover any code it is just going to be a lot of the information I gathered in the process of learning more about Identity Server.

Following are all the post in this series.

Identity Server: Introduction (this post)
Identity Server: Sample Exploration and Initial Project Setup
Identity Server: Interactive Login using MVC
Identity Server: From Implicit to Hybrid Flow
Identity Server: Using ASP.NET Core Identity
Identity Server: Using Entity Framework Core for Configuration Data
Identity Server: Usage from Angular

Identity Server

According to their docs IdentityServer4 is an OpenID Connect and OAuth 2.0 framework for ASP.NET Core which enables Authentication as a Service, Single Sign-on, API Access Control and a Federation Gateway.

Obviously, that covers a lot of scenarios. The two that I am interested in are Authentication as a Service and the API Access Control which has driven my research which means that the other aspects of IdentityServer4 will not be included.

Official Samples

The IdentityServer GitHub account has a samples repo that contains a ton of examples. I have found the quickstart area of the repo to be the most helpful when starting out.

Based on all the quickstarts samples it looks like a typical setup involves a minimum of three projects. One for the API, one for the client and one for Identity Server. As you go through the samples the number of projects increase, but that is because of a wider range of scenarios that the sample is trying to cover.

References for learning

Damienbod has a whole series of blog posts related to IdentityServer4 and code to go along with it which can be found here. As a side note if you are interested in ASP.NET Core and you aren’t following damienbo you should be he has a ton of great content.

Blog posts
Videos

Identity Server Alternatives

Identity Server isn’t the only way to go there is a number of Software as a Service options that cover a lot of same scenarios. The following are some examples.

Auth0 – Check out the .NET Core related blogs by Jerrie Pelser
Stormpath
Amazon Cognito

Wrapping up

Obviously, I didn’t get a lot covered on how to actually do something with IdentityServer, but I wanted to share my starting point. This is an area I am going to continue digging it to and sharing information about as I learn more.

If you have any resources in this area please leave a comment below.

Upgrading a JavaScript Services Application

As part of the ASP.NET Core Basics series of posts, JavaScript Services was used to create a couple of front end for a basic contacts API using Aurelia and Angular 2. Theses applications were created a few months ago and JavaScript Services has kept moving since then. This post is going to look at one strategy for taking an application created on an older version of JavaScript Services and update it to match the current version. This post will be following the upgrade of the Angular project from ASP.NET Core Basics repo with the starting point of the code being from this release.

The strategy

One of the considerations when doing this upgrade was getting the changes that happen on the ASP.NET Core side of the application and not just the JavaScript bits. In order to make sure that nothing was missed I decided to use JavaScript Services to generate a new application and use that to compare with the implementations in the existing application.

Create comparison application

This is going to assume JavaScript Services is already installed. If it isn’t this page has instructions or this post has sections that deal with creating a new application using JavaScript Services.

The update

Following is the files that changed during this update. This is also the list of files I would check anytime an upgrade needs to be done.

Angular.csproj
ClientApp/boot-client.ts
ClientApp/boot-server.ts
Program.cs
package.json
webpack.config.js
webpack.config.vendor.js

There were a fair amount of changes in the files listed above and instead of posting the code the differences can be found here. The previous diff didn’t contain the webpack.config files and those diffs can be found here and here.

After all the files have been updated make sure to run the following command from a command prompt in your project directory to make sure webpack has vendor related items regenerated.

webpack --config webpack.config.vendor.js

Wrapping up

This post is a lighter on the details that I do most of the time, but this type of upgrade would just have been a wall of code and not been overly useful and the commits on GitHub are a much better guide to what the upgrade looked like. My feeling is that over time the number of changes going forward may end up being smaller and easier to integrate.

Both the Aurelia and Angular projects have been upgraded and the final version of the code can be found here.

Aurelia with JavaScriptServices: Call to Node module failed

This is going to be a quick post on how to solve an error I go on a new Aurelia project created using JavaScriptServices. For a walk though of creating a project using JavaScripServices check out this post.

The problem

The project got created and would build with no issues, but when I tried to run it I got the following error.

Call to Node module failed with error: Error: Cannot find module ‘./wwwroot/dist/vendor-manifest.json’

The fix

After a little bit of searching I came across this issue on the JavaScriptServices repo with the same error. One of the comments on the issue suggested running the following command from a command prompt in the same directory as your project.

webpack --config webpack.config.vendor.js

After running that command everything worked like a charm! It is worth noting that the command above can be found in project.json in the scripts prepublish section. From the little bit of reading I did it looks like this command should be rerun anytime a new vendor dependency is added.

JavaScriptServices

I can’t get over how awesome JavaScriptServies is. Steve Sanderson (and team) have done an amazing job. Even with this little hiccup I got this new project up and running 10 times faster than I would have otherwise. It is also going to give me a push to look into webpack.

Angular 2 with ASP.NET Core using JavaScriptServices

This was going to be the fist in a series of posts covering getting started using the RTM versions of ASP.NET Core and Angular 2 together which was going to follow a similar path as the series on Aurelia and ASP.NET Core the first entry of which can be found here.

In the process of writing this post I was reminded of JavaScripServices (they recently added Aurelia support!) and will be using it to get this project up and running instead of doing the work manually.

The code found here can be used as a starting point. The repo contains a solutions with an ASP.NET Core API (Contacts) project and a MCV 6 (Aurelia) project. This post will be add a new MVC 6 project for Angular 2.

JavaScriptServices introduction

JavaScriptServices is an open source project by Microsoft for ASP.NET Core developers to quickly get up and running with one of many JavaScript front ends. The following is their own description.

JavaScriptServices is a set of technologies for ASP.NET Core developers. It provides infrastructure that you’ll find useful if you use Angular 2 / React / Knockout / etc. on the client, or if you build your client-side resources using Webpack, or otherwise want to execute JavaScript on the server at runtime.

The great thing about using the generator that JavaScriptServcies provides is they handle the integration between all the different tools which can be challenging to get right on your own without a lot of time and research.

Project creation

First step is to install the Yeomen generator via npm using the following command from a command prompt.

npm install -g yo generator-aspnetcore-spa

When installation is complete create a new directory call Angular for the project. In the context of the repo linked above this new directory would be in Contact/src at the same level as the Aurelia and Contacts folders.

Open a command prompt and navigate to the newly created directory and run the following command to kick off the generation process.

yo aspnetcore-spa

This will present you will a list of frameworks to choose from. We are going with Angular 2, but Aurelia, Knockout, React and React with Redux are also available.

yoangular2

Hit enter and it will ask for a project name which gets defaulted to the directory name so just hit enter again unless you want to use a different name. This kicks off the project creation which will take a couple of minutes to complete.

Add new project to existing solution

To include the new Angular project in an existing solution right click on the src folder in the Solution Explorer and select Add > Existing Project.

addexisitingproject

This shows the open file dialog. Navigate to the directory for the new Angular project and select the Angular project file.

addexisitingprojectangular

Wrapping up

Set the Angular project as the start up project and hit run and you will find yourself in a fully functional Angular 2 application. It is amazing how simple JavaScriptServices makes getting started with a new project.

The tool setup seems to be one of the biggest pain points with any SPA type JavaScript framework. Aurelia is a little friendlier to ASP.NET Core out of the box than Angular 2, but it still isn’t the simplest process ever. JavaScriptServices is one of those thing I wish I had tried out sooner.

In the near future I am going to redo the Aurelia project in this solution using JavaScriptServices. From there I will come back to the Angular project created in this post and integrate it with the Contact API used in the existing Aurelia application.

Completed code for this post can be found here.

Upgrading to npm 3 or 4

As part of writing a post on getting Angular 2 working with ASP.NET Core I needed to upgrade to npm verson 3. All went well on my main machine, but when I tried it on my laptop things didn’t go so well. No matter how many times I ran npm install -g npm the version returned via npm -v always returned 1.4.9.

After a bit of googling I came across this post on Stack Overflow. The post also points to npm’s github wiki on the upgrade process which can be found here. I am going to go over the option that I used to get my laptop upgraded.

Open an administrator command prompt and navigate to the install directory for nodejs. This should be either C:\Program Files (x86)\nodejs or C:\Program Files\nodejs and then run npm install [email protected].

Now if you run npm -v you should see a 3.x version of npm.

npm 4

Since writing this npm 4 has come out. The above should still apply if you find that npm is stuck as a previous version. Check out the npm release notes page for details.

Aurelia with ASP.NET Core: Host Aurelia from a Controller

This is the forth entry in a series using Aurelia and ASP.NET Core together. Each post builds on the previous and all the code is available on Github.

Part 1 – Add Aurelia to an ASP.NET Core Project
Part 2 – Aurelia with an ASP.NET Core API
Part 3 – Aurelia with an ASP.NET Core API: Modeling and Displaying Data in Aurelia
Part 4 – Aurelia with ASP.NET Core: Host Aurelia from a Controller (this post)
Github repo with the code for all of the parts with a release to go with each post

The goal

So far the Aurelia application in this series has existed outside of the the ASP.NET Core application. This post is going move the Aurelia application to be hosted by a MVC controller and a razor view. This would allow an existing application to slowly be ported to Aurelia or allow portions of an application to be replaced by Aurelia as it made sense, etc.

The controller

The controller isn’t going to be doing much other than returning a view that contains the entry point for the Aurelia application. This example will be using a new Aurelia  action on the HomeController.

public IActionResult Aurelia()
{
    return View();
}

The view

Next create a view in the Views/Home folder named Aurelia.cshtml to match the name of the action added to the HomeController above. Right click on the Home folder and select Add > New Item.

addnewitem

This will show the Add New Item dialog. Using the search in the upper right corner serach for MVC and select MVC View Page. Enter Aurelia.cshtml as the name and click Add.

Enter the following in the newly created file.

<div aurelia-app="main">
    <script src="/scripts/vendor-bundle.js" data-main="aurelia-bootstrapper"></script>
</div>

This code defines a div that will host an Aurelia application named main.

Add a link to the Aurelia application

Inside of the Views/Shared folder open _Layout.cshtml which is where the MVC application’s navigation bar is defined. Locate the navigation bar code and add a list item and link that points to the HomeController Aurelia action defined above. The following is the full navigation bar for the MVC application including the new link for Aurelia.

<div class="navbar-collapse collapse">
    <ul class="nav navbar-nav">
        <li><a asp-area="" asp-controller="Home" asp-action="Index">Home</a></li>
        <li><a asp-area="" asp-controller="Home" asp-action="Aurelia">Aurelia</a></li>
        <li><a asp-area="" asp-controller="Home" asp-action="About">About</a></li>
        <li><a asp-area="" asp-controller="Home" asp-action="Contact">Contact</a></li>
    </ul>
</div>

Adjust Aurelia’s baseUrl

Finally inside the aurelia_project folder open aurelia.json and adjust the baseUrl property inside the targets section to look for the scripts folder to be up one directory. This is required now with the Aurelia application being hosted inside the HomeController which will cause the Aurelia application to look for its scripts in the Home/Scripts folder instead of the site’s main scripts folder. If you are going to have multiple Aurelia applications per MVC application then you may need to take a different path on this section.

Before:
"build": {
  "targets": [
    {
      "id": "aspnetcore",
      "displayName": "ASP.NET Core",
      "output": "wwwroot\\scripts",
      "baseUrl": "scripts"
    }
  ]

After:
"build": {
  "targets": [
    {
      "id": "aspnetcore",
      "displayName": "ASP.NET Core",
      "output": "wwwroot\\scripts",
      "baseUrl": "../scripts"
    }
  ]

Wrap up

Run the application and click the Aurelia link in the navigation bar and the Aurelia application from last week will run, but now it will still have the navigation bar from the MVC application showing. The index.html file located in the wwwroot folder that was previously used to host the Aurelia application can be deleted.

The code associated with this post can be found here.