Skip to main content

Implement ASP.NET Core SPA template features in an Angular 6 app

Earlier, I posted about creating an angular 6 based app with VS 2017. It’s a pure Angular 6 app and doesn’t use features comes with the ASP.NET Core SPA template. At the time of writing this post, default ASP.NET Core SPA template for angular points to angular 5. The SPA template uses angular on the client side and ASP.NET Core as back-end. It uses a package Microsoft.AspNetCore.SpaServices as a middleware to provide different configurable options for your application such as HMR (Hot Module Replacement), Routing Helper, SSR (Server Side Rendering) etc.. In this post, let’s find out how to create an angular 6 app with ASP.NET Core 2.1 and implement ASP.NET Core SPA template features in the same app.

If you want to learn all of Angular, I want to personally recommend ng-book as the single-best resource out there. You can get a copy here.

Implement ASP.NET Core SPA template features in an Angular 6 app

Before we begin, please do the following installation (ignore if already done).

Open Visual Studio 2017, hit Ctrl+Shift+N and select the ASP.NET Core Web Application (.NET Core) project type from the templates. When you click Ok, you will get the following prompt. Select ASP.NET Core 2.1 and choose the API template.

How to create an Angular 6 app with Visual Studio 2017

The Visual Studio will create an ASP.NET Core 2.1 based Web API project with a controller named ValuesController. Just run the app to make sure it is running successfully.

Now, let’s add Angular 6 app to this project through Angular CLI. To do that, open command prompt and navigate to the project folder directory. First, install/update the Angular CLI using the following command.

npm install -g @angular/cli

To create angular 6 based app, navigate to the ASP.NET Core project root folder (where the project’s .csproj file is present) and run the following command.

ng new ClientApp

This will take some time to create the app. Once created, the project structure will look like the following.

Angular 6 App Structure

To configure SPA template features, we need to add support for Microsoft.AspNetCore.SpaServices middleware. To do that, open Startup.cs and registers the SPA service that can provide static files to be served for a Single Page Application (SPA). The ConfigureServices method looks like:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    services.AddSpaStaticFiles(c =>
    {
        c.RootPath = "ClientApp/dist";
    });
}

Here, the published scripts/files/images will be copied to the dist folder inside the ClientApp, hence configuration.RootPath = "ClientApp/dist".

Next, we need to add SPA middleware to the pipeline. We can do that inside the Configure method. So, the Configure method looks like:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseSpaStaticFiles();
    app.UseMvc(routes =>
    {
        routes.MapRoute(name: "default", template: "{controller}/{action=index}/{id}");
    });

    app.UseSpa(spa =>
    {
        // To learn more about options for serving an Angular SPA from ASP.NET Core,
        // see https://go.microsoft.com/fwlink/?linkid=864501

        spa.Options.SourcePath = "ClientApp";

        if (env.IsDevelopment())
        {
            spa.UseAngularCliServer(npmScript: "start");
        }
    });
}

Finally, delete "launchUrl": "api/values" from the Properties/launchSettings.json file. Build the app and run it. You should see the following.

Implement ASP.NET Core SPA template features in an Angular 6 app

Let’s us extend this application and call the ValuesController API from the angular app. To do that, open app.component.ts and add code to call the API using HTTPClient.

import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
  public values: string[];
  constructor(private http: HttpClient) {
    this.http.get('/api/values').subscribe(result => {
      this.values = result as string[];
    }, error => console.error(error));
  }
}

Next, import HTTPClient in app.module.ts.

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

import { AppComponent } from './app.component';

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

Finally, add the following HTML to app.component.html to display the values returned by the API.

<h3>Data coming from server values API</h3>
<ul>
  <li *ngFor="let value of values">
    {{ value }}
  </li>
</ul>

Run the app and you should see the values returned from the API.

Implement ASP.NET Core SPA template features in an Angular 6 app

That’s it.

Thank you for reading. Keep visiting this blog and share this in your network. Please put your thoughts and feedback in the comments section.

PS: If you found this content valuable and want to return the favour, then Buy Me A Coffee

