ASP.NET Core and Angular 2

ASP.NET Core and Angular 2 with TypeScript Writing web applications nowadays is becoming a bit more complex as the frameworks evolve taking advantage of other frameworks/tools. That’s the case of Angular 2 (which was developed using TypeScript) and ASP.NET Core with take advantage of npm and bower for the dependencies as well as gulp for performing some tasks. In this article, I will show you how to configure ASP.NET Core and Angular 2 using TypeScript to create your rich client-side apps.

ASP.NET Core is a new open-source and cross-platform framework for building modern cloud-based Web applications using .NET. It was built from the ground up to provide an optimized development framework for apps that are either deployed to the cloud or run on-premises. It consists of modular components with minimal overhead, so you retain flexibility while constructing your solutions. It has evolve taking concepts from node.js and other platforms.

Angular is a development platform for building mobile and desktop web applications using modern web standards. Is an open-source JavaScript framework that augments browser-based applications with Model-View-Controller (MVC) capability, facilitating both development and testing. If you know the previous version, Angular 2 might seems to be a completely different framework, but the main concepts are there. One of the main differentiators is that Angular 2 is written in TypeScript, a superset of JavaScript that compiles to clean JavaScript output. Because its transcompiled to JavaScript, you can use the framework from JavaScript as well as from TypeScript itself.

Now, let’s start configuring a project with both technologies, ASP.NET Core and Angular 2. I’ll assume that you have an ASP.NET Core project created, with MVC configured, although this is not a requirement for using both technologies together. If you need to create a new project, just use the Web Application template in Visual Studio or using the aspnet’s Yeoman generator.

In order to have ASP.NET Core and Angular 2 running together, you’ll need to have the Angular 2 dependencies in place. Angular 2 is distributed using the npm package manager. Open the npm’s package.json file located at the root of your project and add the following dependencies to it.

  "dependencies": {
    "angular2": "2.0.0-beta.9",
    "systemjs": "0.19.24",
    "es6-shim": "^0.33.3",
    "rxjs": "5.0.0-beta.2"
  },

If you are using Visual Studio, after saving the file, it will download the new dependencies (else, just run npm install in the same folder). The files will be downloaded in the node_modules folder, which is not served as default by ASP.NET. You could configure ASP.NET to serve this folder, but it’s better to just copy the files to the wwwroot folder using a gulp tasks. Add the following code in the gulpfile.js. This will add a few tasks to copy each of the dependencies to the wwwroot/lib/npmlibs folder, as well as a task named copy-deps that will run all the others.

paths.npmSrc = "./node_modules/";
paths.npmLibs = paths.webroot + "lib/npmlibs/";

gulp.task("copy-deps:systemjs", function () {
    return gulp.src(paths.npmSrc + '/systemjs/dist/**/*.*', { base: paths.npmSrc + '/systemjs/dist/' })
         .pipe(gulp.dest(paths.npmLibs + '/systemjs/'));
});

gulp.task("copy-deps:angular2", function () {
    return gulp.src(paths.npmSrc + '/angular2/bundles/**/*.js', { base: paths.npmSrc + '/angular2/bundles/' })
         .pipe(gulp.dest(paths.npmLibs + '/angular2/'));
});

gulp.task("copy-deps:es6-shim", function () {
    return gulp.src(paths.npmSrc + '/es6-shim/es6-sh*', { base: paths.npmSrc + '/es6-shim/' })
         .pipe(gulp.dest(paths.npmLibs + '/es6-shim/'));
});

gulp.task("copy-deps:rxjs", function () {
    return gulp.src(paths.npmSrc + '/rxjs/bundles/*.*', { base: paths.npmSrc + '/rxjs/bundles/' })
         .pipe(gulp.dest(paths.npmLibs + '/rxjs/'));
});

gulp.task("copy-deps", ["copy-deps:rxjs", 'copy-deps:angular2', 'copy-deps:systemjs', 'copy-deps:es6-shim']);

Now that you have the Angular 2 dependencies ready to be served in your project, you need to add them to your site so you can start using it. Open the _Layout.cshtml file located at Views/Shared/ and add the following code at the end of your head tag. Note that the polyfills and shims are declared before system.js and angular2. Additionally, in this case I added the router bundle to show you that you need to add additional bundles like Http and router (if you don’t need it, you can remove it).

<environment names="Development">
  <script src="~/lib/npmlibs/es6-shim/es6-shim.js"></script>
  <script src="~/lib/npmlibs/systemjs/system-polyfills.src.js"></script>
  <script src="~/lib/npmlibs/angular2/angular2-polyfills.js"></script>

  <script src="~/lib/npmlibs/systemjs/system.src.js"></script>
  <script src="~/lib/npmlibs/rxjs/Rx.js"></script>
  <script src="~/lib/npmlibs/angular2/angular2.js"></script>
  <script src="~/lib/npmlibs/angular2/router.js"></script>
</environment>

