If you've worked with ASP.NET MVC (or similar stack) web applications, you've likely noticed that it's very common to see some sort of sidebar widget with supplemental information. If you've got a page and want to display some handy summary information, like statistics for the site, doing so is basically the easiest thing in the world. We're going to walk through the different pieces in a sample setup of this which I've used in this very blog to get the site stats widget you see over there to the right.

site stats

Code on GitHub to follow along with is here.

First let's summarize all the pieces:

  • IBlogRepository - abstract repository which defines the data access methods for our entities (blog posts)
  • BlogRepository - concrete instance of IBlogRepository which defines the logic of each method
  • SiteStatsModel - model class with the fields that we'll be displaying in our sidebar widget
  • WidgetViewModel - view model class with fields for all the data that will be shown in all of our sidebar widgets (this is optional in case that your only sidebar widget is our site states; in this blog's case we're adding the site stats to some sidebar contents that are already there)
  • _Sidebars.cshtml - view to contain our sidebar widgets - each will be a partial view within this one (again, this is optional if site stats is going to be your only sidebar widget)
  • _SiteStats.cshtml - Our site statss widget itself!
  • BlogController - controller class to hold our sidebar child action
  • _Layout.cshtml - layout file, to which we'll add a single line to render our sidebar partial view
  • sidebar - css to define the display features of our sidebar content

We'll start at the lowest level - in the data access layer in our repositories. In the case of this blog we have the abstract IBlogRepository and the concrete BlogRepository. The data we'll need in this example are simple totals for the number of posts and categories. In your own case, these may be whatever numbers you're interested in derived from data in your database. Most of the code in this blog originates from the excellent blog post by Pride Parrot here, and that includes the following method signatures in IBlogRepository:

/// Return total no. of all or published posts.

/// True to count only published posts

int TotalPosts(bool checkIsPublished = true);

/// Return total no. of categories.

int TotalCategories();

as well as definitions of these methods in BlogRepository:

/// Return total no. of all or published posts.

/// True to count only published posts

public int TotalPosts(bool checkIsPublished = true)

{

return _session.Query().Where(p => !checkIsPublished || p.Published == true).Count();

}

/// Return total no. of categories.

public int TotalCategories()

{

return _session.Query().Count();

}

You may have your own more complex Linq or SQL queries to get & assemble your own data into the figures you're trying to display - this is a black box to be filled in according to your own needs.

The data you retrieve should align with the fields in the SiteStatsModel. In our case we have two int fields - TotalPosts and TotalCategories. Our class is not more complicated than this:

SiteStatsModel

namespace RyeBread.Models

{

    public class SiteStatsModel

    {

        public int TotalPosts { get; set; }

 

        public int TotalCategories { get; set; }

    }

}

This SiteStatsModel gets used - along with other model classes - to flesh out the WidgetViewModel, which covers all of our sidebar model content. The WidgetViewModel has the below constructor where we pass in a blogRepository and call the methods we defined earlier to populate the total. I've commented out the other Categories & LatestPosts bits to keep this example simple - WidgetViewModel actually has members for each of these and they're populated in this constructors as the commented lines illustrate.

WidgetViewModel

{

    public WidgetViewModel(IBlogRepository blogRepository)

    {

      //Categories = blogRepository.Categories();

      siteStatsModel = new SiteStatsModel();

      //LatestPosts = blogRepository.Posts(0, 10);

      siteStatsModel.TotalPosts = blogRepository.TotalPosts(true);

      siteStatsModel.TotalCategories = blogRepository.TotalCategories();

    }

    public SiteStatsModel siteStatsModel { get; set; }

    }

Next we'll take a look _Sidebars.cshtml. This is a strongly typed view to the WidgetViewModel. I've commented out the pieces we're not using, but you can see where thoese @Html.Partial invokations along with the unused members of our WidgetViewModel would have come in to populate other parts of the sidebar widget. We only need a div, which we're giving the ID "sidebars", and the inclusion of the partial view _SiteStats, which is strongly typed to a SiteStatsModel. We'll look at _SiteStats next.

@model RyeBread.Models.WidgetViewModel

 

@*Html.Partial("_Categories", Model.Categories)*@

@*Html.Partial("_Tags", Model.Tags)*@

@*Html.Partial("_LatestPosts", Model.LatestPosts)*@

@Html.Partial("_SiteStats", Model.siteStatsModel)

 

The partial view itself - _SiteStats.cshtml - is strongly typed to the SiteStatsModel we created earlier. We're going to have a div with the class "sidebar", a header to label the widget "Site Stats" and a small @if block to check if we have a postive number of posts or categories. If so, we display the number. Otherwise we display "No posts!" / "No categories!".

@model RyeBread.Models.SiteStatsModel

<!-- Widget to display site stats in sidebar -->

<div class="sidebar">

    <h3>Site Stats</h3>

    @if (Model.TotalPosts > 0)

    {

        <ul>

            <li class="stats">@Model.TotalPosts posts</li>

        </ul>

    }

    else

    {

        <p>No posts!</p>

    }

    @if (Model.TotalCategories > 0)

    {

        <ul>

            <li class="stats">@Model.TotalCategories categories</li>

        </ul>

    }

    else

    {

        <p>No categories!</p>

    }

</div>

With all of this done, we just have a couple things to complete, the first of which is in BlogController. In the controller class, we're going to have a method called Sidebars to return a PartialViewResult. This is going to populate an instance of the WidgetViewModel class with the controller's BlogRepository member. Then it will create and return a PartialViewResult - specifically an instance of the _Sidebars.cshtml view with the WidgetViewModel as its model to render.

decorated with the [ChildActionOnly] attribute, which ensures that this action method can be called only as a child method from within a view.

///

/// Child action that returns the sidebar partial view.

///

///

[ChildActionOnly]

public PartialViewResult Sidebars()

{

var widgetViewModel = new WidgetViewModel(_blogRepository);

return PartialView("_Sidebars", widgetViewModel);

}

This is going to be invoked by the folloing line in _Layout.cshtml, which will render the partial view:

@Html.Action("Sidebars")

Note that this should be whatever layout file you have for your application.

And that's it! You've added a sidebar with handy stats to your page. Try not to let all of the success resulting from this enhancement go to your head.

blog comments powered by Disqus