30 thoughts on “Implement ASP.NET Core SPA template features in an Angular 6 app

  1. The first tutorial had “Here, the angular app name must be same as your project name.” but this one is different with “ng new ClientApp”. If you do a “ng new Angular6SPAApp” as per first tutorial and use “c.RootPath = “ClientApp/dist”;” code from second tutorial you get “directory is invalid” npm exception.

  2. My previous comment should have been paired with this change to angular.json:
    “options”: {
    “outputPath”: “wwwroot”,

    That way, when I mentioned the following, the Angular “ng build” process will put the files where the Visual Studio 2017 Publish command will expect them to reside, which will result in a successful deployment (to Azure Web Services, for example).

    // In production, the Angular files will be served from this directory
    services.AddSpaStaticFiles(configuration =>
    {
    configuration.RootPath = “wwwroot”;
    });

  3. Correct me if I misunderstand, but instead of pointing to ClientApp/dist, shouldn’t the ConfigureServices method of Startup.cs point to wwwroot? If you publish the application to Azure Web Services, isn’t wwwroot the ONLY place it will look for files?

    // In production, the Angular files will be served from this directory
    services.AddSpaStaticFiles(configuration =>
    {
    configuration.RootPath = “wwwroot”;
    });

  4. Hi people,
    I have a big problem with tha implementation.
    With that crazy arquitecture, is dificult to understant how ASP.NET core is using Angular.
    Now iam trying to call an API from the Angular inside de ASP.NET core, but, I got this error:
    “Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘https://localhost:5001’ is therefore not allowed access.”
    (I use wappalyzer and it says i’am usin Node.js with node.expres.js??????????????????????????????????????????????????)
    I already defined the httpoption, new httpHeaders inside Angular like:
    const httpOptions = {
    headers: new HttpHeaders({
    ‘Content-Type’: ‘application/json’,
    ‘Access-Control-Allow-Origin’:’*’
    })
    .
    .
    .
    and the same in my services at startup.cs like:
    public void ConfigureServices(IServiceCollection services)
    {
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    services.AddSpaStaticFiles(c =>
    {
    c.RootPath = “ClientApp/dist”;
    });
    services.AddTransient(_ => new AppDb(Configuration[“ConnectionStrings:DefaultConnection”]));

    // ********************
    // Setup CORS
    // ********************
    var corsBuilder = new CorsPolicyBuilder();
    corsBuilder.AllowAnyHeader();
    corsBuilder.AllowAnyMethod();
    corsBuilder.AllowAnyOrigin(); // For anyone access.
    corsBuilder.WithOrigins(“https://localhost:5001”); // for a specific url. Don’t add a forward slash on the end!
    corsBuilder.AllowCredentials();

    services.AddCors(options =>
    {
    options.AddPolicy(“SiteCorsPolicy”, corsBuilder.Build());
    });
    }
    Can any one generate a grat post to explain explicitly how Angular is running inside ASP.Net core?????
    I think all new ASP.Net Core users will apreciatte it a lot
    Thank you a lot in advance
    Noop

  5. Thank you, awesome work. I got you a coffee.

    Publishing however does not handle the web content properly. (the dist folder is missing from the output)
    I guess this is because we did not use the angular template.

    Could you write an article or enhance this one how to publis everything?

  6. Awesome work. I got you a coffe.

    Unfortunatelly when I try to publish my application the web content is missing.

    I guess this is because we don’t use the angular SPA template where the dist files are copied.
    Could you create a post where this is described or enhance this one?

  7. Hi. Thanks for great post. But How can I implement SASS with the new Angular 6 core structure which webpack.config file has gone.

    1. When generating the ClientApp, use the following to have the default styling file extension changed from .css to .scss. Tested with Angular-CLI 6.0.8 and Angular 6.0.4.

      ng new ClientApp –style=scss

  8. Hi Friends ,
    My Project running fine where i Publish code and host on IIS is not running because index page is not getting

  9. Thanks for the great post. However, the app is failed to render the new changes. I mean, when I change the TS or HTML files, it should render automatically. How can I do this?

        1. The angular app at http://localhost:4200/ got failed to access the VS web project, says http://localhost:3737/, is because of the browser’s same origin policy. It is a normal safety measure. Web browser treats the difference in port numbers as two different domain/origin and thus making ajax call from :4200 to :3737 (and any other port numbers) will always fail.

          But there is way to “bypass” this safety measure (during development only!) — simply by adding a HTTP header “Access-Control-Allow-Origin: http://localhost:4200” at all (ajax) response returned by server.
          We can achieved it by adding below code at “Startup.cs”:

          #code#
          public void Configure(IApplicationBuilder app, IHostingEnvironment env)
          {
          if (env.IsDevelopment()) // only add such header at dev env!
          {
          // To favour development and testing with angular app. Remember NOT to add a trailing slash
          // Ref: https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1#enabling-cors-with-middleware
          app.UseCors(builder =>
          builder.WithOrigins(“http://localhost:4200”) // 4200 is the port number consumed by angular app from “ng serve”
          );
          }
          }
          #/code#

  10. Thank you, very useful.
    Only that I’ve made this project and thought It were fine to add a support real HMR (now there’s reload a whole page “on save” and this is not very good).
    After a short search I’ve found the page:
    https://github.com/angular/angular-cli/wiki/stories-configure-hmr
    But here there are some moments that need to be corrected.
    1. In angular.js:

    “build”: {
    ….
    “configurations”: {
    “production”: {
    ………………
    },
    “hmr”: {
    “fileReplacements”: [
    {
    “replace”: “src/environments/environment.ts”,
    “with”: “src/environments/environment.hmr.ts”
    }
    ]
    }
    }
    }
    ….

    “serve”: {
    “configurations”: {
    “production”: {
    ………
    }
    “hmr”: {
    “hmr”: true,
    “browserTarget”: “[APP_NAME]:build:hmr” (правильно, [APP_NAME] заменить на имя своего приложения)
    }
    }
    },

    2. In the file ClientApp/src/tsconfig.app.json delete the line:

    “types”: []

    3. Int the file ClientApp/src/main.ts replace the line

    hmrBootstrap( module, bootstrap );

    by

    hmrBootstrap( module, bootstrap );

    4. And, of course, in Startup.cs replace a name of the called script:

    spa.UseAngularCliServer( npmScript: “hmr” );

    I would be happy if I could help someone.

    1. (правильно, [APP_NAME] заменить на имя своего приложения) – ignore.

      In 3) in the second “hmrBootstrap( module, bootstrap )”; just ytbefore “bootsrap” it is necessary to put expression !any!, where instead of the sign “!” use angle brackets (they disappeared in my previous comment on the dispatch).

  11. When I build the application I got the below error

    Severity Code Description Project File Line Suppression State
    Error CS1061 ‘ISpaBuilder’ does not contain a definition for ‘UseAngularCliServer’ and no extension method ‘UseAngularCliServer’ accepting a first argument of type ‘ISpaBuilder’ could be found (are you missing a using directive or an assembly reference?) Web2018 C:Web2018Web2018Startup.cs 63 Active

    I got error when I write below code
    spa.UseAngularCliServer(npmScript: “start”);
    I already install the “Install-Package Microsoft.AspNetCore.SpaServices -Version 2.1.0”

    Can you please tell me what was problem.

    1. Include following line in your Startup.cs,

      using Microsoft.AspNetCore.SpaServices.AngularCli;

      Also install Microsoft.AspNetCore.SpaServices.Extension nuget package, if not installed. Although it should be installed.

        1. NPM (Node package manager) is not installed. Please check the post for list of installation required. If it is installed, then make sure the entry is there in Environment PATH variables.

          1. Bob,

            There is something wrong either with NPM or Angular CLI. Make sure both are installed and available in PATH variables. Angular CLI should be installed globally as Visual Studio will start the angular CLI server to run the app.

          2. What is weird is this worked fine until I added the the Spa stuff. I had followed your last tutorial and everything ran fine. Once I added the SPA items from this blog, it blew up. I will try re-installing Angular. I have already re-installed Node but that did not help.

          3. That’s weird. As I followed the same steps and it worked fine. There is one change compare to last tutorial. The angular app needs to be created at ASP.NET Core project root folder (where the project’s .csproj file is present).

Leave a Reply

Your email address will not be published. Required fields are marked *