Adding Bootstrap to your Empty ASP.NET MVC6 Project

If you followed my previous post, you got your first ASP.NET website going from scratch. Congratulations. My next step on this project was to add some client-side libraries – specifically, Bootstrap and the jQuery dependency. My first method went like this: “Well, I’ll just add it via NuGet like I always did before”. That didn’t work so well. That’s because Visual Studio is integrating some Javascript tools – specifically npm (the Node Package Manager), Bower and Grunt – and you need to use those to manage client-side libraries.

Firstly, what are these tools? Well, npm is the Node Package Manager and is, well, a package manager. Visual Studio uses this to bring in external tooling libraries for Bower and Grunt. We don’t really want to use it – it’s a means to an end. The end is utilizing bower and grunt. Bower is a package manager for the various libraries you want to use in your client application. Grunt is a task runner for Javascript and has a huge supply of task templates. Why did Microsoft not tool their own like they have in the past? Well, Bower, Grunt and NPM are maintained in the open source community, so they can run on anything. By standardizing on these, Microsoft has made it possible to develop ASP.NET applications on non-Microsoft platforms like Linux and Mac. This is great for the Linux and Mac community but makes scaffolding these things a little harder for us older ASP.NET developers.


Let’s start with Bower. Bower is the tool we will use to pull down Bootstrap and jquery from the Internet. The whole process here starts with a bower.json file. Right click on your project and select Add -> New Item… Search for Bower and you will find the Bower JSON Configuration File. It’s already got the right name, so you can just click on Add.


The contents are fairly straight forward, but its empty. Let’s add some dependencies. You can use Intellisense to find packages or you can use the Search Packages link on the Bower website. I want Bootstrap and jQuery – latest versions, so my bower.json now looks like this:

	"name": "WebApplication1",
	"private": true,
	"dependencies": {
		"bootstrap": "3.3.2",
		"jquery": "2.1.3"
    "exportsOverride": {

Note that if you click on one of those dependencies, a little light-bulb appears in the left-hand margin. Click it and you can go right to the home page of the library you are adding. I love that feature! Also note that the Dependencies node in your Solution Explorer can be expanded and contains the dependencies you just added. Now right-click on your project and select Build. The libraries will get downloaded for you.


Our next step is to get the files we need in the right places. This is where Grunt comes in. The Grunt configuration is a Javascript File. Again, use Add -> New Item… to find the Grunt Configuration File.


We get the right filename from the Add Item dialog (just like we did with the Bower configuration file), so we can just click on Add. The basic format is there, but nothing will happen if we run this. Let’s start by defining a task for installing the Bower libraries we defined in the bower.json file:

This file in the main entry point for defining grunt tasks and using grunt plugins.
Click here to learn more.
module.exports = function (grunt) {
		bower: {
			install: {
				options: {
					targetDir: "wwwroot/lib",
					layout: "byComponent",
					cleanTargetDir: true

	// The following line loads the grunt plugins.
	// This line needs to be at the end of this file.

There are two parts to this file. The first thing we need to do is load an appropriate task template. We are using the grunt-bower-task plugin, but there are literally thousands of others. You can find the big list and a search box on the grunt website. This one is called ‘bower-task’, but do the search for bower and you will see others as well. We add task templates with the grunt.loadNpmTasks() method.

Now that we have the appropriate plugin, we need to configure it. That’s done in the grunt.initConfig() method. The configuration is taken from the grunt plugin page for bower-task. it tells you exactly what the options are and what they are used for. Save this file and watch the Output window, specifically for Task Runner Explorer. Notice that you will get “failed to run” errors. That’s because we haven’t told the system to go get grunt yet.

Node Package Manager

The Node Package Manager is configured with a package.json file. Just like the other two, you will want to Add -> New Item… and add the NPM Package file.


Note that the Name is package.json – which happens to be just what we need. In many ways the package.json is just like the project.json file. We have some devDependencies which we have to list:

	"version": "1.0.0",
	"name": "WebApplication1",
	"private": true,
	"devDependencies": {
		"grunt": "0.4.5",
		"grunt-bower-task": "0.4.0"

You get Intellisense on the versions just like you do on project.json dependencies. Once you have added grunt and grunt-bower-task, save the file and open the Output -> Package Manager Log. Lots of things are getting downloaded here, mostly from Visual Studio is downloading grunt, the plugins that we asked for and all the dependencies – it might take a while the first time.

Running the Task

Open up View -> Task Runner Explorer and then click on the Refresh circle icon. You should see something like the below:


You can select bower, right-click and select Run. Check out your wwwroot directory in your Solution Explorer. Bower downloaded the files for you and Grunt installed the default set of files into your library area. Unfortunately, the default set of files is wrong. Most notably, the bootstrap.css loads fonts from ../fonts and that doesn’t exist.

Adjusting the Exported Views

Firstly, we got it wrong, so delete the lib directory from your wwwroot area. This gets recreated and we don’t want our failed attempt hanging around.

The problem we have run into is that we want to specify the layout of Bootstrap on disk. If you look on disk, there is a dist directory with the appropriate js, css, and fonts directories:


To get bower to install the files in the right place we need to override what the package is telling us we need. We do this in the bower.json file:

	"name": "WebApplication1",
	"private": true,
	"dependencies": {
		"bootstrap": "3.3.2",
		"jquery": "2.1.3"
	"exportsOverride": {
		"bootstrap": {
			"js": "dist/js/*.*",
			"css": "dist/css/*.*",
			"fonts": "dist/fonts/*.*"
		"jquery": {
			"js": "dist/*.*"

Note that new section in exportsOverride. You will see the following layout once you re-run the grunt task in the Task Runner Explorer.


Now we can include bootstrap in our code!

Modifying PageLayout for Bootstrap

I’ve already got a PageLayout.cshtml from my prior post. Let’s now modify that to include bootstrap.

<!DOCTYPE html>
	<meta charset="utf-8">
	<link rel="stylesheet" type="text/css" href="~/lib/bootstrap/css/bootstrap.min.css">
	<link rel="stylesheet" type="text/css" href="~/lib/bootstrap/css/bootstrap-theme.min.css">

	<script src="~/lib/jquery/js/jquery.min.js"></script>
	<script src="~/lib/bootstrap/js/bootstrap.min.js"></script>

Now you can start your project and see the effects of your work. Check out the F12 tools and ensure the HTML is right and that the files are actually getting loaded (using the Network tab in the F12 Developer Tools).

Hooking Into Automated Build

I bet you thought you were finished. Well, almost. We need to be able to run the client-library build when we build our application. If you head over to the Task Runner Explorer again and click on the Bindings tab, you will see there are four bindings – Before Build, After Build, Clean and Project Open. I like to produce four grunt meta-tasks for these. To do this, I add the following to my Gruntfile.js file.

	grunt.registerTask("before-build", ["bower:install"]);
	grunt.registerTask("after-build", []);
	grunt.registerTask("clean", []);
	grunt.registerTask("project-open", []);

Once you save the file the tasks will appear under the Alias Tasks section of your Task Runner Explorer. You can now right-click on each one, select Bindings and bind the task to the appropriate section.

Finishing up

We’ve done all the work. Now let’s remove the lib directory again (to make sure everything is wired up) and use F6 to build the solution. The lib directory should appear again. From this point on we only need to deal with bower.json for the library packages (unless we need something a little bit more in terms of automation). once we have added the library to bower.json, the right files will just appear in our lib directory.