How to use Bootstrap 4 in ASP.NET Core

129,177

Solution 1

As others already mentioned, the package manager Bower, that was usually used for dependencies like this in application that do not rely on heavy client-side scripting, is on the way out and actively recommending to move to other solutions:

..psst! While Bower is maintained, we recommend yarn and webpack for new front-end projects!

So although you can still use it right now, Bootstrap has also announced to drop support for it. As a result, the built-in ASP.NET Core templates are slowly being edited to move away from it too.

Unfortunately, there is no clear path forward. This is mostly due to the fact that web applications are continuously moving further into the client-side, requiring complex client-side build systems and many dependencies. So if you are building something like that, you might already know how to solve this then, and you can expand your existing build process to simply also include Bootstrap and jQuery there.

But there are still many web applications out there that are not that heavy on the client-side, where the application still runs mainly on the server and the server serves static views as a result. Bower previously filled this by making it easy to just publish client-side dependencies without that much of a process.

In the .NET world we also have NuGet and with previous ASP.NET versions, we could use NuGet as well to add dependencies to some client-side dependencies since NuGet would just place the content into our project correctly. Unfortunately, with the new .csproj format and the new NuGet, installed packages are located outside of our project, so we cannot simply reference those.

This leaves us with a few options how to add our dependencies:

One-time installation

This is what the ASP.NET Core templates, that are not single-page applications, are currently doing. When you use those to create a new application, the wwwroot folder simply contains a folder lib that contains the dependencies:

wwwroot folder contains lib folder with static dependencies

If you look closely at the files currently, you can see that they were originally placed there with Bower to create the template, but that is likely to change soon. The basic idea is that the files are copied once to the wwwroot folder so you can depend on them.

To do this, we can simply follow Bootstrap’s introduction and download the compiled files directly. As mentioned on the download site, this does not include jQuery, so we need to download that separately too; it does contain Popper.js though if we choose to use the bootstrap.bundle file later—which we will do. For jQuery, we can simply get a single “compressed, production” file from the download site (right-click the link and select "Save link as..." from the menu).

This leaves us with a few files which will simply extract and copy into the wwwroot folder. We can also make a lib folder to make it clearer that these are external dependencies:

wwwroot folder contains lib folder with our installed dependencies

That’s all we need, so now we just need to adjust our _Layout.cshtml file to include those dependencies. For that, we add the following block to the <head>:

<environment include="Development">
    <link rel="stylesheet" href="~/lib/css/bootstrap.css" />
</environment>
<environment exclude="Development">
    <link rel="stylesheet" href="~/lib/css/bootstrap.min.css" />
</environment>

And the following block at the very end of the <body>:

<environment include="Development">
    <script src="~/lib/js/jquery-3.3.1.js"></script>
    <script src="~/lib/js/bootstrap.bundle.js"></script>
</environment>
<environment exclude="Development">
    <script src="~/lib/js/jquery-3.3.1.min.js"></script>
    <script src="~/lib/js/bootstrap.bundle.min.js"></script>
</environment>

You can also just include the minified versions and skip the <environment> tag helpers here to make it a bit simpler. But that’s all you need to do to keep you starting.

Dependencies from NPM

The more modern way, also if you want to keep your dependencies updated, would be to get the dependencies from the NPM package repository. You can use either NPM or Yarn for this; in my example, I’ll use NPM.

To start off, we need to create a package.json file for our project, so we can specify our dependencies. To do this, we simply do that from the “Add New Item” dialog:

Add New Item: npm Configuration file

Once we have that, we need to edit it to include our dependencies. It should something look like this:

{
  "version": "1.0.0",
  "name": "asp.net",
  "private": true,
  "devDependencies": {
    "bootstrap": "4.0.0",
    "jquery": "3.3.1",
    "popper.js": "1.12.9"
  }
}

By saving, Visual Studio will already run NPM to install the dependencies for us. They will be installed into the node_modules folder. So what is left to do is to get the files from there into our wwwroot folder. There are a few options to do that:

bundleconfig.json for bundling and minification

We can use one of the various ways to consume a bundleconfig.json for bundling and minification, as explained in the documentation. A very easy way is to simply use the BuildBundlerMinifier NuGet package which automatically sets up a build task for this.

