I've been working on a Stack Overflow like pager for my personal use and I've gotten everything working pretty good.  Some of my logic is a bit suspect though, especially the logic in the Pager class itself.  I thought I'd try posting this code on here just to see what sort of responses I got.  I included my test cases as well.  Some of the test names might be weird, but I'll go back and fix that later. 

      public class Pager {
        public int TotalPages { get; private set; }
        public int SelectedItem { get; private set; }
        public int PageNumbersToShow { get; set; }
        public string CssClass { get; set; }
    
        public Pager(int selectedItem, int totalPages, int pageNumbersToShow = 5) {
          this.SelectedItem = selectedItem;
          this.TotalPages = totalPages;
          this.PageNumbersToShow = pageNumbersToShow;
          this.CssClass = "pager fl";
        }
    
        public override string ToString() {
          var finalString = new StringBuilder();
          var pagerDiv = new TagBuilder("div");
          pagerDiv.AddCssClass(CssClass);
    
          //prev 1 2 (3)
          //prev 1 (2) 3 next
          // (1) 2 3 next
          if (TotalPages <= PageNumbersToShow) {
    
            for (int i = 1; i <= TotalPages; i++) {
              finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString());
            }
    
          }
    
          //Greater than pagesize and selected page is less than pagesize
          // prev (1) 2 3 4 5 ... 11 next
          // prev  1 (2) 3 4 5 ... 11 next
          if (SelectedItem < PageNumbersToShow && TotalPages > PageNumbersToShow) {
    
            for (int i = 1; i <= PageNumbersToShow; i++) {
              finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString());
            }
            finalString.Append(new PageNumber().ToString());
            finalString.Append(new PageNumber(TotalPages).ToString());
    
          }
    
          //prev 1 ... 7 8 9 10 (11)
          //prev 1 ... 7 (8) 9 10 11 next
          if (SelectedItem > PageNumbersToShow && TotalPages - (PageNumbersToShow - 1) < SelectedItem) {
    
            finalString.Append(new PageNumber(1).ToString());
            finalString.Append(new PageNumber().ToString());
            for (int i = (TotalPages - PageNumbersToShow) + 1; i <= TotalPages; i++) {
              finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString());
            }
    
          }
    
          //prev 1 ... 4 5 (6) 7 8 ... 11 next
          if (SelectedItem >= PageNumbersToShow && TotalPages - (PageNumbersToShow - 1) >= SelectedItem) {
    
            finalString.Append(new PageNumber(1).ToString());
            finalString.Append(new PageNumber().ToString());
            var middle = (PageNumbersToShow / 2);
            for (int i = SelectedItem - middle; i <= SelectedItem + middle; i++) {
              finalString.Append(new PageNumber(i, (SelectedItem == i)).ToString());
            }
            finalString.Append(new PageNumber().ToString());
            finalString.Append(new PageNumber(TotalPages).ToString());
    
          }
    
          /* Add Previous and Next Link */
          if (SelectedItem != 1) {
            finalString.Insert(0, new PageNumber(SelectedItem - 1, "prev").ToString());
          }
          if (SelectedItem != TotalPages) {
            finalString.Append(new PageNumber(SelectedItem + 1, "next").ToString());
          }
    
          /* Copy final string into div inner HTML */
          pagerDiv.InnerHtml = finalString.ToString();
    
          return pagerDiv.ToString();
    
        }
    
        private class PageNumber {
          private const string cssClass = "page-numbers";
          private const string href = "?page={0}";
          private TagBuilder link = new TagBuilder("a");
          private TagBuilder span = new TagBuilder("span");
          public bool Current { get; private set; }
          public int Page { get; private set; }
    
    
          public PageNumber(int Page, bool Current = false) {
            this.Current = Current;
            this.Page = Page;
            span.AddCssClass(cssClass);
            span.SetInnerText(Page.ToString());
          }
    
          public PageNumber(int Page, string spanText) {
            this.Page = Page;
            span.AddCssClass(cssClass + " " + spanText);
            span.SetInnerText(spanText + " ");
          }
    
          public PageNumber() {
            span.AddCssClass(cssClass + " " + "dots");
            span.SetInnerText("...");
          }
    
          public override string ToString() {
            if (Current) {
              span.AddCssClass("current");
              return span.ToString();
            } else {
    
              if (span.ToString().Contains("dots")) {
                return span.ToString();
              }
    
              link.MergeAttribute("href", string.Format(href, Page));
              link.MergeAttribute("title", string.Format("go to page {0}", Page));
              link.InnerHtml = span.ToString();
              return link.ToString();
            }
          }
        }
      }
    
      [TestClass]
      public class PagerTests {
        // (1)
        [TestMethod]
        public void Should_Only_Print_Out_One_Span_If_Number_Of_Pages_Is_One() {
    
          //Arrange
          var pager = new Pager(1, 1);
    
          //Act
          var result = pager.ToString();
    
          //Assert
          result.ShouldEqual(@"<div class=""pager fl""><span class=""current page-numbers"">1</span></div>");
        }
    
        // (1) 2 3 next
        [TestMethod]
        public void Should_Not_Print_Out_Previous_If_Selected_Page_Is_First_In_List_Smaller_Than_Five() {
    
          //Arrange
          StringBuilder expectedValue = new StringBuilder();
          var pager = new Pager(1, 3);
    
          //Act
          var result = pager.ToString();
    
          //Assert
          expectedValue.Append(@"<div class=""pager fl"">");
          expectedValue.Append(@"<span class=""current page-numbers"">1</span>");
          expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers"">2</span></a>");
          expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>");
          expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers next"">next </span></a>");
          expectedValue.Append(@"</div>");
          result.ShouldEqual(expectedValue.ToString());
        }
    
        // prev 1 2 (3)
        [TestMethod]
        public void Should_Not_Print_Out_Next_Link_When_Selected_Page_Is_Last_In_List_Smaller_Than_Five() {
    
          //Arrange
          StringBuilder expectedValue = new StringBuilder();
          var pager = new Pager(3, 3);
    
          //Act
          var result = pager.ToString();
    
          //Assert
          expectedValue.Append(@"<div class=""pager fl"">");
          expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers prev"">prev </span></a>");
          expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
          expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers"">2</span></a>");
          expectedValue.Append(@"<span class=""current page-numbers"">3</span>");
          expectedValue.Append(@"</div>");
          result.ShouldEqual(expectedValue.ToString());
        }
    
        // prev 1 (2) 3 next
        [TestMethod]
        public void Should_Print_Out_Both_Next_And_Previous_When_Selected_Is_Not_First_Or_Last_In_List_Smaller_Than_Five() {
    
          //Arrange
          StringBuilder expectedValue = new StringBuilder();
          var pager = new Pager(2, 3);
    
          //Act
          var result = pager.ToString();
    
          //Assert
          expectedValue.Append(@"<div class=""pager fl"">");
          expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers prev"">prev </span></a>");
          expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
          expectedValue.Append(@"<span class=""current page-numbers"">2</span>");
          expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>");
          expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers next"">next </span></a>");
          expectedValue.Append(@"</div>");
          result.ShouldEqual(expectedValue.ToString());
        }
    
        // (1) 2 3 4 5 ... 11 next
        [TestMethod]
        public void List_Greater_Than_Five_Pages_Generates_Dot_Dot_Dot_Last_Link_With_Page_One_Selcted() {
    
          //Arrange
          StringBuilder expectedValue = new StringBuilder();
          var pager = new Pager(1, 11);
    
          //Act
          var result = pager.ToString();
    
          //Assert
          expectedValue.Append(@"<div class=""pager fl"">");
          expectedValue.Append(@"<span class=""current page-numbers"">1</span>");
          expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers"">2</span></a>");
          expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>");
          expectedValue.Append(@"<a href=""?page=4"" title=""go to page 4""><span class=""page-numbers"">4</span></a>");
          expectedValue.Append(@"<a href=""?page=5"" title=""go to page 5""><span class=""page-numbers"">5</span></a>");
          expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
          expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>");
          expectedValue.Append(@"<a href=""?page=2"" title=""go to page 2""><span class=""page-numbers next"">next </span></a>");
          expectedValue.Append(@"</div>");
          result.ShouldEqual(expectedValue.ToString());
    
        }
    
        // prev 1 ... 3 4 (5) 6 7 ... 11 next
        [TestMethod]
        public void List_Greater_Than_Five_Give_Prev_One_Dot_Dot_Dot_Four_Numbers_Dot_Dot_Dot_Last_Next() {
    
          //Arrange
          StringBuilder expectedValue = new StringBuilder();
          var pager = new Pager(5, 11);
    
          //Act
          var result = pager.ToString();
    
          //Assert
          expectedValue.Append(@"<div class=""pager fl"">");
          expectedValue.Append(@"<a href=""?page=4"" title=""go to page 4""><span class=""page-numbers prev"">prev </span></a>");
          expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
          expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
          expectedValue.Append(@"<a href=""?page=3"" title=""go to page 3""><span class=""page-numbers"">3</span></a>");
          expectedValue.Append(@"<a href=""?page=4"" title=""go to page 4""><span class=""page-numbers"">4</span></a>");
          expectedValue.Append(@"<span class=""current page-numbers"">5</span>");
          expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers"">6</span></a>");
          expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers"">7</span></a>");
          expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
          expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>");
          expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers next"">next </span></a>");
          expectedValue.Append(@"</div>");
          result.ShouldEqual(expectedValue.ToString());
    
        }
    
        // prev 1 ... 7 8 9 10 (11)
        [TestMethod]
        public void When_List_Is_Greater_Than_Five_And_Selected_Is_The_Last_Item() {
    
          //Arrange
          StringBuilder expectedValue = new StringBuilder();
          var pager = new Pager(11, 11);
    
          //Act
          var result = pager.ToString();
    
          //Assert
          expectedValue.Append(@"<div class=""pager fl"">");
          expectedValue.Append(@"<a href=""?page=10"" title=""go to page 10""><span class=""page-numbers prev"">prev </span></a>");
          expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
          expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
          expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers"">7</span></a>");
          expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers"">8</span></a>");
          expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>");
          expectedValue.Append(@"<a href=""?page=10"" title=""go to page 10""><span class=""page-numbers"">10</span></a>");
          expectedValue.Append(@"<span class=""current page-numbers"">11</span>");
          expectedValue.Append(@"</div>");
          result.ShouldEqual(expectedValue.ToString());
    
        }
    
        // prev 1 ... 7 (8) 9 10 11 next
        [TestMethod]
        public void When_List_Is_Greater_Than_Five_And_Within_PageSize_Of_End_Of_List_And_Last_Item_Is_Not_Selected() {
    
          //Arrange
          StringBuilder expectedValue = new StringBuilder();
          var pager = new Pager(8, 11);
    
          //Act
          var result = pager.ToString();
    
          //Assert
          expectedValue.Append(@"<div class=""pager fl"">");
          expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers prev"">prev </span></a>");
          expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
          expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
          expectedValue.Append(@"<a href=""?page=7"" title=""go to page 7""><span class=""page-numbers"">7</span></a>");
          expectedValue.Append(@"<span class=""current page-numbers"">8</span>");
          expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>");
          expectedValue.Append(@"<a href=""?page=10"" title=""go to page 10""><span class=""page-numbers"">10</span></a>");
          expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>");
          expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers next"">next </span></a>");
          expectedValue.Append(@"</div>");
          result.ShouldEqual(expectedValue.ToString());
    
        }
    
        //prev 1 ... 5 6 (7) 8 9 ... 11 next
        [TestMethod]
        public void When_Selected_Is_One_Less_Than_Page_Size() {
    
          //Arrange
          StringBuilder expectedValue = new StringBuilder();
          var pager = new Pager(7, 11);
    
          //Act
          var result = pager.ToString();
    
          //Assert
          expectedValue.Append(@"<div class=""pager fl"">");
          expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers prev"">prev </span></a>");
          expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
          expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
          expectedValue.Append(@"<a href=""?page=5"" title=""go to page 5""><span class=""page-numbers"">5</span></a>");
          expectedValue.Append(@"<a href=""?page=6"" title=""go to page 6""><span class=""page-numbers"">6</span></a>");
          expectedValue.Append(@"<span class=""current page-numbers"">7</span>");
          expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers"">8</span></a>");
          expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>");
          expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
          expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>");
          expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers next"">next </span></a>");
          expectedValue.Append(@"</div>");
          result.ShouldEqual(expectedValue.ToString());
    
        }
    
        //prev 1 ... 8 9 (10) 11 12 ... 15 next
        [TestMethod]
        public void When_Selected_Is_Exactly_Total_Pages_Minus_Page_Size() {
    
          //Arrange
          StringBuilder expectedValue = new StringBuilder();
          var pager = new Pager(10, 15);
    
          //Act
          var result = pager.ToString();
    
          //Assert
          expectedValue.Append(@"<div class=""pager fl"">");
          expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers prev"">prev </span></a>");
          expectedValue.Append(@"<a href=""?page=1"" title=""go to page 1""><span class=""page-numbers"">1</span></a>");
          expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
          expectedValue.Append(@"<a href=""?page=8"" title=""go to page 8""><span class=""page-numbers"">8</span></a>");
          expectedValue.Append(@"<a href=""?page=9"" title=""go to page 9""><span class=""page-numbers"">9</span></a>");
          expectedValue.Append(@"<span class=""current page-numbers"">10</span>");
          expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers"">11</span></a>");
          expectedValue.Append(@"<a href=""?page=12"" title=""go to page 12""><span class=""page-numbers"">12</span></a>");
          expectedValue.Append(@"<span class=""page-numbers dots"">...</span>");
          expectedValue.Append(@"<a href=""?page=15"" title=""go to page 15""><span class=""page-numbers"">15</span></a>");
          expectedValue.Append(@"<a href=""?page=11"" title=""go to page 11""><span class=""page-numbers next"">next </span></a>");
          expectedValue.Append(@"</div>");
          result.ShouldEqual(expectedValue.ToString());
    
        }
      }