Day 27: Rendering Data in a Bootstrap Table

This is an installment in a 30 day series on Bootstrap and the MVC Framework. To see more, check out Day 0 for an index.

We created a nice tab for our users to be able to manage the different components of their account, hi-jacking the Manage Account feature of the default MVC template. Now we want to render the user’s outstanding notifications in a good looking table in one of those tabs.

Caution: this is the lipstick on a pig post of the series. Here be dragons…

Rendering Tables with Bootstrap

The first thing you need to know is that you don’t have to throw away a single thing you’ve learned in your years of HTML ninja skill building. Tables are still not to be used for layout. Tables are for lists of data. And more importantly, Bootstrap doesn’t try to change the semantics or document structure for a table. In fact, to get the Bootstrap look-and-feel in an HTML table, you need to apply but one class.

<table class="table">
  ...
</table>
So what else does it offer?  A bunch of common things that you might try to do, like “[tighter](http://getbootstrap.com/css/#tables-condensed)” versions of a table, [striped styling](http://getbootstrap.com/css/#tables-striped) or [hover-states](http://getbootstrap.com/css/#tables-hover-rows). You can also use the now familiar [contextual classes](http://getbootstrap.com/css/#tables-contextual-classes) on rows or cells to highlight pertinent information to your users. All in all, it’s a clean looking table that will suit most needs and fit in with the rest of the site. [![image](https://jcblogimages.blob.core.windows.net/img/2014/07/image_thumb1.png "image")](https://jcblogimages.blob.core.windows.net/img/2014/07/image4.png) Another important aspect of the Bootstrap table is the ability to easily make a table responsive. I don’t have the answer as to why this isn’t the default, but it’s easily added with a DIV wrapper that has the table-responsive class. This adds horizontal scroll bars to your tables, when needed, when they are viewed on smaller screens to ensure that the data doesn’t end up in some non-accessible, off-device part of the screen. [![image](https://jcblogimages.blob.core.windows.net/img/2014/07/image_thumb2.png "image")](https://jcblogimages.blob.core.windows.net/img/2014/07/image5.png) That wrapper looks like the following:
<div class="table-responsive">
    <table class="table table-striped ">
       <!-- table rows here -->
    </table>
</div>
## Retrieving the Notifications We’re going to need to get the list of notifications that haven’t yet been dismissed. You may have already created some test data with the efforts from the past few days, and that will work great here. Open the AccountController.cs class and navigate down to the Manage action.  Just before it, add the following code :
private IEnumerable<Notification> GetUserNotifications()
{
    // get the user ID
    var userId = User.Identity.GetUserId();

    // load our notifications
    var context = new SiteDataContext();
    var notifications = context.Notifications
        .Where(n => n.UserId == userId)
        .Where(n => !n.IsDismissed)
        .Select(n => n)
        .ToList();
    return notifications;
}
All this guy is doing, really, is snapping up the rows for this currently logged in user. One thing to mention here is that we’re really now _crying_ for some Dependency Injection. Our NotificationFilter and our AccountController are now both creating instances of our SiteDataContext – now multiple instances per request – and it’s making our code harder to test. ## Adding the Data to Our ViewBag Both the GET and POST versions of Manage are already relying on ViewBag to get data up to the view, so we’ll follow the same cue and put our notifications in there. In both methods you’ll find the ReturnUrl being assigned to a ViewBag property, so immediately after that, add the following line of code:
ViewBag.NotificationList = GetUserNotifications();
## Adding a Partial View for the Table Next, let’s get a partial view added called “_RenderNotifications.cshtml”.  The model type for the page will be a IEnumerable<Notification>, and we’ll iterate over the collection of rows to generate the TR and relevant TDs inside each of those. The entire view will look something like this:
@using SimpleSite.Models
@model IEnumerable<Notification>

<div class="table-responsive">
    <table class="table table-striped ">
        <tr>
            <th>Type</th>
            <th>Notification</th>
            <th>Actions</th>
        </tr>
        @foreach (var notification in Model)
        {
            var badgeClass = NotificationType.Email == notification.NotificationType
                ? "label-success"
                : "label-info";
            <tr>
                <td><span class="label @badgeClass">@notification.NotificationType</span></td>
                <td>@notification.Title</td>
                <td></td>
            </tr>
        }
    </table>
</div>

There’s a placeholder in there for “Actions”, which we’ll look at tomorrow when we revisit buttons and explore drop-downs.

Updating our Manage View

With the partial view in place and the data being loaded into the ViewBag we’re ready to update our view. Return to the Manage.cshtml file and locate our placeholder for the notifications. Update it to render the partial view, passing in the collection of notifications.

<div class="tab-pane active" id="notifications">
    @Html.Partial("_RenderNotifications", ViewBag.NotificationList as IEnumerable<Notification>)
</div>

That should be it! I found what seems to be a bug in Bootstrap where if you have a table in a tab, and the tab is set to active and you have the fade class, the table doesn’t seem to be visible on page load. It shows up fine after clicking on a tab, but to work around this you’ll notice that I’ve removed the fade class from the tab.

Oh Noes! It’s Turned Into A Mess!

Folks, I’m not going to lie; though the Account controller and Manage views may have never have been intended to handle our humble little notifications, I found several things in both the controller and related views that left me uncomfortable with the design. I’m trying to keep this as a “how to get some MVC in your Bootstrap” type series, but all of the following were worth noting as things I’d try to avoid:

  • Nested views with non-obvious dependencies
  • Multiple methods that do the same work as each other
  • Magic strings
  • Methods doing too many things or things that you wouldn’t attribute of them by their name (for example, the “Manage” action which resolves status messages based on optional parameters)
  • ViewBag use that gets in the way of the view’s maintainability
  • Views that don’t leverage Bootstrap enough
  • Way too much reliance on ViewBag, and, therefore,
  • Absence of reasonable view models
  • Dogs and cats playing together

I will perhaps one day sit down and hash through the AccountController, but needless to say, there’s some amount of work to be done! I, for one, would like to see more best practices in place, a more referencable example of how to do things and sample views that better embrace the Bootstrap visuals (since, after all, it’s included by default in the template).

Now on our end, we’ve done some off-script things as well, namely putting direct database access in a controller (and filter),  pushing database models directly up to the view and leaning on those ViewBag properties to shuffle data around. So, yes, kettle, meet teapot.

All of these things are leading up to another set of posts on best practices Smile.

Next Steps

Okay, our users can now see the list of notifications that are outstanding, but they have no way to manage them just yet. Tomorrow we’ll get some drop-down button action in play and explore some of the ways we can compose some pushable UI.

Day 26: Bootstrap Tabs for Managing Accounts

This is an installment in a 30 day series on Bootstrap and the MVC Framework. To see more, check out Day 0 for an index.

We’ve got this notification thing going on now and we’d like to give users a way to review notifications. There’s a fairly acceptable landing spot on the “Manage Account” view (at /Account/Manage in your browser), at least for the purpose of these exercises, so we’ll flesh things out there.

However, the view is isn’t really set up for notifications (it’s truthfully not the best spot) so we’ll need to give us some UI to make it work.

Understanding the Tab Component

There are two main elements you’ll need to get the tabs going correctly, a UL tag that will set up as the menu elements, and a DIV to act as a container for the content.

<ul class="nav nav-tabs" role="tablist" id="accountTab">
  <!-- content -->
</ul>

<div class="tab-content">
  <!-- content -->
</div>
Visually, you can link those elements as illustrated below: [![image](https://jcblogimages.blob.core.windows.net/img/2014/07/image_thumb.png "image")](https://jcblogimages.blob.core.windows.net/img/2014/07/image3.png) Because our site includes the JavaScript library for Bootstrap our tabs will automatically render and behave correctly. The classes help with the visuals, and the JS takes care of the behavior. The UL will contain LI elements for each tab that you wish to display on the page. For us, that will the notifications, linked accounts and password reset. Those last two are the content that already exists on the page at \Views\Account\Manage.cshtml, and the notifications bits are what we’ll fill in after our tabs are in place. In addition to those two root elements, you can use a bit of JavaScript to manipulate the tabs if needed. For example, if you wanted a particular tab displayed on page load, you could use the ID as part of a jQuery selector and call the show method as follows:
$('#accountTab a[href="#linkedAccounts"]').tab('show');
The DIV for content will in turn hold container elements for the rest of the content you want on the page. The structure will look something like this:
<div class="tab-content">
    <div class="tab-pane active" id="notifications">
        <!-- content -->
    </div>
    <div class="tab-pane" id="linkedAccounts">
        <!-- content -->
    </div>
    <div class="tab-pane" id="passwordReset">
        <!-- content -->
    </div>
</div>

Each of the tab-pane DIVs could also have a fade class applied, which creates a nice content-switching visual. Let’s use that.

Updating the View

If you haven’t done so already, open up the \Views\Account\Manage.cshtml file and start cutting it up! Inside the DIV.row DIV.col-md-12 structure, add the UL for the tab headers, and add a DIV to contain the tab pages including a placeholder for notifications, and the DIVs for linked accounts and password reset. Move the content from those parts of the page in.

The final page code should be similar to the following:

@using SimpleSite.Models;
@using Microsoft.AspNet.Identity;
@{
ViewBag.Title = “Manage Account”;
}

<h2>@ViewBag.Title.</h2>

<div class=”row”>
<div class=”col-md-12”>
<p class=”text-success”>@ViewBag.StatusMessage</p>

    <span class="kwrd">&lt;</span><span class="html">ul</span> <span class="attr">class</span><span class="kwrd">="nav nav-tabs"</span> <span class="attr">role</span><span class="kwrd">="tablist"</span> <span class="attr">id</span><span class="kwrd">="accountTab"</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">li</span> <span class="attr">class</span><span class="kwrd">="active"</span><span class="kwrd">&gt;&lt;</span><span class="html">a</span> <span class="attr">href</span><span class="kwrd">="#notifications"</span> <span class="attr">role</span><span class="kwrd">="tab"</span> <span class="attr">data-toggle</span><span class="kwrd">="tab"</span><span class="kwrd">&gt;</span>Notifications<span class="kwrd">&lt;/</span><span class="html">a</span><span class="kwrd">&gt;&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">a</span> <span class="attr">href</span><span class="kwrd">="#linkedAccounts"</span> <span class="attr">role</span><span class="kwrd">="tab"</span> <span class="attr">data-toggle</span><span class="kwrd">="tab"</span><span class="kwrd">&gt;</span>Linked Accounts<span class="kwrd">&lt;/</span><span class="html">a</span><span class="kwrd">&gt;&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">li</span><span class="kwrd">&gt;&lt;</span><span class="html">a</span> <span class="attr">href</span><span class="kwrd">="#passwordReset"</span> <span class="attr">role</span><span class="kwrd">="tab"</span> <span class="attr">data-toggle</span><span class="kwrd">="tab"</span><span class="kwrd">&gt;</span>Password Reset<span class="kwrd">&lt;/</span><span class="html">a</span><span class="kwrd">&gt;&lt;/</span><span class="html">li</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">ul</span><span class="kwrd">&gt;</span>

    <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="tab-content"</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="tab-pane fade active"</span> <span class="attr">id</span><span class="kwrd">="notifications"</span><span class="kwrd">&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">p</span><span class="kwrd">&gt;</span>Here's where we'll put our notifications.<span class="kwrd">&lt;/</span><span class="html">p</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="tab-pane fade"</span> <span class="attr">id</span><span class="kwrd">="linkedAccounts"</span><span class="kwrd">&gt;</span>
            <span class="kwrd">&lt;</span><span class="html">section</span> <span class="attr">id</span><span class="kwrd">="externalLogins"</span><span class="kwrd">&gt;</span>
                @Html.Action("RemoveAccountList")
                @Html.Partial("_ExternalLoginsListPartial", new ExternalLoginListViewModel { Action = "LinkLogin", ReturnUrl = ViewBag.ReturnUrl })
            <span class="kwrd">&lt;/</span><span class="html">section</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>
        <span class="kwrd">&lt;</span><span class="html">div</span> <span class="attr">class</span><span class="kwrd">="tab-pane fade"</span> <span class="attr">id</span><span class="kwrd">="passwordReset"</span><span class="kwrd">&gt;</span>
            @if (ViewBag.HasLocalPassword)
            {
                @Html.Partial("_ChangePasswordPartial")
            }
            else
            {
                @Html.Partial("_SetPasswordPartial")
            }
        <span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>
    <span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>
<span class="kwrd">&lt;/</span><span class="html">div</span><span class="kwrd">&gt;</span>

</div>

@section Scripts { @Scripts.Render(“~/bundles/jqueryval”) }

Next Steps

All that’s left now is to get our list of user-specific notifications into our view. Tomorrow we’ll get a view model figured out, populate it with the user’s notifications and get it rendering in a Bootstrap-styled table in the view.

Day 25: Personalizing Notifications

This is an installment in a 30 day series on Bootstrap and the MVC Framework. To see more, check out Day 0 for an index.

Back on Day 19 we introduced persistent storage for notifications, allowing us to pop a custom badge up in the navbar. This was great, but as we left it, it was creating notifications only in the seed method of our DbContext migrations configuration, and the notifications were shown to all users. Not too helpful for dialing in on specific details or messages for specific users.

Today we’re going to get that “everyone’s data” out of the mix, update our notifications so that they belong to a single user and then create a temporary way for us to add new, user-specific notifications to the site.

Clearing our DB and Seed Method

Let’s get those records (from our seed method) out of the database. Locate your DB in SQL Server Management Studio and delete the rows. Something this simple is adequate:

delete from notifications
Now, the only thing is that effort is all in vain if we don’t clean out our seed method. Each time the database configuration class is used to perform or check for migrations it will re-insert those rows. Locate the Configuration class, which should be in \Migrations directory in the root of your solution. Comment out or delete all the code we added to upsert the notifications. ## Extend our Notifications Class Let’s next add a couple of properties to our Notification class, located in \Models.
public string UserId { get; set; }
public bool IsDismissed { get; set; }
Remember that when we modify a class that takes part in our Entity Framework works that we’ll also need to generate a migration and update the database to match our model. Type these commands into the Package Manager Console, updating the namespace appropriately:
Add-Migration PersonalNotifications -ConfigurationTypeName SimpleSite.Migrations.Configuration
Update-Database -ConfigurationTypeName SimpleSite.Migrations.Identity.Configuration

The first command creates a migration for us, and the second updates the database accordingly.

Updating our ActionFilter

So, if notifications belong only to users, we never want our filter to execute if the current request is for an unauthenticated user. We’ll also want to make sure that we only capture notifications for the user that _is_ logged in, and then, only the notifications that have not yet been seen. 

Here’s the updated code for the NotificationFilter (located in \Filters):

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated) return;

var userId = filterContext.HttpContext.User.Identity.GetUserId();

var context = <span class="kwrd">new</span> SiteDataContext();
var notifications = context.Notifications
    .Where(n =&gt; n.UserId == userId)
    .Where(n =&gt; !n.IsDismissed)
    .GroupBy(n =&gt; n.NotificationType)
    .Select(g =&gt; <span class="kwrd">new</span> NotificationViewModel
    {
        Count = g.Count(),
        NotificationType = g.Key.ToString(),
        BadgeClass = NotificationType.Email == g.Key
            ? <span class="str">"success"</span>
            : <span class="str">"info"</span>
    });

filterContext.Controller.ViewBag.Notifications = notifications;

}

Scaffolding a Temporary Controller and View

The MVC Framework has some great scaffolding capabilities, as we’ve explored in minor detail so far. Today we’re going to use this feature to create our whole controller and the related views for all our CRUD operations. Right-click as you normally do on the controllers folder, and click Add->Controller.

This time ‘round, use the Scaffold for the “MVC5 Controller with views, using Entity Framework”. Fill out the options as follows:

image

You are selecting the Notification model, checking off “Generate views” and “Use a layout page”. The controller name should automatically be set to NotificationsController for you. Click Add to finish it out.

image

One more thing: you’re going to want an easy way to get your UserId – it’s what we’re using to match the notifications – so add the following to your Create view in Views\Notifications\Create.cshtml:

@if (User.Identity.IsAuthenticated)
{
<p>Your User ID is <b>@User.Identity.GetUserId()</b></p>
}

That will output your UserId (which is a Guid) so that you can create notifications for yourself.

Now when you run the site, sign in and navigate to the /Notifications path. This will show you an empty list, but you’ll have a link to create some new records. Add some to the site, using your UserId, and watch the navbar light up.

image

Next Steps

Now, I did say this is a temporary solution. By no means would you actually have a situation where you’d have users enter their own notifications, you’d more likely have events happen in the system that require some notification to be required – perhaps the completion of a job or a required update to some business process.  That’s why we just used the scaffolding today…the NotificationsController and view are something that you’ll likely eventually just delete…and that’s okay! One of the nice things about scaffolding is that you’re not married to it. So delete it when you’re done with it.

In the real world, however, you would likely want users to be able to see and manage notifications in some way. Tomorrow we’ll look at getting the first of those bits in place.

Day 24: Storing User Profile Information

This is an installment in a 30 day series on Bootstrap and the MVC Framework. To see more, check out Day 0 for an index.

Session is an attractive and oft-used mechanism for storing user profile data. It’s freely available and has been around forever. But session state and logged-in user identity, while they may seem closely related, do not operate on the same lifecycle and sensitive data, personal data, could get “leaked out”.

And hey…this post assumes you’ve been following along with the series and you have already signed in at least once with a registered user.

A Better Place to Store User Profile Data

In yesterday’s article we penned in the user’s choice of Bootstrap Theme and stored their selection in the Session object. Brock Allen wrote a great post a couple years back on why this kind of thing isn’t a great approach. The things that concern us most are that:

  • By default, session isn’t durable and doesn’t scale
  • Even if we move to a more durable session management approach, there’s no persistence of session data and yet we’re making network hops
  • Session isn’t tied to users signing in or out

So, today, we’re going to fix that Session access with a permanent, more reliable and secure approach.

Extending the User Profile Data

Since you’ve already created an account, you technically have some profile information already stored in your site’s database. We’re going to leverage the identity infrastructure of our project and extend the class that keeps track of our data, adding in the user’s selected theme. In your Solution Explorer, locate the ApplicationUser class under Models. The easiest way is usually just through the search box at the top:

image

Add the following property to your ApplicationUser class:

public string CssTheme { get; set; }

Something to keep in mind: we’re going to be modifying a class that participates in Entity Framework persistence, as managed by the Asp.Net Identity libraries. This is handy, but not free. Because we’re changing essentially the schema of a table, we’ll also need to enable and create a migration from the Package Manager Console:

Enable-Migrations -ContextTypeName SimpleSite.Models.ApplicationDbContext -MigrationsDirectory Migrations\Identity
Add-Migration CssTheme -ConfigurationTypeName SimpleSite.Migrations.Identity.Configuration

Note that we’ve got a pre-existing migration on our site, so we need to now be more specific and explicitly name the Configuration type. Also, in enabling the migrations, I added the MigrationsDirectory folder for the DbContext, so that our identity-related migrations would be in a sub-folder.

The Entity Framework created the appropriate classes for me to track DbContext-specific settings and the migration that I needed to update the database, but those are just the classes, nothing’s changed in the DB yet. That all needs to be followed by an update to our database like so:

Update-Database -ConfigurationTypeName SimpleSite.Migrations.Identity.Configuration

We can now store the data we need to, we just need a way to be able to stuff it in there.

Updating our Controller

Since we’re now targeting a user managed from the Identity libraries we’re going to wipe out the code that writes to session and instead use the relevant classes to locate the user profile and update it. Head over to ProfileController.cs (in Helpers) and replace the call to Session with the following:

var userStore = new UserStore<ApplicationUser>(new ApplicationDbContext());
var manager = new UserManager<ApplicationUser>(userStore);
var user = manager.FindById(User.Identity.GetUserId());
user.CssTheme = themename;
manager.Update(user);

We resolve the user through a UserManager, and the manager needs a UserStore to locate it’s data. We can then set the CssTheme and update the user through the manager. ApplicationUser and ApplicationDbContext are just the names of the types that were automatically created for you through the project template.

It’s only 5 lines of code to access and update a property, but you can see how there must be a better solution to all this than having to write this code all the time. Some day I bet a post will pop up on that…

Updating our Layout

Open up _Layout.cshtml (in Shared\Views) and update the code that resolves the correct style bundle. We’re going to use a similar approach to what we did in the controller to find the user and property, and we’ll handle the null case a little differently than we were previously as well by setting the default in advance.

@{
var theme = Bootstrap.Theme.Stock;
if (User.Identity.IsAuthenticated)
{
var userStore = new UserStore<ApplicationUser>(new ApplicationDbContext());
var manager = new UserManager<ApplicationUser>(userStore);
var user = manager.FindById(User.Identity.GetUserId());
theme = user.CssTheme ?? theme;
}
@Styles.Render(Bootstrap.Bundle(theme))
}

Our other line of code – to actually render the bundle – will remain the same, as you can see at the bottom.

Wait, What Did We Actually Do Again?

I know, I know, it’s hard to put time into something when it seems that nothing really changed. Our functionality is identical and users still have the same options as they did before.

image

But technically our solution is a little more sound.  Here’s what we did again as a bit of a recap:

  • We added a CssTheme property to our ApplicationUser class
  • We enabled migrations on our ApplicationDbContext, using a specify folder for our identity migrations
  • We added a migration to accommodate our new CssTheme property
  • We updated our controller to use the Identity objects instead of session
  • We refactored our _Layout to get the theme of choice from the user’s profile information

Next Steps

For brownie points here, one could likely go to the “manage” bits (under Controllers\AccountController and Views\Account) and allow the user to make a theme selection from there. It’s likely a better home than continuously being available from the home page.

Hang on a sec, though…if we’ve got a place to store information about specific users now, why don’t we revisit our code that puts up those lovely notification icons in the navbar?

Day 23: Choosing Your Own Look-And-Feel

This is an installment in a 30 day series on Bootstrap and the MVC Framework. To see more, check out Day 0 for an index.

Here’s the thing: everybody’s site is going to look the same if everybody’s site uses Bootstrap, right? Well, if we did that to users, we’d sure be missing the point as developers, and for two key reasons: 1) With the LESS and SASS source it’s easy to customize, and 2) Because it’s easy to customize, there’s already people creating all kinds of alternate themes for Bootstrap.

