Adaptive/dynamic page numbering in c#

If you need to show many results (tens, hundreds or thousands), in a paged manner, you won’t want to display links to all those pages. I looked online for some c# that would adapt the number of page links shown to with the number of pages returned, but found nothing.

If you get 5 pages of results, show them all. If you get 5,000 pages of results, show some around your current page and less and less the further you get from your current page.

This is something I put together in an hour, I make no claims about its efficiency and there are scenarios that are not catered for (like higher current page than the total number of pages).

Here are some examples of what this code does.

Current Page:1 Total Pages:40 Pages to display around current page:5
1 2 3 4 5 6 7 8 9 10 11 20 30 40

Current Page:90 Total Pages:600 Pages to display around current page:5
1 40 50 60 70 80 85 86 87 88 89 90 91 92 93 94 95 100 110 120 130 140 200 300 400 500 600

Current Page:147 Total Pages:6825 Pages to display around current page:5
1 90 100 110 120 130 140 142 143 144 145 146 147 148 149 150 151 152 160 170 180 190 200 300 400 500 600 700 800 900 1000 1100 2000 3000 4000 5000 6000 6825

You could easily change the code to take a Page type to suit your own needs.

Here’s the code.

namespace NoDogmaBlog
{
    public class PagingHelper
    {
        public IEnumerable<int> GetListOfPages(int currentPage, int pagesAroundCurrent, int totalPages)
        {
            var pages = new Dictionary<int, int>();
            double powerOfTenTotalPages = Math.Floor(Math.Log10(totalPages));
            if ((int)powerOfTenTotalPages == 0)
            {
                powerOfTenTotalPages = 1;
            }
            pages.Add(1, 1);
            if (!pages.ContainsKey(totalPages))
            {
                pages.Add(totalPages, totalPages);
            }

            for (int loop = 1; loop <= powerOfTenTotalPages + 1; loop++)
            {
                GetPages(pages, currentPage, pagesAroundCurrent, totalPages, (int)Math.Pow(10, loop - 1));
            }
            return pages.OrderBy(k=>k.Key).Select(p=>p.Key).AsEnumerable();
        }

        private void GetPages(Dictionary<int, int> pages, int currentPage, int pagesAroundCurrent, int totalPages, int jump)
        {
            int startPage = ((currentPage / jump) * jump) - (pagesAroundCurrent * jump);

            if (startPage < 0)
            {
                startPage = 0;
                pagesAroundCurrent = 10;
            }

            int endPage = currentPage + (pagesAroundCurrent * jump);
            if (endPage > totalPages)
            {
                endPage = totalPages;
            }
            AddPagesToDict(pages, startPage, endPage, jump);
        }

        private void AddPagesToDict(Dictionary<int, int> pages, int start, int end, int jump)
        {
            for (int loop = start; loop <= end; loop += jump)
            {
                if (!pages.ContainsKey(loop))
                {
                    if (loop > 0)
                    {
                        pages.Add(loop, loop);
                    }
                }
            }
        }
    }
}

Drop down lists in ASP.NET MVC

This post shows two methods of implementing drop down lists in ASP.NET MVC 4. The code for data access and the general layout of the application should not be considered suitable for anything other than pedagogical purposes.

The provided source code uses entity framework and requires a local database to be running, see the web.config for naming.

The main components of the application are Vehicle and TyreType classes, and controllers for each.
The controllers have the standard Index/Create/Edit/Details/Delete views and actions.
The VehicleController shows two ways of providing a TyreType drop down list, one using the ViewBag and the other using a VehicleViewModel.

The TyreType is as follows.

using System.ComponentModel.DataAnnotations;

