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.