You would think that creating an ASP.NET Core application that uses Angular would be easy-peasy. After all, there’s an “Angular” option in the new project wizard for an ASP.NET Core application! Sadly, reality is a cruel mistress, and if you take that approach to creating your next Angular + ASP.NET Core project, you’ll be in for a world of hurt. Here’s a better approach.

Please note: This article was written for the .NET Core 2.0 project templates. The new .NET 2.1 templates, currently in preview, change things up for the better. Here’s an overview of the new template, including some improvements!

Credit where credit is due: this post was inspired by Levi Fuller’s take on the topic. I made a few changes along the way, but his approach got me started!

Friends Don’t Let Friends Use File -> New Project -> Angular

Let’s get this out of the way: yes, there is an easy-to-use, File -> New Project way to make an ASP.NET Core application with Angular. But you don’t want to use that.

This will give you an Angular 4x project built directly around Webpack. For reference, Angular 5 is the current production version of Angular, and Angular 6 is approaching release. Heck, there’s a good chance Angular 6 will be out before I get around to publishing this post!

But the out-of-date version of Angular isn’t the biggest reason you shouldn’t use the Visual Studio project template. The biggest is that it does not use the Angular CLI. Instead, it uses webpack directly. You don’t want that. You want to use the Angular CLI. It is the bee’s knees. Why?

Quite simply, because using it means you no longer need to manage your own build pipeline. And if that isn’t enough for you, it has numerous other handy capabilities, such as generating (and wiring up!) new components, producing optimized builds, serving content with hot reloading…

If you’re doing Angular development, you want to use the CLI!

And, aside from even that, the Visual Studio Angular template gives you a lot of junk you probably don’t need or want, such as the Razor view engine, a home controller, a (poorly) implemented starter project, etc.

So what do we do instead? Well, it turns out it’s remarkably easy to add Angular to an existing ASP.NET Core app using the CLI. Let’s try it out!

Creating a New Project

We are still going to start with a new ASP.NET Core project in Visual Studio. Choose the ASP.NET Core Web Application option…

On the next screen, choose to create a Web API project, not an Angular one!

Now we can fire up the command prompt (I use Hyper with Powershell, by the way), make sure we have the latest-and-greatest Angular CLI installed…

npm i -g @angular/cli

Now we are ready to create our new Angular project!

Warning: There’s a bug in the current version of Angular CLI that prevents you from creating a project inside a non-empty directory. We’re going to work around that, but in the future, this step shouldn’t be necessary!

We’ll use the ng new command to create our project.

Make sure you’re in the same directory as your new ASP.NET Core project (not the solution!), and execute the following command:

ng new my-project --skip-install

Want to start with routing enabled? Or would you rather use LESS or SASS instead of normal CSS? The ng new command has a lot of useful options. Check out the documentation for more information!

This will create our new project in a subfolder of our ASP.NET Core project.

Now we need to move those files up to the root of our project. This PowerShell command will do that and clean up the now-empty folder:

mv .\my-project\* .
rm .\my-project\

Now we just need to restore our npm packages.

I’ve had mixed results doing this initial restore from the command-line while Visual Studio is running. It seems like Visual Studio, somehow, interferes with things, leading to strange errors and a corrupted node_modules folder.

So instead, you should restore the packages by right-clicking on the npm folder under your project’s dependencies, and selecting “Restore Packages.”

Reconfiguring the Angular CLI

At this point, we have our ASP.NET Core app, and we have our Angular CLI app living alongside it. But we need to reconfigure things a bit to make them play nicely together.

See that .angular-cli.json file in the root of your solution? We can modify that file to change how the Angular CLI behaves.

By default, if we create a production build of our client-side app, the CLI will create a dist folder with our bundled JS, CSS, and HTML. That’s not what we want.

We want our files to go to the wwwroot folder that ASP.NET Core serves static files from. All we need to do is find the outDir setting and change it from dist to wwwroot:

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "my-project"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "wwwroot",
      //snip!
  ],
  //snip!
}

Now when we execute ng build, our Angular app will be output to the wwwroot folder, ready for publishing!

Running Locally

I’m a huge fan of eliminating as much friction as possible from your day-to-day development workflow. Unfortunately, this setup that we have now? It’s not going to work all that well for our day-to-day.

When we want to run our app locally, we’re going to need to do a few different things:

  1. Build and run our ASP.NET Core project.
  2. Start our Angular app by executing ng serve.
  3. Make sure our Angular app executes API calls against our locally-running ASP.NET Core project

Compare that to a “normal” ASP.NET Core application with MVC, where the workflow is basically:

  1. Press F5.

But don’t worry! We can fix this!