namespace Automobile.Models
{
    public class TyreType
    {
        public int TyreTypeID { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public string Material { get; set; }
    }
}

And the Vehicle looks like this.

using System.ComponentModel.DataAnnotations;

namespace Automobile.Models
{
    public class Vehicle
    {
        public int VehicleID { get; set; }
        [Required]
        public string Name { get; set; }
        public string Description { get; set; }
        public double MSRP { get; set; }
        [Required]
        public int TyreTypeID { get; set; }
        public virtual TyreType TypeType { get; set; }
    }
}

The TyreTypeController is a standard controller with text boxes for entering information on the Edit and Create views.

The VehicleController has a drop down list filled with available tyre types as found in the database.

Using the ViewBag

The first method of filling the drop down list is to use the ViewBag.

In the [HttpPost]Edit method we have –

ViewBag.TyreTypeID = new SelectList(db.TyreType, "TyreTypeID", "Name", vehicle.TyreTypeID);

I’ll explain in detail what this line of code is doing –
ViewBag.TyreTypeID – is referencing the ViewBag and dynamically adding an entry called TyreTypeID.

new SelectList(db.TyreType, "TyreTypeID", "Name", vehicle.TyreTypeID) – is doing five things –

  1. new SelectList – creates a new SelectList(this is what drop down lists use)
  2. db.TyreType – passing in the TypeTypes from the database
  3. "TyreTypeID" – specifying that this public property of TyreType will be used for dataValueField
  4. "Name" – specifying that this public property of TyreType will be used for dataTextField
  5. vehicle.TyreTypeID – specifying the selected value in the drop down list, note that it is the same property as the dataValueField

Inside the TyreType Edit view we have –

@model Automobile.Models.Vehicle
…snip…
   <div class="editor-label">
      @Html.LabelFor(model => model.TyreTypeID, "Type Type")
   </div>
   <div class="editor-field">
      @Html.DropDownList("TyreTypeID","--Select a tyre type--")
      @Html.ValidationMessageFor(model => model.TyreTypeID)
   </div>

In this example the "TyreTypeID" specifies both the source of items for the drop down list and the destination property for the selected value that will be sent back to the controller. In the example, the Vehicle is sent to the Edit action, so the Vehicle. TyreTypeID is set with the selected value.

I found this very confusing at first because I wanted to change the name of the ViewBag property for storing the drop down list items, so my selected value was being lost. MVC is doing a lot by convention over coding, if you fight it you will have to learn many rules.

I’m not a big fan of this approach, too many things are happening without my explicit control and if forces me to use the same name for a list of items (the SelectList in the ViewBag) and the selected item (an int).

Using a ViewModel

One alternative is to create a ViewModel for the Vehicle and the values for the drop down list. Note again, I’m not advocating this methodology for data access for production code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Automobile.DataAccess;
using Automobile.Models;

namespace Automobile.ViewModels
{
    public class VehicleViewModel
    {
        private AutomobileContext db = new AutomobileContext();
        public IEnumerable<SelectListItem> TyreTypes { get; set; }
        public Vehicle Vehicle { get; set; }
        public VehicleViewModel(Vehicle vehicle)
        {
            Vehicle = vehicle;
            TyreTypes = PopulateTyreTypes();
        }
        private IEnumerable<SelectListItem> PopulateTyreTypes()
        {
            var tyreTypesQuery = db.TyreType.OrderBy(t => t.Name);
            return new SelectList(tyreTypesQuery,"TyreTypeID","Name");
        }
    }
}

Inside the VehicleController I have

public ActionResult Create()
{
   //we're going to use the view model to send the tyre types to the view here.
   var vehicleViewModel = new VehicleViewModel(new Vehicle());
   return View(vehicleViewModel);
}
   
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Vehicle vehicle)
{
   if (ModelState.IsValid)
   {
      db.Vehicle.Add(vehicle);
      db.SaveChanges();
      return RedirectToAction("Index");
   }
   var vehicleViewModel = new VehicleViewModel(vehicle);
   return View(vehicleViewModel);
}

And the view has

