Tutorial: How to use Angular CLI with DotNetCore

In this post we’ll explore how to use the Angular CLI to build an application hosted inside a DotNetCore.1.1 web api project. The code that accompanies this post can be found here.

1.      Create a new WebApi application

Open a command line and use the following commands to generate your WebApi project.

mkdir AngularDotNetCore
cd .\AngularDotNetCore\
dotnet new webapi

2.     Configure the WebApi project for Angular

    1. Open the project with Vs Code and edit the .csproj
    2. Disable the automated compilation of typescript as it will be handled by the Angular-cli (line 4)
    3. Add a reference to the Microsoft.AspNetCore.StaticFiles package so that we’ll be able to serve static files from the “/wwwroot” (line 13)
<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp1.1</TargetFramework>
    <TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
  </PropertyGroup>

  <ItemGroup>
    <Folder Include="wwwroot\" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.2" />
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.1.1" />
    <PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.2" />
  </ItemGroup>
  <ItemGroup>
   <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" />
  </ItemGroup>
</Project>

c. To install the new packages run:

dotnet restore

3. Modify Startup.cs

  1. Redirect all non API requests to the index.html page. (line 6-14)
  2. Configure the app to serve static files and use the index.html as default page. (line 17-23)
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

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

    // use default route /api/[controller] 
    app.UseMvcWithDefaultRoute();

    // use index.html as default page
    app.UseDefaultFiles();
    
    // serve static pages
    app.UseStaticFiles();
}

3. Initialize the Angular App through Angular-CLI

  1. a. Install Angular-CLI
    npm install @angular/cli --global
    
  2. b. Create the Angular app
    ng new my-app --skip-install
    
  3. c. Move to the root all the content of your “my-app” folder
    mv .\my-app\* .\
    
  4. d. Delete the “my-app” folder:
  5. e. Define the “wwwroot” as the Angular-CLI output directory.
    Edit the .angular-cli.json and update the “apps” part (line 9):

    {
      "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
      "project": {
        "name": "my-app"
      },
    "apps": [
      {
        "root": "src",
        "outDir": "wwwroot",
        "assets": [
          "assets",
          "favicon.ico"
        ],
        "index": "index.html",
        "main": "main.ts",
        "polyfills": "polyfills.ts",
        "test": "test.ts",
        "tsconfig": "tsconfig.app.json",
        "testTsconfig": "tsconfig.spec.json",
        "prefix": "app",
        "styles": [
          "styles.css"
        ],
        "scripts": [],
        "environmentSource": "environments/environment.ts",
        "environments": {
          "dev": "environments/environment.ts",
          "prod": "environments/environment.prod.ts"
        }
      }
    ],
      "e2e": {
        "protractor": {
          "config": "./protractor.conf.js"
        }
      },
      "lint": [
        {
          "project": "src/tsconfig.app.json"
        },
        {
          "project": "src/tsconfig.spec.json"
        },
        {
          "project": "e2e/tsconfig.e2e.json"
        }
      ],
      "test": {
        "karma": {
          "config": "./karma.conf.js"
        }
      },
      "defaults": {
        "styleExt": "css",
        "component": {}
      }
    }
    
    
  6. f. Install the npm packages
    npm install
    
  7. g. Build and run the app
    ng build
    dotnet run
    
  8. If everything went fine you should see:

4. Call from Angular the WebApi backend

Here we’ll make a simple http call from our Angular application to our DotNetCore Web Api. We’ll query the generated example “ValuesController” from our Angular app and output the result onto our homepage. Because I want to make this example as simple as possible I make the call directly from the component but in a real application you’ll encapsulate this code into an Angular service.

  1. a. Edit the app.component.ts file:
    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 = 'app works!';
       values:string[] = [];
       ngOnInit() {
          this._httpService.get('/api/values').subscribe(values => {
             this.values = values.json() as string[];
          });
       }
    }
    
    
  2. b. Edit the app.component.html file:
    
    <h1>
      {{title}}
    </h1>
    
    
    
      Retrieved values:
    
    
    
    <ul *ngFor="let value of values">
      
    <li>{{value}}</li>
    
    </ul>
    
    
  3. c. Compile and run the app:
    ng build
    dotnet run
    

5. Configure your Angular application to auto update when code changes

The Angular-CLI can configure webpack to serve the application through his built-in server and refresh your page whenever a file changes. To launch this developer friendly mode use:

ng serve

Notice that when you open your browser on http://localhost:4200 (the webpack server default port) you don’t see any retrieved values anymore.

This is because our Angular application calls our REST API on http://localhost:4200/api/values but there’s nothing there! What we need to do is launch our WebApi application and redirect calls to it from port 4200.

  1. a. Create a “proxy.json” file on the root and add the following content to the file:
    {
       "/api": {
          "target": "http://localhost:5000",
          "secure": false
       }
    }
    
  2. b. Launch two consoles. One to run the webapi app:
    dotnet run
    

    The other to launch the webpack server with the proxy redirection:

    ng serve –proxy proxy.json
    
  3. c. You can also enable the auto refresh mode of your WebApi application. Edit the .csproj file and add following section and run “dotnet restore”:
      <ItemGroup>
       <DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="1.0.0" />
      </ItemGroup>
    
  4. d. Now you can launch also the WebApi in watch mode:
    dotnet watch run 

Of course, you’ll still need to refresh your page every time you change your webapi project but it will recompile & run automatically every time code is changed.

Have fun!

Leave a Reply