After installing that package, we need to create a bundleconfig.json at the root of the project with the following contents:

[
  {
    "outputFileName": "wwwroot/vendor.min.css",
    "inputFiles": [
      "node_modules/bootstrap/dist/css/bootstrap.min.css"
    ],
    "minify": { "enabled": false }
  },
  {
    "outputFileName": "wwwroot/vendor.min.js",
    "inputFiles": [
      "node_modules/jquery/dist/jquery.min.js",
      "node_modules/popper.js/dist/umd/popper.min.js",
      "node_modules/bootstrap/dist/js/bootstrap.min.js"
    ],
    "minify": { "enabled": false }
  }
]

This basically configures which files to combine into what. And when we build, we can see that the vendor.min.css and vendor.js.css are created correctly. So all we need to do is to adjust our _Layouts.html again to include those files:

<!-- inside <head> -->
<link rel="stylesheet" href="~/vendor.min.css" />

<!-- at the end of <body> -->
<script src="~/vendor.min.js"></script>

Using a task manager like Gulp

If we want to move a bit more into client-side development, we can also start to use tools that we would use there. For example Webpack which is a very commonly used build tool for really everything. But we can also start with a simpler task manager like Gulp and do the few necessary steps ourselves.

For that, we add a gulpfile.js into our project root, with the following contents:

const gulp = require('gulp');
const concat = require('gulp-concat');

const vendorStyles = [
    "node_modules/bootstrap/dist/css/bootstrap.min.css"
];
const vendorScripts = [
    "node_modules/jquery/dist/jquery.min.js",
    "node_modules/popper.js/dist/umd/popper.min.js",
    "node_modules/bootstrap/dist/js/bootstrap.min.js",
];

gulp.task('build-vendor-css', () => {
    return gulp.src(vendorStyles)
        .pipe(concat('vendor.min.css'))
        .pipe(gulp.dest('wwwroot'));
});

gulp.task('build-vendor-js', () => {
    return gulp.src(vendorScripts)
        .pipe(concat('vendor.min.js'))
        .pipe(gulp.dest('wwwroot'));
});

gulp.task('build-vendor', gulp.parallel('build-vendor-css', 'build-vendor-js'));

gulp.task('default', gulp.series('build-vendor'));

Now, we also need to adjust our package.json to have dependencies on gulp and gulp-concat:

{
  "version": "1.0.0",
  "name": "asp.net",
  "private": true,
  "devDependencies": {
    "bootstrap": "4.0.0",
    "gulp": "^4.0.2",
    "gulp-concat": "^2.6.1",
    "jquery": "3.3.1",
    "popper.js": "1.12.9"
  }
}

Finally, we edit our .csproj to add the following task which makes sure that our Gulp task runs when we build the project:

<Target Name="RunGulp" BeforeTargets="Build">
  <Exec Command="node_modules\.bin\gulp.cmd" />
</Target>

Now, when we build, the default Gulp task runs, which runs the build-vendor tasks, which then builds our vendor.min.css and vendor.min.js just like we did before. So after adjusting our _Layout.cshtml just like above, we can make use of jQuery and Bootstrap.

While the initial setup of Gulp is a bit more complicated than the bundleconfig.json one above, we have now have entered the Node-world and can start to make use of all the other cool tools there. So it might be worth to start with this.

Conclusion

While this suddenly got a lot more complicated than with just using Bower, we also do gain a lot of control with those new options. For example, we can now decide what files are actually included within the wwwroot folder and how those exactly look like. And we also can use this to make the first moves into the client-side development world with Node which at least should help a bit with the learning curve.

Solution 2

Looking into this, it seems like the LibMan approach works best for my needs with adding Bootstrap. I like it because it is now built into Visual Studio 2017(15.8 or later) and has its own dialog boxes.

Update 6/11/2020: bootstrap 4.1.3 is now added by default with VS-2019.5 (Thanks to Harald S. Hanssen for noticing.)

The default method VS adds to projects uses Bower but it looks like it is on the way out. In the header of Microsofts bower page they write: Bower is maintained only.Recommend using LibManager

Following a couple links lead to Use LibMan with ASP.NET Core in Visual Studio where it shows how libs can be added using a built-in Dialog:

In Solution Explorer, right-click the project folder in which the files should be added. Choose Add > Client-Side Library. The Add Client-Side Library dialog appears: [source: Scott Addie 2018]

enter image description here

Then for bootstrap just (1) select the unpkg, (2) type in "bootstrap@.." (3) Install. After this, you would just want to verify all the includes in the _Layout.cshtml or other places are correct. They should be something like href="~/lib/bootstrap/dist/js/bootstrap...")

Solution 3

Try Libman, it's as simple as Bower and you can specify wwwroot/lib/ as the download folder.

Solution 4

What does the trick for me is:

1) Right click on wwwroot > Add > Client Side Library

2) Typed "bootstrap" on the search box

3) Select "Choose specific files"

4) Scroll down and select a folder. In my case I chose "twitter-bootstrap"

5) Check "css" and "js"

6) Click "Install".

A few seconds later I have all of them wwwroot folder. Do the same for all client side packages that you want to add.

Solution 5

Libman seems to be the tool preferred by Microsoft now. It is integrated in Visual Studio 2017(15.8).

This article describes how to use it and even how to set up a restore performed by the build process.

Bootstrap's documentation tells you what files you need in your project.

The following example should work as a configuration for libman.json.

{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": [
  {
    "library": "[email protected]",
    "destination": "wwwroot/lib/bootstrap",
    "files": [
    "js/bootstrap.bundle.js",
    "css/bootstrap.min.css"
    ]
  },
  {
    "library": "[email protected]",
    "destination": "wwwroot/lib/jquery",
    "files": [
      "jquery.min.js"
    ]
  }
]
}
Share:
129,177
developer
Author by

developer

Updated on September 09, 2020