@model Automobile.ViewModels.VehicleViewModel
…snip…
<div class="editor-label">
   @Html.LabelFor(model => model.Vehicle.TyreTypeID, "Tyre Type")
</div>
<div class="editor-field">
   @Html.DropDownListFor(model => model.Vehicle.TyreTypeID, Model.TyreTypes, "--Select a tyre type--" )
   @Html.ValidationMessageFor(model => model.Vehicle.TyreTypeID)
</div>

@Html.DropDownListFor(model => model.Vehicle.TyreTypeID, Model.TyreTypes, "--Select a tyre type--" ) is doing three things –

  1. model => model.Vehicle.TyreTypeID – specifies where the selected value from the DDL is stored
  2. Model.TyreTypes – is the source of SelectListItems for the DDL
  3. "--Select a tyre type--" – is a default value

This is the approach I prefer. Full source code is a attached here.

Entity Framework in an Dynamics Nav (Navision) environment (or using EF to access tables with unknown table names)

Summary
In this post I should how to use dynamic compilation to allow Entity Framework to reference tables whose names are not known at compile time.

Details
Entity Framework works great for the majority of scenarios; it handles tables in one database or spread across multiple databases very well.  Let’s say you have a site that sells products online for small companies you would need tables like company, customer, order, product, invoice etc, you would probably put all your data into a single set of tables and EF will work just fine.

However, if you have ever worked Microsoft Dynamics Nav (Navision) you know that it does not follow this standard structure.

Dynamics segregates the data differently. Each company had its own set of customer, order, product, invoice, etc, tables which were prefixed with the company name. For example, if you had two companies called ACME and SuperCorp the table structure would be like the following –

[ACME$Customer]
[ACME$Order]
[ACME$Product]
[ACME$Invoice]
[SuperCorp$Customer]
[SuperCorp$Order]
[SuperCorp$Product]
[SuperCorp$Invoice]

EF does not play nicely with this.

My first attempt was to pass in the table prefix to my DbContext when mapping, this worked for the first company passed in, but when I create a new DbContext for the second company, it would give model errors because somewhere deep in the workings of EF, something was being set statically and the mapping was failing (it was still pointing to the first company). If I created another new DbContext for the first company it worked fine again.

My second attempt was to pass in a DbCompiledModel for the company when constructing  the DbContext

DbContext(string nameOrConnectionString, System.Data.Entity.Infrastructure.DbCompiledModel model)

This worked a bit better than the first attempt, I could create a DbContext for the first and second and first (again) companies. I could retrieve data, but as soon as a there was a join in the query it failed, again it looked like something was being set the first time I created the DbContext and this was not changing when for the second company. I wasn’t happy with this approach anyway as it required a significant step away from well known EF practices of mapping and constructing a context.
My third approach was to create a context file specifically for each company which would inherit from a base context that contained all the DbSets and column mappings, table mapping was done in each individual context. This approached worked for all database queries, but has the huge issue of requiring a recompile and redeployment for each new company; a working, but impractical approach.

Building on this I came up with my solution. I created a CommonDBContext, which has the DbSets and the OnModelCreating where the table prefix is passed to the Mapping classes.
A DynamicContext class that is used to dynamically compile and construct DbContexts for each of the companies as needed. It also caches the compiled DbContext so you only take the compilation hit once for the lifetime of the application.

public abstract class CommonDBContext : DbContext
{

private readonly string tablePrefix;

protected CommonDBContext(string connectionString, string tablePrefix) :base(connectionString)
    {
        this.tablePrefix = tablePrefix;
    }

    public DbSet Customer { get; set; }
    public DbSet Order { get; set; }
    public DbSet Product { get; set; }
    public DbSet Invoice { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new CustomerMap(tablePrefix));
        modelBuilder.Configurations.Add(new OrderMap(tablePrefix));
        modelBuilder.Configurations.Add(new ProductMap(tablePrefix));
        modelBuilder.Configurations.Add(new InvoiceMap(tablePrefix));
    }
}

