Migrating from the old ASP.NET Core Angular Spa template to the newer one

Client Side Changes:

If you are using the ASP.NET Core Angular SPA template that has been shipped with the .NET Core 2.0 release of the framework, you will have the following project structure.

Assuming that you put your application scripts under the ClientApp/app folder. So, before migrating, take a back up of the folder.

Delete the ClientApp folder altogether. We will generate the folder with the Angular CLI. On the project root directory, open up a command prompt window and generate an Angular app by running the following the CLI command,

ng new ClientApp

If you don't have the Angular CLI installed already. Install it with the following npm command

npm install -g @angular/cli

Once the CLI scaffolds an Angular application in the ClientApp folder, you should have the following application structure.

Now replace the current app folder with your previously backed up app folder. You can delete the app.module.browser.ts and app.module.server.ts file. Rename the app.module.shared.ts to app.module.ts. Open the renamed file and do the following changes:

  • Import BrowserModule from angular and add it in the imports array:
    • import { BrowserModule } from '@angular/platform-browser';
  • Add and configure a bootstrap property under @NgModule. Add the AppComponent in the in the array,
    • bootstrap: [AppComponent]
  • Rename AppSharedModule to AppModule
  • Depending on the selector name of your bootstrap component, change the selector name in index.html if you need to e.g. <app-root> to <app>

Configure your application base url in the main.ts file. Add the following scripts after the imports in main.ts file,

  export function getBaseUrl() {
    return document.getElementsByTagName('base')[0].href;

  const providers = [
    { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] }
  • Pass the providers array as parameter in platformBrowserDynamic(),
  .catch(err => console.log(err));

Client side npm dependencies should be installed on the ClientApp root. So, extract the packages from the package.json that is on your project root directory and add them in the package.json file under the ClientApp folder. Once done, do a npm install to restore the packages.

Now you should be able to run just the Angular application by executing the following CLI command on the ClientApp folder,

ng serve

Server Side Changes

Remove the old Microsoft.AspNetCore.SpaServices references from Startup.cs,

  • Remove using statements: using Microsoft.AspNetCore.SpaServices.Webpack;
  • Remove app.UseWebpackDevMiddleware middleware
  • Remove fallback route for SPA files: routes.MapSpaFallbackRoute
  • Install the new SpaServices package extension from Nuget:
    • In VS Package Manger Window: Install-Package Microsoft.AspNetCore.SpaServices -Version 2.0.1
    • From dotnet CLI: dotnet add package Microsoft.AspNetCore.SpaServices --version 2.0.1
  • In ConfigureServices(), add a new service AddSpaStaticFiles and configure it as following,
    services.AddSpaStaticFiles(configuration =>
        configuration.RootPath = "ClientApp/dist";
  • Also add the UseSpaStaticFiles middleware in the Configure method, app.UseSpaStaticFiles();
  • Add the using statement, using Microsoft.AspNetCore.SpaServices.AngularCli; to work with the AngularCLI.
  • Add and configure app.UseSpa() middleware as following
    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");
  • .csproj file need some modifications. Basically, you just have to keep the <PackageReference> and change everything. However, I'm providing the whole new .csproj files. You can extract and add the information needed to your .csproj file,
<Project Sdk="Microsoft.NET.Sdk.Web">


    <!-- Set this to true if you enable server-side prerendering -->

    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.3" />
    <PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="2.0.0-preview1-final" />

    <DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.1" />

    <!-- Don't publish the SPA source files, but do show them in the project files list -->
    <Content Remove="$(SpaRoot)**" />
    <None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />

  <Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
    <!-- Ensure Node.js is installed -->
    <Exec Command="node --version" ContinueOnError="true">
      <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
    <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." />
    <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />

  <Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
    <!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build -- --prod" />
    <Exec WorkingDirectory="$(SpaRoot)" Command="npm run build:ssr -- --prod" Condition=" '$(BuildServerSideRenderer)' == 'true' " />

    <!-- Include the newly-built files in the publish output -->
      <DistFiles Include="$(SpaRoot)dist\**; $(SpaRoot)dist-server\**" />
      <DistFiles Include="$(SpaRoot)node_modules\**" Condition="'$(BuildServerSideRenderer)' == 'true'" />
      <ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">

  • Remove the webpack.vendor.config.js and webpack.config.js from the client root.

At this point you are done if you don't have/want SSR in your application.

Remove Unnecessary files (Be careful!)

  • Remove the Views folder from the project root (if you want). Because we no longer need asp-prerender-module for SSR and also the index.html file under ClientApp/scr is the new entry point where the Angular application is rendered.

Enabling SSR

In the previous templates we used to have a TagHelper, asp-prerender-module to enable Server Side Rendering support in our Angular apps. We no longer need this TagHelper and also we don't have any specific placeholder in some razor view where the whole client application is rendered. Instead the index.html under ClientApp/scr is the main entry point of our application. The official documentation talks at length about how to enable SSR in the following url,