So, we aren’t headed down a slippery slope here, we just need to make a little effort to give our users some unique looking sites.  Other posts will show you how to replace the Bootstrap theme, but this one will show you how to let your users choose from a list you’ve pre-built.

Download a Free Substitute

There are some great, free alternatives located at Bootswatch.com. So, start there and pick one or two to download, I chose Amelia and Darkly. We need to create a folder structure to organize our themes, and move the CSS into those folders. Mine ended up working like this:

image

Note that I also pushed a copy of the stock CSS for bootstrap into this structure. This allows us to simplify our code for theme switching, allowing users to pick the base theme if they like.

Shameless plug: If you’re looking for professionally designed themes to replace your palette, you can help out this blogger (me!) by purchasing one over at {wrap}bootstrap. They have a selection of great looking Bootstrap themes. A very affordable alternative to taking the time to create your own theme.

Creating a Helper Class

Next, we create a class called Bootstrap.cs (I put mine in \Helpers) so that we can programmatically work with the themes. This class is responsible for presenting the list of supported themes and resolving the path to them when we try to load the bundles.

public class Bootstrap
{
    public const string BundleBase = "~/Content/css/";

    public class Theme
    {
        public const string Stock = "Stock";
        public const string Amelia = "Amelia";
        public const string Darkly = "Darkly";
    }