<environment names="Staging,Production">
  <script src="~/lib/npmlibs/es6-shim/es6-shim.min.js"></script>
  <script src="~/lib/npmlibs/systemjs/system-polyfills.js"></script>
  <script src="~/lib/npmlibs/angular2/angular2-polyfills.min.js"></script>

  <script src="~/lib/npmlibs/systemjs/system.src.js"></script>
  <script src="~/lib/npmlibs/rxjs/Rx.min.js"></script>
  <script src="~/lib/npmlibs/angular2/angular2.min.js"></script>
  <script src="~/lib/npmlibs/angular2/router.min.js"></script>
</environment>

Now, you have the dependencies in place for your ASP.NET Core and Angular 2 application, but if you plan to use TypeScript in your project you need to perform a few steps more. Create a tsconfig.json file in the root of your project to configure the compiler to include decorators and specify the use of system.js for module resolution.

{
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "es5",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "module": "system",
    "moduleResolution": "node"
  },
  "exclude": [
    "node_modules",
    "wwwroot/lib"
  ]
}

If you try to compile the project now, you might find some TypeScript issues because Promise and other types are not defined. Add the es6-shim’s TypeScript definitions to your project. To do this, download the one from the DefinitelyTyped repository and add it to your project (you don’t need to serve this file, so you can have a ts folder with it in the root of the project).

Finally, let’s create the base structure for an Angular 2 application. We’ll create two TypeScript files inside a new folder named app under wwwroot. The first file will be the component, which will be a basic Hello World component. Create a file named app.component.ts inside the wwwroot/app folder and add the following code.

import {Component} from 'angular2/core';

