There are many ways to do Angular development with Microsoft stack. On one extreme is Angular/Node/Express in one project and ServiceStack backend in another one. This works for people who prefer Angular development on platforms other than Windows, but there are two projects or actually two groups of projects to manage and maintain, which again may be a necessity in very big projects and multiple teams. On another extreme there is ASP.NET MVC application with strongly typed helpers that emit Angular code. This gives familiar ASP.NET MVC development experience at the cost of extra layer of abstraction.

The approach that I have been using during past year in a couple of my projects can be called middle ground solution. It is a mix of both worlds where certain site components and features are provided by server-side strongly-typed ASP.NET MVC code while client front-end is Angular. In particular, what I mean by that is that site menu, breadcrumb and site map are produced by handy NuGet called MvcSiteMapProvider, while there typical Angular 1.x infrastructure is pulled via Bower and intermingled with Razor views. This approach is beneficial if not every page on the site should be Angular or there is an existing ASP.NET MVC site which needs Angular on some pages. In this design each view is a SPA with Angular ng-app as opposed to ng-app being applied to html or body tags. ASP.NET MVC provides root controller, navigation and routing while each Angular view has its own controllers. To illustrate these idea I put together sample project. Starting from ASP.NET 4.6.1 MVC template with Web API these are the main steps.

Install-Package MvcSiteMapProvider.MVC5  

Provides site map, menu, breadcrumb and more. Edit initial site map to

<?xml version="1.0" encoding="utf-8" ?>  
<mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
            xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0"
            xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd">

  <mvcSiteMapNode title="Home" controller="Home" action="Index">
    <mvcSiteMapNode title="Products" controller="Products" action="Index"/>
    <mvcSiteMapNode title="About" controller="Home" action="About"/>
    <mvcSiteMapNode title="Contact Us" controller="Home" action="Contact"/>
  </mvcSiteMapNode>

</mvcSiteMap>  

We are going to need a custom helper in Views/Shared/DisplayTemplates:

BootstrapMenuHelperModel.cshtml

@model MvcSiteMapProvider.Web.Html.Models.MenuHelperModel
@using System.Web.Mvc.Html
@using MvcSiteMapProvider.Web.Html.Models

@foreach (SiteMapNodeModel node in Model.Nodes)
{
    if (node.IsRootNode)
    {
        continue;
    }
    string url = node.IsClickable ? node.Url : "#";

    // Ignore any nodes with custom hidden attribute
    int countOfHiddenNodes = node.Children.Count(s => s.Attributes.Any(a => a.Key == "hidden"));
    if (node.Children.Count - countOfHiddenNodes == 0)
    {
        <li class="@GetCssClass(node)">
            <a href="@url"> @RenderIcon(node) @node.Title </a>
        </li>
    }
    else
    {
        string css = GetCssClassForLi(node);
        <li class="dropdown @css">
            <a href="#" class="dropdown-toggle" aria-expanded="false" data-toggle="dropdown">
                @RenderIcon(node)
                @node.Title<b class="caret"></b>
            </a>
            @DropDownMenu(node.Children)
        </li>
    }
}

@* Two level max, not doing recursion *@
@helper DropDownMenu(SiteMapNodeModelList nodeList)
{
    <ul class="dropdown-menu">
        @foreach (SiteMapNodeModel node in nodeList)
        {
            string url = node.IsClickable ? node.Url : "#";
            @* We can show active node here*@
            <li>
                <a href="@url" class="@GetCssClass(node)">
                    @RenderIcon(node)
                    @node.Title
                </a>
            </li>
        }
    </ul>
}

@helper RenderIcon(SiteMapNodeModel node)
{
    if (!string.IsNullOrEmpty(node.ImageUrl))
    {
        string cssClass = node.ImageUrl.Substring(1);
            <i class="glyphicon @cssClass"></i>
    }
}

@functions
{
    string GetCssClass(SiteMapNodeModel node)
    {
        bool match = Html.RouteMatch(node.Action, node.Controller);
        if (!match)
        {
            // Since menu item can have hidden nodes, it is possible that we failed to match on parent
            // and now one of those hidden nodes is active.
            match = AnyActiveChildren(node);
        }

        return match ? "active" : string.Empty;
    }

    string GetCssClassForLi(SiteMapNodeModel node)
    {
        return AnyActiveChildren(node) ? "active" : string.Empty;
    }

    bool AnyActiveChildren(SiteMapNodeModel node)
    {
        return node.Descendants.Any(s => Html.RouteMatch(s.Action, s.Controller));
    }
}

Then we use this helper in _Layout.cshtml:

<!DOCTYPE html>  
<html>  
<head>  
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AngularMvcStarter-@Html.MvcSiteMap().SiteMapTitle()</title>
    @Styles.Render("~/css")
    @Scripts.Render("~/lib/jquery/dist/jquery.min.js")
    @Scripts.Render("~/angular")
    @RenderSection("JavascriptInHead", required: false)
</head>  
<body>  
<div class="navbar navbar-inverse navbar-fixed-top">  
    <div class="container">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            @Html.ActionLink("Home", "Index", "Home", new {area = ""}, new {@class = "navbar-brand"})
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                @Html.MvcSiteMap().Menu("BootstrapMenuHelperModel")
            </ul>
        </div>
    </div>