Comments

  • developer
    developer over 3 years

    I want to update Bootstrap in ASP.NET Core with NuGet. I used this:

    Install-Package bootstrap -Version 4.0.0
    

    It did add the dependencies but how do I add it to my project now? What is the path for local NuGet dependencies?

    Installed NuGet dependencies

  • James Blake
    James Blake about 6 years
    When using the npm method, I was getting back errors like "Uncaught SyntaxError: Unexpected token export". To fix this I switched to the popper.js umd file "node_modules/popper.js/dist/umd/popper.min.js". Otherwise one of the best answers I have ever seen on stack, thank you.
  • poke
    poke about 6 years
    @JamesBlake Thank you for the feedback! – Let me check about that error, are you using the Gulp-based solution, or the bundleconfig-one?
  • James Blake
    James Blake about 6 years
    That was using bundleconfig.json.
  • poke
    poke about 6 years
    @JamesBlake Oh, yes, you’re right! The path I had in the answer is an ES6 module compatible file. Fixed it in the answer, thank you! :)
  • user
    user about 6 years
    I am receiving an error following these instructions: "The command "node_modules\.bin\gulp.cmd" exited with code 1." The output shows: gulp.task('build-vendor-css', () => { SyntaxError: Unexpected token ) (The output points to the closing parenthesis). Suggestions?
  • poke
    poke about 6 years
    @user That sounds as if you are using a very old version of Node. You can see the version by running node -v, and get a current version over here on nodejs.org
  • dave317
    dave317 about 6 years
    Thanks, this post was super helpful. Any idea how to get Visual Studio's autocomplete to recognize the newer version of bootstrap? It seems like mine is still pointing to the old 3.3.7 version
  • poke
    poke about 6 years
    @dave317 Hmm, I don’t think there is an explicit autocomplete for Bootstrap. I think it’s rather that the Razor toolls will autocomplete CSS classes from .css files. So if you have the bootstrap.css included properly, that should work out of the box.
  • dave317
    dave317 about 6 years
    SCRATCH THAT, VS autocomplete working great. Thanks again for this answer. Super helpful
  • dave317
    dave317 about 6 years
    Do you have any recommendations as for what files a person can remove in their project and anything in the _Layout that could be removed.
  • poke
    poke about 6 years
    @dave317 You mean from the default template? You pretty much have full control over that. You need the layouts file and may want to keep the _ViewStart and _ViewImports to keep MVC working nicely but apart from that, you can do whatever you want. I usually replace the whole layout with my own stuff and completely replace everything that’s inside wwwroot. I also remove the <environment> switches from the layout since I usually don’t work on projects that take advantage over different sources for these files. I just host my files in the wwwroot directly.
  • dave317
    dave317 about 6 years
    Thanks @poke, makes sense. I'll try that with a new project and build my own template.
  • camainc
    camainc about 6 years
    LOL. I have to laugh or I'll cry. Seventeen years of .Net development using the tooling support of Visual Studio, and it has come to this? Personally, I fail to see how this is forward progress. If it takes this much work just to add Bootstrap styling to a web project then something has gone drastically wrong.
  • poke
    poke about 6 years
    @camainc If anything, then blame it on the development of the JavaScript ecosystem. This is really not related to .NET or Visual Studio at all. The simple solution is still to just download the files manually and then add them to your web root. That’s just how it worked all the years before too. – And for what it’s worth, Microsoft is working on new VS tooling to make this process simpler (and updatable).
  • SJP
    SJP almost 6 years
    @poke Thanks for this post, really helpful. I tried both bundleconfig and GULP methods, and everything got added to my project folder as you specified. But i didn't get intellisense working for bootstrap. So I tried the old method, Onetime Installation, download and simply copy files to the lib folder under wwwroot. And I got intellisense working for bootstrap then. So I just wonder, why other methods - GULP and bundleconfig - missing intellisense even if the files got installed properly.
  • poke
    poke almost 6 years
    @SJPadikkoth I think Visual Studio picks up CSS classes automatically from all files that are within the wwwroot folder. So it’s possible that Visual Studio does not pick up the files when they are automatically placed there during build. Did you try running the scripts (to have the files being moved there), and then restarting Visual Studio?
  • SJP
    SJP almost 6 years
    @poke thanks for the reply.But I didn't understand what did you mean by running the scripts (to have the files being moved there)? Could you explain me how can I do the same please. Really appreciate your help.
  • poke
    poke almost 6 years
    @SJPadikkoth I mean, if you are using e.g. the Gulp solution, then make sure to run it once so that the files get created within the wwwroot folder. And then check if restarting Visual Studio is enough to make it pick up the CSS rules.
  • SJP
    SJP almost 6 years
    @poke, thank you for your reply. Yes I did both, ran the scripts and restarted VS. All files got created within wwwroot folder. But still no luck. :(
  • poke
    poke almost 6 years
    @SJPadikkoth I’ve been playing around with this a bit now; unfortunately, Visual Studio behaves really inconsistent there. I believe VS will not look into .min.css files for this. So if you change the gulpfile.js (or the bundleconfig.json) to create a vendor.css (instead of vendor.min.css), then it should work. Restarting Visual Studio might still be necessary though.
  • SJP
    SJP almost 6 years
    @poke Great !!!! It worked very well. changed both vendor.min.js and vendor.min.css to vendor.js and vendor.css. Restarting VS is not necessary actually, just rebuild the solution. Thank you very much.
  • pedroremedios
    pedroremedios almost 6 years
    Mine was in the "Scripts" section.
  • Patrick Borkowicz
    Patrick Borkowicz almost 6 years
    I didn't think there was anything wrong with NuGet and Bower for dependency management? All of this leaves me a bit baffled as to how this is an improvement.
  • poke
    poke almost 6 years
    @Patrick I don’t consider this an improvement. It’s just a very different situation with both NuGet and Bower gone for this type of dependencies.
  • kristianp
    kristianp almost 6 years
    Not in the release of VS2017 yet: UPDATE: 24-May-2018 – It looks like LibMan didn’t make it into the final release of 15.7. It’s in the preview for 15.8.x
  • Andy
    Andy almost 6 years
    Yes I agree with poke @camainc this is not a .net problem. Its the way software development is going. JS everywhere. If you have been developing for 17 years, you can probably continue to do so (as I hope I will be able to) but JS is definitely the way forward.
  • camainc
    camainc almost 6 years
    @ozzy432836, I know it is not a bootstrap problem, and I never said it was. It is a general development issue with everyone seemingly chasing the next new framework. I've seen a lot of changes in my career, but nothing like what has happened in the last couple of years surrounding Javascript. It has been absolutely nuts watching the development community churning one new framework after another. As for whether JS is the way forward, the jury is still out on that one, especially with WASM and projects like Blazor on the horizon.
  • Kirk Larkin
    Kirk Larkin over 5 years
    Looks like this is out now with the final 15.8 release.
  • Jemin
    Jemin over 5 years
    It is available now in VS2017 V 15.8 and much simpler approach than the accepted answer
  • Fandango68
    Fandango68 about 5 years
    Get me out of here! I want basic GridViews and ASP.Net... client just wants a simple data entry screen and I have to jump all these hurdles now?! @camainc I totally concur
  • camainc
    camainc about 5 years
    The new templates with VS 2019 have finally addressed this problem. I know not everyone is able to use the bleeding edge tools though. If so, the easiest thing to do is download BS 4 and add it to the project manually. LibMan us also a good tool to use.
  • Kalin Krastev
    Kalin Krastev about 5 years
    For projects which wasn't created using the VS's templates app.UseStaticFiles() has to be added to "Configure" method in Startup.cs in order to be able to link files located in wwwroot folder.
  • Ed Gibbs
    Ed Gibbs about 5 years
    I have VS 4.7.02558 (Community Edition) and this was the easiest option for me. I used it in practice projects created to study for the MS 70-486 (MVC) exam, so I can't answer for how effective this is for projects that are headed for production.
  • TxRegex
    TxRegex almost 5 years
    Use of a CDN adds a runtime dependency. So if the CDN goes down, so does your site. It's a security issue since whoever controls the cdn can change popular files and inject script into your site. It's also a privacy issue since the user's browser requests the files from a 3rd party server rather than your own.
  • TxRegex
    TxRegex almost 5 years
    Thanks, I was following along in a Pro ASP.NET Core MVC 2 book that told me to use Bower which is now obsolete. I searched around for a good while before realizing that you can simply right-click your project and select Add -> Client-Side library. And that uses libman. It's all built in.
  • FredyWenger
    FredyWenger almost 5 years
    For me, this also was the easiest way to install the stuff with the MS STANDARD TOOL. With the hints in your posting - change Provider to unpkg, type in bootstrap@4., I was able to install. Libman is really not intuitive (in my case, I had also to enter the . (point) after 4, before the packages were showed (I thought, libman is not working in my environment).
  • ATL_DEV
    ATL_DEV almost 5 years
    @camainc, Well, you will continue crying for the foreseeable future. Many of these newfangled tools and languages are developed by folks who lack expertise in software engineering . Most only know HTML/CSS/JS. Consequently, they are able to circumvent a lot of the vetting process real software engineers endure. Also, many of them weren't alive during 1984 revolution when the GUI made computers usable to millions. Command line interfaces are a great way of impressing those who fund these flyby-night web technologies.
  • D.Rosado
    D.Rosado over 4 years
    Just a reminder: if you looking for Bootstrap on CdnJS, be aware is the name is twitter-bootstrap as it was originally called.
  • joedotnot
    joedotnot over 4 years
    @TxRegex at some stage it was actually recommended that references be to CDN rather than a web app's server; because a user's browser was likely to have already cached a popular library such as Bootstrap while perusing other sites. But whatever...
  • Harald S. Hanssen
    Harald S. Hanssen almost 4 years
    In Visual Studio 2019 (the latest by 11th of June 2020) - The libman file gets created, but I don't see the libman popup window.
  • SunsetQuest
    SunsetQuest almost 4 years
    @HaraldS.Hanssen - I just tried it and you are right - bootstrap 4.1.3 is added by default now for new projects. Nice!
  • Harald S. Hanssen
    Harald S. Hanssen almost 4 years
    I’ve tested LibMan on several projects and it is really the way to go. Too bad the GUI doesn’t work, but after a few tries it’s easy to use.
  • Himalaya Garg
    Himalaya Garg almost 3 years
    After 2019, It is better to use LibMan as explained in this post.
  • poke
    poke almost 3 years
    @HimalayaGarg I wouldn’t say better since it is always good to have multiple options. For example, dependending on your requirements, you may want to establish an npm-based process in order to integrate other Node-based build processes. – But yeah, LibMan is a very good alternative here, as also mentioned in the answer below by SunsetQuest.