@Component({
    selector: 'my-app',
    template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }

Now, create a file named boot.ts also inside the wwwroot/app folder and add the following code. This file is the one that you will load as start point of your app.

import {bootstrap}    from 'angular2/platform/browser'
import {AppComponent} from './app.component'

bootstrap(AppComponent);

Open the view where you plan to add your Angular app, I will choose the Views/Home/Index.cshtml view. Add the angular component tag (e.g. <my-app></my-app>) to the html and add the following script section to the end of the file. This script will configure System.js (specifying to use js files whenever the extension it’s not defined) as well as initialize the Angular 2 app by importing the boot.js file located at the app folder.

@section Scripts {
    <script>
        System.config({
            packages: {
                'app': { defaultExtension: 'js' },
                'lib': { defaultExtension: 'js' },
            },
        });

        System.import('app/boot')
            .then(null, console.error.bind(console));
    </script>
}

You have the base structure for an ASP.NET Core and Angular 2 application. You can find the full code in my Angular2ASPNETCoreBaseApp repository. Now, you just need to start developing your awesome ideas.

Updated: I created a new post explaining how to configure routing to use Angular 2 Routing component.

Updated 2: I created a new post explaining how to configure Angular2’s Http service and ASP.NET to consume the MVC APIs.

  • Daniel

    the project should include the angular asp.net services for angular universal

    • I still need to play a bit with the NodeServices packages. I plan to do it in the near future. Thanks for the feedback:)

  • Tiago

    Hello!
    I don’t know why, but my VS can’t compile typescript code. 🙁

    Error TS2307 Build: Cannot find module ‘angular2/core’.
    Error TS2307 Build: Cannot find module ‘angular2/platform/browser’.

    Any idea?

    • Just a few questions:

      1. What version of VS are you using?
      2. Do you have the “TypeScript for Microsoft Visual Studio” extension installed?
      3. Did you execute the copy-deps’ gulp task once you add it?
      4. Did you update the layout to include the dependencies with the correct paths (where the gulp task copy the files)?

      • Tiago

        I’m using VS 2015 SP1, I installed “Typescript for Microsoft Visual Studio 2015 1.8.6.0” and I executed copy-deps too. I cloned your project and happened the same issue. 🙁

  • Pingback: Dew Drop – March 15, 2016 (#2208) | Morning Dew()

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #2053()

  • Matt kruczek

    Hi,

    Can I ask why you feel like creating a gulp task to move over the npm files that you need is a better solution then altering the startup.cs file to do it?

    You could do it like so in startup.cs

    public static void ConfigureStaticFiles(IApplicationBuilder app, IApplicationEnvironment appEnv, IHostingEnvironment hostEnv)

    {

    // Configure the options to deploy

    var fileServerOptions = new FileServerOptions();

    // Add the physical path to the node_modules folder

    fileServerOptions.FileProvider = new PhysicalFileProvider(

    Path.Combine(appEnv.ApplicationBasePath, “node_modules”)

    );

    // Add the request path

    // (http://docs.asp.net/en/latest/fundamentals/static-files.html)

    fileServerOptions.RequestPath = new PathString(“/node_modules”);

    // With this setting on ASP will search for the following files upon startup

    // default.htm

    // default.html

    // index.htm

    // index.html

    fileServerOptions.EnableDefaultFiles = true;

    // If we are in development then allow directory browsing

    fileServerOptions.EnableDirectoryBrowsing = hostEnv.IsDevelopment();

    // Add those options to the file server

    app.UseFileServer(fileServerOptions);

    }

    • Hi! Thanks for your question. That’s a valid way to do it as I point out in the post. What’s more, that the first thing I did when I started working with Angular 2 in ASP.NET Core. However, I prefer only serving the files that are really needed to be served.

      The idea behind creating the task is to choose what files are being served. Additionally, using this approach I could create new tasks and modify the files, for example, by concatenating all of them into a single file, or uploading them to a CDN, or whatever you want.

    • Simon Weaver

      exactly what I was wondering. I just can’t get over the ugliness of manually copying files. I am absolutely for ‘only serving the files that are really needed’ but copying extra files doesn’t serve them – you still have to request them. still undecided but thanks for providing this

  • DevGuy74

    Hello,
    I’m not sure why I cannot get this example to work. I get the following error.

    Error: Error: XHR error (404 Not Found) loading http://localhost:40723/Home/app/boot.js(…)

    This makes sense because my boot.js is under wwwrootappboot.js and not wwwrootHomeappboot.js. My project is structured exactly the same as the sample except I named the html page NewPage.cshtml instead of Index.cshtml.

    • Hi!, That’s strange, are you using exactly the same configuration as I show? What’s your System.js configuration?

      Just in case, you could try using the baseUrl property of the System.js configuration: System.config({ baseURL: ‘/’ });

      Additionally, what is your routing configuration in the startup.cs file? you should have the calls to the UseStaticFiles and UseMvc methods inside Configure.

      • DevGuy74

        Hi,
        The System.js I have is v 0.19.24 from npm package. I also have the UseStaticFiles and UseMvc methods in the Startup.cs. My default route is the same as your example. I got the example to work if the page was named Index.cshtml. Since angular2 apps are generally SPA(Single Page Applications) I guess Index.cshtml makes sense but it is still unclear to me why this did not work with another page title.
        Thanks for your help.

        • I could reproduce the issue and workaround it specifying the path adding the / at the beginning: System.import(‘/app/boot’).

          Additionally, you should update the configuration to target the same package: System.config({ packages: { ‘/app’: { defaultExtension: ‘js’ } } });

          • DevGuy74

            Hi,
            That worked for me, thanks for the help.

  • Maxime

    hi, i got the same probleme than DevGuy74 ! everything was ok with beta 8 but with beta 9 or 10 the application is broken …

    • Did you try using the same dependencies that I did? “angular2”: “2.0.0-beta.9”, “systemjs”: “0.19.24”, “es6-shim”: “^0.33.3”, “rxjs”: “5.0.0-beta.2”. Try running this solution: https://github.com/nbellocam/Angular2ASPNETCoreBaseApp

      I will need to test with beta 10. However, note that with beta 9, you couldn’t use the latest version of some of the other dependencies.

  • Pingback: Les liens de la semaine – Édition #176 | French Coding()

  • Pingback: Routing in Angular 2 with ASP.NET Core - Nicolas Bello Camilletti()

  • Pingback: Angular 2 Http with ASP.NET Core APIs - Nicolas Bello Camilletti()

  • Simon Weaver

    could you complete the example so that I know where `paths.webroot` comes from. also how do I run this task? I’m using /// but it would help new users immensely if you could put more details in

    • You should have the ‘paths.webroot’ variable defined in the default gulp task. The default value is “./wwwroot/”.

      In order to run the tasks, you can use the “Task Runner Explorer” view in Visual Studio (right-click the task and click run), or you could use the gulp command line: “gulp copy-deps”.

      • travis7

        I’m using .NET Core RC2 and I noticed that in my gulp file there was no paths.webroot, but there was just “var webroot”. So I changed this line and it worked for me:
        paths.npmLibs = paths.webroot + “lib/npmlibs/”;
        changed to
        paths.npmLibs = webroot + “lib/npmlibs/”;
        Otherwise it copies the files to “undefinedlib” in your root directory.

  • Pingback: Cascading DropDown List with ASP.NET Core WEB API and AngularJS 2()

  • Neil Young

    Is there any plan to blog about authentication? How to not only secure WebAPI by credentials/cookies, but how to also save parts of my business logic, which is contained in angular2 templates, nowadays freely available?

    • I have a post about authentication in radar, but honestly, I don’t know when I will be writing it (I like to do it soon).

  • Diego Martín

    I think you’re missing some step. At what point are the TypeScript files compiled? shouldn’t we be running some tsc command to do so?
    And how are the compiled typescript files referenced in the index.html?

  • Owa

    Hi,
    Can you do a new tutorial based on rc1? or can you update this to work with VS2015 update 2 and angular 2 rc1 with the latest typescript version

  • Jacob Johnston

    Nicolas, you are a hero! I literally spent the past two days full time messing with other “getting started with Angular 2 and ASP.NET Core” type tutorials. Each was overkill and riddled with errors. They had all this source code that didn’t work, special instructions creating empty core projects then manually adding MVC structures, etc… taking hours on end following tedious out-dated instructions and not a single one of them worked. Surely that was due in no small part to my own lack of understanding but you – YOU just cut right to the chase and gave me(us) what I(we) want: how do I get Angular 2 working with ASP.Net!?

    Thank you, Mr. Camilletti. Thanks!

    And now that Angular 2 RC is out, perhaps you could update this? Though I’m pretty confident I’ll manage to get that working myself now that you elucidated the basics.

    Kudos, Bravo, etc…