</div>  
<div>  
    <div class="page-title">
        <h3>@Html.MvcSiteMap().SiteMapTitle()</h3>
    </div>
</div>  
<p class="clearfix layout-header" />  
<div class="container body-content">  
    @RenderBody()
    <hr />
    <footer>
        <p>&copy; @DateTime.Now.Year</p>
    </footer>
</div>

@RenderSection("scripts", required: false)
</body>  
</html>  

ASP.NET MVC and Web API Controllers

There isn't much in any of them:

using System.Web.Mvc;

namespace AngularMvcStarter.Controllers  
{
    public class ProductsController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }
    }
}

namespace AngularMvcStarter.ViewModels  
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Number { get; set; } 
    }
}

using System.Collections.Generic;  
using System.Web.Http;  
using AngularMvcStarter.ViewModels;

namespace AngularMvcStarter.Controllers.Api  
{
    public class ProductsController : ApiController
    {
        [Route("api/products/{productName}")]
        public IList<Product> Get(string productName)
        {
            return new List<Product>
            {
                new Product {Id = 1, Name = "Adjustable Race", Number = "AR-5381"},
                new Product {Id = 2, Name = "Bearing Ball", Number = "BA-8327"},
                new Product {Id = 3, Name = "BB Ball Bearing", Number = "BE-2349"}
            };
        }
    }
}

It is helpful to change JSON casing that is coming out of Web API:

namespace AngularMvcStarter  
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.Formatters.XmlFormatter.SupportedMediaTypes.Clear();

            var jsonformatter = config.Formatters.JsonFormatter;
            var settings = jsonformatter.SerializerSettings;
            settings.Formatting = Formatting.Indented;
            settings.ContractResolver = new CamelCasePropertyNamesContractResolver();

            config.MapHttpAttributeRoutes();
        }
    }
}

I also add Web API helper page:

install-package Microsoft.AspNet.WebApi.HelpPage  

With that we should be able to navigate to http://localhost:59386/api/products/abc to get the list of products:

[
  {
    "id": 1,
    "name": "Adjustable Race",
    "number": "AR-5381"
  },
  {
    "id": 2,
    "name": "Bearing Ball",
    "number": "BA-8327"
  },
  {
    "id": 3,
    "name": "BB Ball Bearing",
    "number": "BE-2349"
  }
]

Angular

It is consensus these days that JavaScript libraries should be brought up with Bower or Node as opposed to NuGets and thus here are two Bower files

bower.json

{
  "name": "ASP.NET",
  "private": true,
    "dependencies": {
        "angular": "1.5.0",
        "angular-resource": "1.5.0",
        "bootstrap": "^3.3.6"        
    }
}

.bowerrc

{
  "directory": "lib"
}

As far as location of common packages some people leave packages in bower_components others have gulp to move them elsewhere. To keep things simple, I added lib folder to the project where the packages will reside.

Gulp or Grunt is probably a better choice for bundling and minification, especially because gulp is now supported in VS 2015, but to keep things simple I chose the old route:

using System.Web.Optimization;

namespace AngularMvcStarter  
{
    public class BundleConfig
    {
        // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
        public static void RegisterBundles(BundleCollection bundles)
        {
            bundles.Add(new ScriptBundle("~/angular").Include(
                "~/lib/angular/angular.js",
                "~/lib/angular-resource/angular-resource.js"));

            bundles.Add(new StyleBundle("~/css").Include(
                      "~/lib/bootstrap/dist//css/bootstrap.css",
                      "~/css/site.css"));
        }
    }
}

I went with Joe Eames recommendations for Angular organization and naming. In particular, there is one global module variable in app.js:

"use strict";
var starterModule = angular.module("starterModule", ['ngResource']);  

products-service.js

"use strict";
starterModule.factory("productsService", function ($resource) {  
    return {
        getProducts: function (productName) {
            var params = { productName: productName };
            return $resource("/api/products/:productName", { productName: "@productName" }).query(params);
        }
    };
});

products-controller.js

"use strict";
starterModule.controller("ProductsController", function($scope, productsService) {  
    $scope.productName = "Bearing";

    $scope.getProducts = function() {
        productsService.getProducts($scope.productName)
            .$promise.then(
                function(response) {
                    $scope.products = response;
                }
            );
    };
});

And this finally takes us to Views\Products\Index.cshtml:

@section JavascriptInHead
{
    @Scripts.Render("~/js/app.js")
    @Scripts.Render("~/js/products/products-service.js")
    @Scripts.Render("~/js/products/products-controller.js")
}

<div ng-app="starterModule" ng-controller="ProductsController">  
    <form class="form-inline">
        <div class="form-group">
            <label for="productName">Product Name</label>
            <input type="text" class="form-control" id="productName" ng-model="productName"/>
        </div>
        <button type="submit" class="btn btn-primary" ng-click="getProducts()">Retrieve</button>
    </form>

    <p></p>

    <table class="table table-striped" ng-show="products">
        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Number</th>
        </tr>
        <tr ng-repeat="product in products">
            <td>{{product.id}}</td>
            <td>{{product.name}}</td>
            <td>{{product.number}}</td>
        </tr>
    </table>
</div>  

In real project of there would be partials and directives, this is just the simplest way to get Angular up in ASP.NET MVC application. See
source here.