class DynamicContext
{
    private readonly static Dictionary<string, Type> CompiledContexts = new Dictionary<string, Type>();
    private readonly string _classNamePrefix;
    private static readonly object LockObject = new object();
    private readonly string _sourceCode =
            @"
            using System.Data.Entity;
            namespace Implementation.Context
            {{
                public class {0}_Context : CommonDBContext
                {{
                  public {0}_Context(string connectionString, string tablePrefix)
                        : base(connectionString, tablePrefix)
                    {{
                        Database.SetInitializer<{0}_Context>(null);
                    }}
                }}
            }}";

    #region Constructors

    public DynamicContext(string classNamePrefix)
    {
        _sourceCode = string.Format(_sourceCode, classNamePrefix);
        _classNamePrefix = classNamePrefix;
    }

    #endregion

    #region Public Methods

    public CommonDBContext GetContext(string connectionString, string tablePrefix)
    {
        Type[] constructorTypes = new Type[2] { typeof(string), typeof(string) };

        Type compiledType;
        //Double lock to prevent multiple compilations of same code
        if (!CompiledContexts.TryGetValue(_classNamePrefix, out compiledType))
        {
            lock (LockObject)
            {
                if (!CompiledContexts.TryGetValue(_classNamePrefix, out compiledType))
                {
                    compiledType = CompileContext(_classNamePrefix);
                    CompiledContexts.Add(_classNamePrefix, compiledType);
                }
            }
        }

        CommonDBContext contextObject = GetInstanceOfCompiledContext(connectionString, tablePrefix, compiledType, constructorTypes);
        return contextObject;
    }

    #endregion

    #region Private Methods

    private CommonDBContext GetInstanceOfCompiledContext(string connectionString, string tablePrefix, Type compiledContext, Type[] constructorTypes)
    {
        ConstructorInfo contextConstructorInfo = compiledContext.GetConstructor(constructorTypes);
        object contextObject = contextConstructorInfo.Invoke(new object[] { connectionString, tablePrefix });
        return contextObject as CommonDBContext;
    }

    ///
<summary>
    /// This is a one time hit for each class compiled.
    /// </summary>

    /// <param name="assemblyNames"></param>
    /// <returns></returns>
    private string[] GetAssembly(string[] assemblyNames)
    {
        string [] locations = new string[assemblyNames.Length];

        for (int loop = 0; loop <= assemblyNames.Length - 1; loop++) { locations[loop] = AppDomain.CurrentDomain.GetAssemblies().Where(a => !a.IsDynamic && a.ManifestModule.Name == assemblyNames[loop]).Select(a => a.Location).First();
        }
        return locations;
    }

    private Type CompileContext(string classNamePrefix)
    {
        var compilerParameters = new CompilerParameters { GenerateInMemory = true };

        compilerParameters.ReferencedAssemblies.AddRange(GetAssembly(new string[] { "Implementation.dll", "EntityFramework.dll" }));
        var provider = new CSharpCodeProvider();
        var compiled = provider.CompileAssemblyFromSource(compilerParameters, _sourceCode);

        Type compliedType = compiled.CompiledAssembly.GetType(string.Format("Implementation.Context.{0}_Context", classNamePrefix));
        return compliedType;
    }

    #endregion

}

public class CustomerMap : EntityTypeConfiguration
{
    public CustomerMap(string tablePrefix)
    {
        // Primary Key
        this.HasKey(t => t.CustomerID);
        //snip

        // Map the table name
        string tableName = string.Format("{0}$Customer", tablePrefix);
        this.ToTable(tableName)
    }
}

If you have trouble getting this working, get in touch.

SSN checking and formatting

Here’s something I worked on a few days ago. It shows six ways of verifying that an incoming string has nine numeric characters and then returns a string in the standard social security number format. In this example I perform the SSN checking and formatting using: static and instances of Regex; compiled and non-compiled; string replacements and match evaluators. More details on these can be found here.