    public static HashSet<string> Themes = new HashSet<string>
    {
        Theme.Stock,
        Theme.Amelia,
        Theme.Darkly
    };

    public static string Bundle(string themename)
    {
        return BundleBase + themename;
    }
}
This is a simple class, but it prevents us from duplicating code all over the place or unnecessary spelling mistakes. The other nice thing is that if you choose to add another theme to your project, you will just have to modify this one file and the rest will fall into place.  For that to happen, we’ll need to modify our startup to generate all the appropriate bundles. ## Updating Our Startup Bits Head into BundleConfig.cs (inside of \App_Startup) and replace the code that creates the Bootstrap bundle with the following:
foreach (var theme in Bootstrap.Themes)
{
    var stylePath = string.Format("~/Content/Themes/{0}/bootstrap.css", theme);

    bundles.Add(new StyleBundle(Bootstrap.Bundle(theme)).Include(
                stylePath,
                "~/Content/bootstrap.custom.css",
                "~/Content/site.css"));
}
We’re simply looping over that handle collection we created so that we could generate a bundle for every installed theme.  We always want all the themes – startup is only run at as the application starts, so we need them all there – as different users may wish to select different themes. ## Making Our Layout “Themeable” What we really need to do here is just a quick update to figure out the user’s current theme, and then figure out what the correct bundle to use is.
@{
    var theme = Session["CssTheme"] as string ?? Bootstrap.Theme.Stock;
}
@Styles.Render(Bootstrap.Bundle(theme))
I’m using Session for now, but I’ll explain why in a bit that is bad idea. ![Smile](https://jcblogimages.blob.core.windows.net/img/2014/06/wlEmoticon-smile3.png) Note that, at this point, you could set that theme default – right now set to Bootstrap.Theme.Stock – to whichever theme you like and run your app. The mechanics of building the bundle and the class to resolve it are all in place. ## Letting the User Choose a Theme Once again we’re going to revisit the _LoginPartial.cshtml file (in Views\Shared). In this round, we’re going to update the text that shows the logged in user’s email address (which, by default, is also their username). The LI for the username is now going to be a dropdown box in the navbar.
<li class="dropdown">
    <a href="#" class="dropdown-toggle" data-toggle="dropdown">Hello @username! <span class="caret"></span></a>
    <ul class="dropdown-menu" role="menu">
        <li>
            @Html.ActionLink("Manage Account", "Manage", "Account", routeValues: null, htmlAttributes: new { title = "Manage" })
        </li>
        <li class="divider"></li>
        @foreach (var theme in Bootstrap.Themes)
        {
            <li><a href="@Url.Action("ChangeTheme", "Profile", new { themename = theme})">@theme</a></li>
        }
    </ul>
</li>
I’ve taken that LI that was there – all it had was the user name, which was a link to Manage Account – and replaced it will all of the above code. We put in a divider and iterate over the list of known themes.  Each will be a link to a “ChangeTheme” action on the “Profile” controller. ## Adding our New Profile Controller Throw ProfileController.cs in your \Controllers directory with the following, lone action in the class:
public ActionResult ChangeTheme(string themename)
{
    Session["CssTheme"] = themename;
    if (Request.UrlReferrer != null)
    {
        var returnUrl = Request.UrlReferrer.ToString();
        return new RedirectResult(returnUrl);
    }
    return RedirectToAction("Index", "Home");
}

If we have a referring URL we can push the user back to the same page, otherwise we ship them home. The preference of theme is set in the Session.

And there you have it: users can now pick their own theme on your site:

image

Next Steps

This data doesn’t really belong in the user’s session…whenever the app pool is recycled or the website or IIS is restarted or their session expires they will lose this choice. Even worse, session and Identity aren’t on the same lifecycle, so when they log out the session persists and they’ll still see the theme they chose when they logged in.

So, where should it be stored? Tune in next time as we answer this question and more. Smile with tongue out

Happy coding! Smile

Day 22: Sprucing up Identity for Logged In Users

This is an installment in a 30 day series on Bootstrap and the MVC Framework. To see more, check out Day 0 for an index.

Typically you wouldn’t want the entirety of the internet adding and editing records at will without some form of authentication and authorization so that you can keep track of who’s editing your data, or so that your users can keep track of their own.

So, let’s continue with our project and build out some identity capabilities.

Okay, I’m Kidding. Just Press F5!

Great work, you’re all done!

As most folks are well aware, the default templates for Asp.Net applications now ship with a sample account administration implementation (reasonably good ones, at that). Users are able to register and log in using pre-built models, controllers and views. You can easily extend the template with 3rd party login capabilities, allowing folks with Microsoft, Facebook or Google accounts (and, and, and…) to log into your site as well. We’ve now got substantial improvements to identity management overall, with things like two-factor authentication, reductions in the leaky abstractions we’ve lived with, better testability, more flexibility in storage options, and more.

If you’re not familiar with these bits, it’s worth having a look, but this is a topic already well covered. Believe me, these are worth the reads:

But we’re here to do Bootstrappy things, right? So let’s spruce up that top bar a little for our logged in users with some MVC bits we build (HTML helpers) and some Bootstrap bits (image classes) that will take our site up a level.

Bootstrap Image Classes

The CSS library gives us a few easy-to-use helpers to make our images look consistent. Here’s a sample from the Bootstrap site:

image

The classes are as follows:

  • img-rounded – provides rounded corners to your rectangular images
  • img-circle – turns any image into a circle
  • img-thumbnail – makes your image look like a little Polaroid of itself

Making Members Feel Welcome

Today we’re just going to add a little touch to the navbar that our logged in users will see, keying in off of the default implementation of the Identity providers.  We’ll head in that direction by extending our HtmlHelper that generates Gravatar images, as we need to add a property for a CSS class to give us a nice round face on the page.  But first, we’ll have to add the following line of code to the GravatarOptions class:

public string CssClass { get; set; }
We’ll need to add that to the tag, so let’s revist the GravatarImage, likely located in the Helpers folder, to check for a value and add it to the tag if present. The full method should now look like this:
public static HtmlString GravatarImage(this HtmlHelper htmlHelper, string emailAddress, GravatarOptions options = null)
{
    if (options == null)
        options = GravatarOptions.GetDefaults();

    var imgTag = new TagBuilder("img");

    emailAddress = string.IsNullOrEmpty(emailAddress) ? string.Empty : emailAddress.Trim().ToLower();

    // <-- adding support for CSS
    if (!string.IsNullOrEmpty(options.CssClass))
    {
        imgTag.AddCssClass(options.CssClass);
    }
    // adding support for CSS  -->

    imgTag.Attributes.Add("src",
        string.Format("http://www.gravatar.com/avatar/{0}?s={1}{2}{3}",
            GetMd5Hash(emailAddress),
            options.Size,
            "&d=" + options.DefaultImageType,
            "&r=" + options.RatingLevel
            )
        );

    return new HtmlString(imgTag.ToString(TagRenderMode.SelfClosing));
}
Unfortunately there isn’t quite the exact Bootstrap class we need to make our image place and size well in the navbar, so we’ll need to open up our bootstrap.custom.css file and add the following structural class:

.navbar-image {
float: left;
padding: 10px 5px;
}

Finally, we’ll pop over to our _LoginPartial.cshtml (in Views\Shared) and modify the block of code displayed for logged in users.  Because I’m reusing the user’s name a couple of times (which is also their email address) I’m storing it in a variable first, and using that throughout the block. I also add a DIV as a container for our image, using the class that we just created. Last, I make a call to our GravatarImage helper, passing in the username (email!), an appropriate size for the toolbar (30px), and the Bootstrap class that gives us the shape we’re looking for (img-circle).

var username = User.Identity.GetUserName();
using (Html.BeginForm(“LogOff”, “Account”, FormMethod.Post, new { id = “logoutForm”, @class = “navbar-right” }))
{

@Html.AntiForgeryToken()

<div class=”navbar-image”>
@Html.GravatarImage(username, new GravatarOptions { Size = 30, CssClass = “img-circle” })
</div>

<ul class=”nav navbar-nav navbar-right”>
<li>
@Html.ActionLink(“Hello “ + username + “!”, “Manage”, “Account”, routeValues: null, htmlAttributes: new { title = “Manage” })
</li>
<li><a href=”javascript:document.getElementById(‘logoutForm’).submit()”>Log off</a></li>
</ul>
}

And now we’re rockin’ head shots in our navbar!

image

Next Steps

Perhaps you’ve modified your user profiles so that the username doesn’t have to be an email address. You could easily modify this example to read from a different property and generate the same type of effect.

What is sparkle without shine? Let’s give our users the ability to choose their own look-and-feel.  I mean, it worked for GeoCities, right?