Upgrade bootstrap 3 to 4 in ASP.NET Core MVC Identity deafult template

Motivation

Recently, I had to work with the default ASP.NET Core MVC template, which uses twitter bootstrap v3.3.7. I decided that it would be nice to upgrade and make use of all the amazing stuff v4.x.x brings to us!

I wanted to gather the main changes, we shall apply at the default template to integrate bootstrap v4 in our project. I searched over the internet, but I wasn’t able to find clear steps of how to do that. Therefore, here it comes a small article, about this migration.🎉🎉

Prerequisites

First of all, create an MVC project with Identity in Visual Studio or by running mkdir Bootstrap4Identity && cd Bootstrap4Identity && dotnet new mvc --auth Individual inside a terminal. Now, we are ready to upgrade the default libraries.

I prefer using libman, which is a new feature included in Visual Studio 2017, to manage client-side libraries.

To add libman to our project, simply right click on the project and choose Manage Client-Side libraries

This will generate a single libman.json file in your project’s root path, which now is empty. It only contains the default provider, its version and an empty array of libraries.

{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": []
}

We wouldn’t want to break the default routing of the project, because they are already referenced in template’s html files. So I will configure the destination for the bootstrap files as wwwroot/lib/bootstrap/. Please make sure to delete the bootstrap template-generated folder. The second we save the file a restore operation is startitn to download the required files.

Now if you run the application(F5) you will notice that the UI is broken, which is the problem we are trying to resolve.

Migration to Bootstrap 4

  • Let’s begin by fixing the top navbar. As mentioned in the docs, significant changes made for navs. We apply the required changes bellow at

_Layout.cshtml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top">
        <a asp-area="" asp-controller="Home" asp-action="Index" class="navbar-brand">Bol.Identity</a>
        <button class="navbar-toggler" data-toggle="collapse" data-target="#layoutNavbarSupportedContent"
                aria-controls="layoutNavbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="layoutNavbarSupportedContent">
            <ul class="navbar-nav">
                <li class="nav-item"><a asp-area="" asp-controller="Home" asp-action="Index" class="nav-link">Home</a></li>
                <li class="nav-item"><a asp-area="" asp-controller="Home" asp-action="About" class="nav-link">About</a></li>
                <li class="nav-item"><a asp-area="" asp-controller="Home" asp-action="Contact" class="nav-link">Contact</a></li>
            </ul>
            <partial name="_LoginPartial" />
        </div>
    </nav>

and _LoginPartial.cshtml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@if (SignInManager.IsSignedIn(User))
{
    <form asp-area="Identity" asp-page="/Account/Logout" asp-route-returnUrl="@Url.Action("Index", "Home", new { area = "" })" method="post" id="logoutForm" class="ml-auto">
        <div class="navbar-nav">
            <div class="nav-item">
                <a asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage" class="nav-link btn navbar-btn">Hello @UserManager.GetUserName(User)!</a>
            </div>
            <div class="nav-item">
                <button type="submit" class="btn btn-link navbar-btn nav-link">Logout</button>
            </div>
        </div>
    </form>
}
else
{
    <div class="navbar-nav ml-auto">
        <div class="nav-item"><a class="nav-link" asp-area="Identity" asp-page="/Account/Register">Register</a></div>
        <div class="nav-item"><a class="nav-link" asp-area="Identity" asp-page="/Account/Login">Log in</a></div>
    </div>

}
  • Also, I have noticed a strange behavior at Manage/Layout sidebar navigation.

Note: As we know Identity is provided as a nuget package and if we like to override its view components, we should scaffold it. If you don’t know how to do that, check the docs.

For our purposes (we want to make the minimum changes on the template, basic stuff) we will scaffold only 2 basic components, as we can see in the photo below. In addition, we are specifying our existing layout, because we have already applied some changes to that file and we don’t want scaffold operation to override our existing layout:


Hint: Before we continue improving the Manage/ section of our app, I have noticed that in the 2nd line of Areas/Identity/Pages/Account/Manage/_Layout.cshtml:

Layout = "/Areas/Identity/Pages/_Layout.cshtml";

should be replaced by our existing layout, so replace the above with this:

Layout = "~/Views/Shared/_Layout.cshtml";

The main changes that should be applied here is in the _ManageNav.cshtml file, in which the .nav-stacked css class has been removed in Bootstrap 4. Also, we will make the appropriate changes about the nav. The complete code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@inject SignInManager<IdentityUser> SignInManager
@{
    var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any();
}
<div class="nav nav-pills flex-column navbar-light bg-light">
    <div class="nav-item"><a asp-page="./Index" class="nav-link @ManageNavPages.IndexNavClass(ViewContext)">Profile</a></div>
    <div class="nav-item"><a id="change-password" asp-page="./ChangePassword" class="nav-link @ManageNavPages.ChangePasswordNavClass(ViewContext)">Password</a></div>
    @if (hasExternalLogins)
    {
        <div class="nav-item"><a id="external-login" asp-page="./ExternalLogins" class="nav-link @ManageNavPages.ExternalLoginsNavClass(ViewContext)">External logins</a></div>
    }
    <div class="nav-item"><a asp-page="./TwoFactorAuthentication" class="nav-link @ManageNavPages.TwoFactorAuthenticationNavClass(ViewContext)">Two-factor authentication</a></div>
    <div class="nav-item"><a asp-page="./PersonalData" class="nav-link @ManageNavPages.PersonalDataNavClass(ViewContext)">Personal data</a></div>
</div>
  • Other updates related to Bootstrap 4:

    I, also, noticed a bunch of other updates, useful for our template, such as:

    • Carousel updates in class naming,
    • They dropped .form-group-* classes. Replace them with .form-control-* classes,
    • Use .form-check class instead of .checkbox,
    • .btn-default is now .btn-secondary.

    For a complete list of changes, you can take a look at the docs.

Bonus

The complete libman.json file for those who want to add the lib/ dir to their .gitignore:


Share this:

Buy me a coffeeBuy me a coffee