Leveraging Task Runner Explorer

The first thing we’ll do is configure our Angular application to be served immediately when we open our project. We can do that with Task Runner Explorer.

If you don’t have the Task Runner Explorer window visible already, you can show it by searching for Task Runner in the Visual Studio Quick Launch box:

Using Task Runner Explorer, right-click on the start task, go to Bindings, and set it to Project Open.

That will instruct Task Runner Explorer to run the start task immediately whenever you open the project.

Let’s improve on this just a bit. Let’s make the start task also open our Angular application in a new browser window.

In package.json, find the start task, and add the --open argument, like so:

{
  "name": "my-project",
  "version": "0.0.0",
  "license": "MIT",
  "scripts": {
    "ng": "ng",
    "start": "ng serve --open",
    //SNIP!
  },
  //SNIP!
}

Now we just need to make sure our Angular application calls our ASP.NET Core APIs.

Proxying Requests from Angular to ASP.NET Core

When we deploy this application to production, our Angular app and our ASP.NET Core Web APIs will be running on the same host.

We’ll load our Angular app by navigating to https://some.url/, and it will make calls to https://some.url/api/some/endpoint.

But when we’re running locally, we actually want our Angular app running on one host, and ASP.NET Core on another! That’s because the Angular CLI will serve our Angular app (with hot-reloading!) for us! And we get the same thing on the ASP.NET Core side from Visual Studio and dotnet run!

That means our Angular app and our ASP.NET Core app won’t be running on the same host. Our Angular app will be running on something like http://localhost:4200/, and our ASP.NET Core app will be running on http://localhost:56221.

There are a couple of ways to handle that.

One way is to use a proxy. That’s the approach Levi Fuller took .

If we were going to do that, we’d create a proxy configuration file, like so:

{
  "/api": {
    "target": "http://localhost:56221/api",
    "secure": false,
    "pathRewrite": {
      "^/api": ""
    }
  }
}

Then we’d run ng serve using its proxy parameter: ng serve --proxy-config proxy.config.json.

And that will work, but that’s not the option I like to use.

Leveraging Environment Configuration Files

Instead of using Angular’s proxy configuration, I prefer to use the built-in support for environments. This accomplishes the same thing while giving me flexibility to easily move my API somewhere external in the future, even in production, should the need arise.

My default environment file looks like this:

export const environment = {
  production: false,
  apiUrl: 'http://localhost:56221/api'
};

Now I can use environment.apiUrl when I’m building up API requests.

I like to take things one step further though, and wrap Angular’s HttpClient with a custom service that will apply this prefix automatically. Here’s my ApiClient service:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { environment } from '../environments/environment';

@Injectable()
export class ApiClient {
  constructor(private httpClient: HttpClient) {}

  private getUrl(url: string) {
    const trimmedUrl = url.startsWith('/') ? url.substring(1) : url;
    return `${environment.apiUrl}/${trimmedUrl}`;
  }

  public post<T>(
    //snip
  ) {
    return this.httpClient.post<T>(this.getUrl(url), body, options);
  }

  public get<T>(
    //snip!
  ) {
    return this.httpClient.get<T>(this.getUrl(url), options);
  }

  public put<T>(
    //snip!
    ) {
    return this.httpClient.put<T>(this.getUrl(url), body, options);
  }
}

The argument definitions for post, get, and put are quite lengthy. You can see the full implementation in the Github repo.

ApiClient just wraps HttpClient and converts relative URLs, like /SomeEntity and SomeEntity/Action into URLs that target the API: http://localhost:56221/api/SomeEntity and http://localhost:56221/api/SomeEntity/Action respectively.

Here’s an example of how to use the client:

  async ngOnInit() {
    this.response = await this.apiClient.get<any>('Values').toPromise();
  }

You do need to make one more change to your ASP.NET Core application, too.

Enabling CORS

The out-of-the-box ASP.NET Core Web API project only allows requests from the same origin. We need to enable cross-origin requests.

In Startup.cs, add a call to AddCors() to your ConfigureServices method:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.AddCors();
    }

And add a call to UseCors() following to your Configure method:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        app.UseCors(x => x.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
        app.UseMvc();
    }

The order that middleware is added matters. Be sure you add UseCors() BEFORE the call to UseMvc(). If you don’t, the MVC middleware will reject the request before the CORS middleware has a chance to do anything.

The Code

So there you have it: an ASP.NET Core application with an Angular CLI app embedded in it. This is better than using the ASP.NET Core 2.0 Angular template, which sets you up with an old version of Angular and an obsolete build system.

If you want to check out the code, head on over to the Github repository. Let me know what you think!