Monthly Archives: October 2017

How to structure a SPA using Angular CLI and ASPNET Core 2.0?

This article describes step by step how to structure a SPA made out of Angular for the client and ASPNET Core 2.0 for the backend.

When integrating these technologies you get a lot of options to choose from.  The first one is to decide if you should host your app inside an MVC View or just serve the angular app from static files.  After experimenting with both options, I decided that I should go for the simplest solution that could possibly work and started with just serving static files inside a Web-Api application.

For the project structure I prefer to completely separate both projects in folders beside each other. Nevertheless, I deploy the Angular app inside the same ASP.NET site that serve also the web-api.  Therefore, I need to bundle everything together when publishing the app.  To achieve this, I call the “ng build” from MsBuild targets and configured angular-cli to output the build in the \wwwroot folder of the ASP.NET app.

Concerning the IDE, what I found the most productivity was to develop my angular app using Vs.Code.  Thus far, for the Web-Api part I tend to prefer VisualStudio and Resharper. So, I optimized my Angular app for working with Vs.Code and my Web-Api project for VisualStudio.  During development I usually run the backend and launch the Webpack dev server through an “npm start” command.  At publish everything is nicely packaged together inside a ASP.NET app, so deploying to Azure can simply be done by using the VisualStudio publish wizard.

This article is a step by step guide demonstrating how to setup your dev environment following the configuration just described here above. If you’re an experienced Angular & Web-Api developer and only need an overview you can go to my  github project core-angular-example.  There you can download the solution template I use for making SPA’s with Angular-cli and DotNet Core.

For the less experienced developers you can follow this step by step guide to get started.

Prerequisites

To follow along you’ll need to install following things (just follow install guide):

1. Create the new App

Because I’m very enjoying the “dotnet” command line I propose to start our app with the  “dotnet new” and use the web-api template.  To create our Angular app we’ll do something similar but with the ng new command from Angular-Cli.

Start a new command prompt/shell and navigate to the folder you want to create your app in (root). Copy/Paste following commands:

mkdir angular-dotnetcore
cd angular-dotnetcore
mkdir web-api
cd web-api
dotnet new webapi
cd ..
ng new angular-app

2. Open your app with VS.Code

Start Vs.Code and choose file, open folder.  Navigate to the root of your app.

3. Disable TypeScript Compilation

Since we will eventually have TypeScript files in our project and we only want to compile/run them through angular-cli we should disable any TypeScript compilation. Open the web-api.csproj file and modify the top PropertyGroup:

<PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
    <TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
    <IsPackable>false</IsPackable>
  </PropertyGroup>

4. Configure Startup.cs

As our web-api app will also serve the static files we need to configure the Stratup.cs file as follow


public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseDefaultFiles();
    app.UseStaticFiles();

    app.Use(async (context, next) => {
        await next();
        if (context.Response.StatusCode == 404 &&
            !Path.HasExtension(context.Request.Path.Value) &&
            !context.Request.Path.Value.StartsWith("/api/")) {
                context.Request.Path = "/index.html";
                await next();
            }
    });

    // Configure application for usage as API
    // with deafult route '/api/[Controller]'
    app.UseMvcWithDefaultRoute();

    // Serve static files
    app.UseStaticFiles();
}

5. Configure Angular CLI

Configure angular-cli to output the build inside the wwroot of the web-api app =>
edit the .angular-cli.json file and change the OutDir parameter:

"apps": [
    {
      "root": "src",
      "outDir": "../web-api/wwwroot",

Now when running ng build inside the angular-app angular-cli should output the result inside the wwroot folder of the web-api app.

6. Modify the app to display data coming from the backend

Modify the angular app to consume data from your web-api
Edit the following files under /angular-app/src/app file=>

App.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { HttpModule } from '@angular/http';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component, OnInit } from '@angular/core';
import { Http } from '@angular/http'
@Component({
   selector: 'app-root',
   templateUrl: './app.component.html',
   styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
   constructor(private _httpService: Http) { }
   title = "DotNet Core Angular Example";
   apiValues: string[] = [];
   ngOnInit() {
      this._httpService.get('/api/values').subscribe(values => {
         this.apiValues = values.json() as string[];
      });
   }
}

Edit app.component.html and add this as last lines of the html file:



<li>


<h2>Values from ValuesController</h2>


    

{{value}}

  </li>


</ul>


7. Redirect api calls to your DotNet core app

To be able to redirect api calls from your angular app when running in the webpack dev server you should create a proxy.conf.json file on the root of your angular app. Here my dotnet webapi runs on port 5000:

{
    "/api": {
      "target": "http://localhost:5000/",
      "secure": false
    }
}

Now you can test this part by:
– run the web-api with:
dotnet run
– launch the angular app and pass the proxy configuration:
ng serve –proxy-config proxy.conf.json
– Open Chrome on:
http://localhost:4200/

8. Configure npm proxy scripts to run and build the Angular app
edit the package.json of the angular-app and edit the script section:

"scripts": {
    "ng": "ng",
    "start": "ng serve --proxy-config proxy.conf.json",
    "build": "ng build",
    "build-prd": "ng build --prod --env=prod",

9. Create proxy scripts to run the npm commands from the web-api project

{
    "name": "core-angular-example",
    "version": "0.0.0",
    "license": "MIT",
    "scripts": {
        "install": "cd ../angular-app & npm install",
        "start": "cd ../angular-app & npm start",
        "build": "cd ../angular-app & npm run-script build",
        "build-prd": "cd ../angular-app & npm run-script build-prd"
    }
}

10. Setup MsBuild to compile the Angular app

Finally, we configure our web-api MsBuild script to invoke the ng build script when running a release build. Therefore, we add the following targets to the project webapi.csproj file:

<Target Name="EnsureNode">
  <Exec Command="node --version" ContinueOnError="true">
    <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
  </Exec>
  <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
</Target>

<Target Name="ReleaseRunNgBuild" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Release' ">
  <CallTarget Targets="EnsureNode" />
  <Message Importance="high" Text="Install packages..." />
  <Exec Command="npm install" />
  <Message Importance="high" Text="Performing ng build for prd build..." />
  <Exec Command="npm run-script build-prd" />
</Target>

Now when you launch a Release build everything will be build together.

You can get a package containing all your app by using the publish command.
If you want to publish your app to Azure simply use the VisualStudio publish wizard or the Azure Powershell Publish commands.