using System.Text.RegularExpressions;

namespace NoDogmaBlog
{
  public class SSNFormatter
  {
    private const string IncomingFormat = @"^(d{3})(d{2})(d{4})$";
    private const string OutgoingFormat = "$1-$2-$3";
    readonly Regex regexNotCompiled = new Regex(IncomingFormat);
    readonly Regex regexCompiled = new Regex(IncomingFormat, RegexOptions.Compiled);

    #region Static
    public static string StaticStringRepleacement(string ssnInput)
    {
      var result = Regex.Replace(ssnInput, IncomingFormat, OutgoingFormat);
      return result;
    }

    public static string StaticMatchEvaluatorReplacement(string ssnInput)
    {
      var result = Regex.Replace(ssnInput, IncomingFormat, m => m.Groups[1] +
        "-" + m.Groups[2] + "-" + m.Groups[3]);
      return result;
    }
    #endregion

    #region NotCompiled
    public string InstanceNotCompiledStringReplacement(string ssnInput)
    {
      var result = regexNotCompiled.Replace(ssnInput, OutgoingFormat);
      return result;
    }

    public string InstanceNotCompiledMatchEvaluatorReplaement(string ssnInput)
    {
      var result = regexNotCompiled.Replace(ssnInput, m => m.Groups[1] +
        "-" + m.Groups[2] + "-" + m.Groups[3]);
      return result;
    }
    #endregion

    #region Compiled
    public string InstanceCompiledStringReplacement(string ssnInput)
    {
      var result = regexCompiled.Replace(ssnInput, OutgoingFormat);
      return result;
    }

    public string InstanceCompiledMatchEvaluatorReplaement(string ssnInput)
    {
      var result = regexCompiled.Replace(ssnInput, m => m.Groups[1] + "-"
        + m.Groups[2] + "-" + m.Groups[3]);
      return result;
    }
    #endregion
  }
}

I ran these methods on 10,000,000 randomly generated nine digit strings. I consistently observed results similar to those shown below.

Results

MethodTime
StaticStringRepleacement00:00:16.0028520
StaticMatchEvaluatorReplacement00:00:17.5301894
InstanceNotCompiledStringReplacement00:00:11.6908033
InstanceNotCompiledMatchEvaluatorReplaement00:00:13.8301780
InstanceCompiledStringReplacement00:00:09.1909727
InstanceCompiledMatchEvaluatorReplaement00:00:11.5331829
Be aware that using a compiled regular expression will suffer from a certain amount of overhead when compiling the expression. This overhead should be taken into consideration when writing shortlived applications.

Dotclear blog editing problem

The dotclear blogging engine has some issues when including pre-formated html; it removes all leading spaces and mangles empty lines.

This is a significant problem when posting nicely coloured code snippets like those produced by hilite.me or the SyntaxHilighter in WordPress.

A small hello world app ends up looking like this –

public class Hello1
{
public static void Main()
{
System.Console.WriteLine("Hello, World!");
}
}

Instead of this –

public class Hello1
{
   public static void Main()
   {
      System.Console.WriteLine("Hello, World!");
   }
}

Ahhh, much more readable. My way of solving this requires sed, so you’ll need a Linux installation, cygwin or Windows version of the command.

My hilite.me CSS looks like this –
border:solid gray;border-width:.1em .1em .1em .8em;padding:.2em .6em;font-size:9px

Create a file called SedFixesForDotclear.sed.
Its content is

s/^$/<br/>/g #replace blank lines with <br/>
s/t/    /g #replace tabs with spaces - then the next line replaces the spaces
:l s/^((&nbsp)*) /1&nbsp/;tl #replace all leading spaces with &nbsp

Run the command –
sed -f SedFixesForDotclear.sed input.html > output.html

Paste the output file into your post.