16 Jun

.NET Core and Angular Template


I’ve already seen a lot of different ways people develop an Angular app with .NET Core.
Most of the time it does not involve using the .NET Core .cshtml views, but only the use of .html files located in the App-folder.
With this template I’ll show you a way of using Angular together with the .NET Core .cshtml.

But why like this?

The idea behind trying to use the .cshtml views from .NET Core is so that C#-code can be put in the view if really needed.
Basically having the best of both worlds.


You’ll notice that I’ll be using a lot of Gulp calls to move and transform my files.
My idea in this template is to move and generate all files inside the wwwroot-folder. By doing this I can see a clear distinction between the files that I’m working on, and the files that are generated or used by the website itself.

The template

To download the template, you can scroll down to the bottom of this post.
If you need more information or you have any questions I suggest you read the notes or leave a comment below.


As you can see the App-folder contains all Angular components, services and modules. There are no views in here, since they’re located in the Views folder, following the MVC-mapping.
I tend to create sub-folders for every new module and I create a new module for every new MVC controller I’m using.


You’ll notice that the HomeController contains a Start action. This is the default action that will be called when starting the app. This view also contains the selector for the App.Component.

using Microsoft.AspNetCore.Mvc;

namespace NetCore.Angular.Controllers
    public class HomeController : Controller
        public IActionResult Index()
            return PartialView();

        public IActionResult Start()
            return View();

The most important part can be seen in the Index action. You’ll see that I’m returning a PartialView(), not a View(). This is because the latter will also fetch the _Layout.cshtml markup, and that’s not what we want.
If you want to see some strange HTML-stuff, try changing all your PartialView()-calls to View(), you’ll see what I mean.


This folder contains all .scss files. These get converted by the Gulp.js file and are placed in the css-folder inside the wwwroot.
Nothing special here.


Together with the Controller-folder, this is also one of the default folders for MVC.
This folder will contain all Views, sorted by the controller name in sub folders.
Except for the Start.cshtml view which is a normal view, all other views should be created as partial views.

Start.cshtml will also contain the app.component selector, which in this case is “start”.
In this view you can implement some sort of loading screen since this is the first page that will be shown when people access your website.

    ViewBag.Homepage = true;
    Layout = "~/Views/Shared/_Layout.cshtml";

    <div class="start">
        <i class="fa fa-circle-o-notch fa-5x fa-spin"></i>

In the shared folder, you’ll find the _layout.cshtml. You’ll notice that this file contains all the links to the css and js files.
At the top you’ll also see a variable which is called “production”. I just check whether my url contains my domain to see if it’s on production. After this I can use this variable to load or do stuff different depending if it’s on production or not.


I’m only using the Grunt-file to set the location of all my bower packages.
You can see that I’m ordering them by component in my wwwroot/lib-folder.

/// <binding BeforeBuild='bower, bower:install' />
module.exports = function (grunt) {
        bower: {
            install: {
                options: {
                    targetDir: "wwwroot/lib/",
                    layout: "byComponent",
                    cleanTargetDir: false



As already stated above, I’m using Gulp to move all my npm packages from the node_modules folder to my wwwroot/lib folder.
The file will also compile my SASS- and Typescript files, and put them in their specific folders located in the wwwroot.

/// <binding BeforeBuild='moveToLibs, sass, typescript' Clean='clean' ProjectOpened='sass:watch, watch:ts' />
var gulp = require('gulp'),
    ts = require('gulp-typescript'),
    dest = require('gulp-dest'),
    sass = require('gulp-sass'),
    merge = require('merge2'),
    del = require('del'),
    tsProject = ts.createProject('tsconfig.json'),
    paths = {
        target: {
            webroot: 'wwwroot',
            js: 'wwwroot/js',
            css: 'wwwroot/css',
            lib: 'wwwroot/lib'
        source: {
            typescript: 'App/**/*.ts',
            packages: [
                //Add more npm-packages here
            sass: [
                //Add more sass files here

gulp.task('typescript', function () {
    var result = gulp.src(paths.source.typescript)

    return result.js.pipe(gulp.dest(paths.target.js));
gulp.task('watch:ts', ['typescript'], function () {
    gulp.watch(paths.source.typescript, ['typescript']);

gulp.task('sass', function () {
    return gulp.src(paths.source.sass)
        .pipe(sass().on('error', sass.logError))
gulp.task('sass:watch', function () {
    gulp.watch(paths.sass, ['sass']);

gulp.task('moveToLibs', function () {
    var merges = [];
    for (var i = 0; i < paths.source.packages.length; i++) {
        var to = paths.source.packages[i].replace('@', '');
        merges.push(gulp.src('node_modules/' + paths.source.packages[i] + '/**/*.js').pipe(gulp.dest(paths.target.lib + '/' + to)));
        merges.push(gulp.src('node_modules/' + paths.source.packages[i] + '/**/*.min.js').pipe(gulp.dest(paths.target.lib + '/' + to)));
    return merge(merges);

gulp.task('clean', function () {
    return del([paths.target.lib + '/*', paths.target.js + '/*', paths.target.css + '/*']);


This file is simply used to minify my files.
I also minify some package files since they are not minified by default.




That’s it!

If you like this template or have any comments, please feel free to let me know in the comments below.
And if I helped you out big time, you can also buy me a beer by clicking on the menu item above. 😉

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.