MvcContrib Grid Part 6 – Sorting

This is part 6 of a series about the MvcContrib Grid.

I recently added single-column sorting support to the MvcContrib grid. This can be turned on by calling the “Sort” method on a grid declaration and accepting a parameter of type GridSortOptions in your controller actions.

Controller:

public ActionResult Sorting(GridSortOptions sort) 
{
  ViewData["sort"] = sort;
  var people = _peopleFactory.CreatePeople();
 
  if(!string.IsNullOrEmpty(sort.Column)) {
    people = people.OrderBy(sort.Column, sort.Direction);
  }
 
  return View(people);
}

View:

<%= Html.Grid(Model)
  .Sort(ViewData["sort"] as GridSortOptions)
  .Columns(column => {
      column.For(x => x.Id).Named("Person ID");
      column.For(x => x.Name);
      column.For(x => x.Gender);
      column.For(x => x.DateOfBirth).Format("{0:d}");
    }) %>

By calling the “Sort” method, this tells the grid that sorting should be enabled. This will generate sorting links for each column heading (note that currently sorting is enabled for all columns – there is no way to enable it for individual columns only. I’ll change this in a future release)

These sorting links will add two additional parameters to the querystring: Column and Direction. These can be handled in your controller action by taking as a parameter an object of type GridSortOptions.

Using this object, you can then sort your data using whatever mechanism you choose. Out of the box, MvcContrib provides an overload for the “OrderBy” extension method that takes a property name and a direction and delegates the sorting to IQueryable. However, use of this extension method is entirely optional.

This also works with the grid’s paging support, so if you want your data to be both paged and sorted then you can make a call to AsPagination (or by using a custom IPagination provider) after the call to OrderBy:

public ActionResult SortingAndPaging(int? page, GridSortOptions sort) 
{
  ViewData["sort"] = sort;
  var people = _peopleFactory.CreatePeople();
 
  if (!string.IsNullOrEmpty(sort.Column)) {
    people = people.OrderBy(sort.Column, sort.Direction);
  }
 
  people = people.AsPagination(page ?? 1, 10);
 
  return View(people);
}

…and the results will be as expected.

When a column is sorted, the CSS classes of “sort_asc” or “sort_desc” will be applied to the relevant <th> element, so you can style the column headings (for example, by adding up/down arrows).

Contributing to MvcContrib using Mercurial

Now that the source code for MvcContrib is moving back to CodePlex I’ve written a guide to contributing to MvcContrib using Mercurial.

Using Git with Windows Powershell

Whenever I’m working with a Git repository I tend to do so from a Windows Powershell command line running inside Console. I prefer this to the UNIX-like “git bash” that comes with msysgit and it’s fairly straightforward to extend Powershell to provide git integration.

Custom Prompt

The first thing that I have is a custom prompt when I’m within a Git repository:

gitprompt

This prompt shows various pieces of information about the current git repository:

  • “1.3” – The name of the current branch that I’m working on
  • “+0” – The number of files that have been added since the last commit
  • “~1” – The number of files that have been modified since the last commit
  • “-0” – The number of files that have been deleted since the last commit
  • “!” – Whether or not there are untracked files in the working directory

Essentially this is implemented by writing a custom “prompt” function inside your Powershell profile. My colleague Mark Embling wrote about this in detail.

Tab Expansion

I also use a custom TabExpansion function that provides tab-completion for common git commands.

For example, if I type “git ch<tab>” then powershell will insert “git checkout”. This is taken further by providing auto-completion for branch names and remote names, so typing “git push <tab>” would automatically fill in “git push origin” and “git push origin <tab>” would then cycle through my local branches.

To implement a custom TabExpansion function, you’ll need to open your Powershell profile (stored in Documents\WindowsPowershell\Profile.ps1). If this file doesn’t exist, then you’ll need to create it.

Next, create a function called “TabExpansion”. This function takes two arguments – the last word that was entered before the user hit the tab key as well as the entire line that has been entered into the prompt. Inside this function, we want to parse the entire line in order to extract the last “block” (ie the last piece of input not separated by a semicolon or a pipe):

function TabExpansion($line, $lastWord) {
  $LineBlocks = [regex]::Split($line, '[|;]')
  $lastBlock = $LineBlocks[-1] 
}

Next, we can use a regular expression to see whether the block begins with “git “. If so, then we’ll hand the input off to a function called “gitTabExpansion”:

function TabExpansion($line, $lastWord) {
  $LineBlocks = [regex]::Split($line, '[|;]')
  $lastBlock = $LineBlocks[-1] 
 
  switch -regex ($lastBlock) {
    'git (.*)' { gitTabExpansion($lastBlock) }
  }
}

The gitTabExpansion again uses regular expressions to identify what the user has entered and acts appropriately:

function gitTabExpansion($lastBlock) {
     switch -regex ($lastBlock) {
 
        #Handles git branch -x -y -z <branch name>
        'git branch -(d|D) (\S*)$' {
          gitLocalBranches($matches[2])
        }
 
        #handles git checkout <branch name>
        #handles git merge <brancj name>
        'git (checkout|merge) (\S*)$' {
          gitLocalBranches($matches[2])
        }
 
        #handles git <cmd>
        #handles git help <cmd>
        'git (help )?(\S*)$' {      
          gitCommands($matches[2])
        }
 
        #handles git push remote <branch>
        #handles git pull remote <branch>
        'git (push|pull) (\S+) (\S*)$' {
          gitLocalBranches($matches[3])
        }
 
        #handles git pull <remote>
        #handles git push <remote>
        'git (push|pull) (\S*)$' {
          gitRemotes($matches[2])
        }
    }	
}

Hopefully the comments are pretty self explanatory. The gitLocalBranches, gitCommands and gitRemotes functions invoke the appropriate git command and parse the output:

function gitCommands($filter) {
  $cmdList = @()
  $output = git help
  foreach($line in $output) {
    if($line -match '^   (\S+) (.*)') {
      $cmd = $matches[1]
      if($filter -and $cmd.StartsWith($filter)) {
        $cmdList += $cmd.Trim()
      }
      elseif(-not $filter) {
        $cmdList += $cmd.Trim()
      }
    }
  }
 
  $cmdList | sort
 }
 
function gitRemotes($filter) {
  if($filter) {
    git remote | where { $_.StartsWith($filter) }
  }
  else {
    git remote
  }
}
 
function gitLocalBranches($filter) {
   git branch | foreach { 
      if($_ -match "^\*?\s*(.*)") { 
        if($filter -and $matches[1].StartsWith($filter)) {
          $matches[1]
        }
        elseif(-not $filter) {
          $matches[1]
        }
      } 
   }
}

At the moment the functionality is quite limited but already I find this extremely useful when working with git repositories – it has already saved me countless keystrokes throughout the day.

I have also created similar functionality for Mercurial repositories which I’ve posted about here.

Using FluentValidation with an IoC Container

In my recent FluentValidation presentation I mentioned that if you’re going to be using FluentValidation with ASP.NET MVC then you should probably be using an Inversion of Control container rather than using the AttributedValidatorFactory.

What is a Validator Factory?

A validator factory is a class responsible for creating validator instances. The IValidatorFactory interface looks like this:

public interface IValidatorFactory {
  IValidator<T> GetValidator<T>();
  IValidator GetValidator(Type type);
}

The interface has two methods – one generic, one not. The GetValidator method will receive a Type instance representing the type of object that needs to be validated and it is the responsibility of this factory to create and return the appropriate validator instance.

Creating your own Validator Factory

To create your own Validator Factory you can either implement IValidatorFactory directly, or inherit from the ValidatorFactoryBase class (which does some of the work for you). In this example I’m going to create a validator factory that leverages StructureMap.

Firstly, you’ll need to register your validator types with StructureMap:

ObjectFactory.Configure(cfg => cfg.AddRegistry(new MyRegistry()));
 
public class MyRegistry : Registry {
  public MyRegistry() {
    For<IValidator<Person>>()
	.Singleton()
	.Use<PersonValidator>();
  }
}

Here I am configuring StructureMap using a custom Registry. In the Registry I tell StructureMap that when it is asked to instantiate an IValidator<Person>, it should return a PersonValidator.

Now, you can write a custom ValidatorFactory that leverages StructureMap to instantiate the validator:

public class StructureMapValidatorFactory : ValidatorFactoryBase {
	public override IValidator CreateInstance(Type validatorType) {
		return ObjectFactory.TryGetInstance(validatorType) as IValidator;
	}
}

In the CreateInstance method you receive a Type object that represents the type of validator that the framework requires (for example, typeof(IValidator<Customer>)). This method should attempt to instantiate the appropriate type (CustomerValidator) and return it (or return null if no such type exists).

Using the AssemblyScanner

The next version of FluentValidation (1.2) will also include an “AssemblyScanner” class that makes it very easy to automatically register all of the validator classes in a particular assembly with your IoC container. Using the AssemblyScanner, the MyRegistry class could look like this:

public class MyRegistry : Registry {
  public MyRegistry() {
 
    AssemblyScanner.FindValidatorsInAssemblyContaining<MyValidator>()
      .ForEach(result => {
           For(result.InterfaceType)
              .Singleton()
              .Use(result.ValidatorType);
      });
 
  }
}

Note that this functionality is not in the current 1.2 beta 3 release, but will be in 1.2 RC (or you can grab it from the source code).

Using the Factory with MVC

If you want to make use of FluentValidation’s ASP.NET MVC integration then you need to pass your ValidatorFactory to the FluentValidationModelValidatorProvider in your application startup routine:

protected void Application_Start() {
	RegisterRoutes(RouteTable.Routes);
 
	//Configure structuremap
	ObjectFactory.Configure(cfg => cfg.AddRegistry(new MyRegistry()));
	ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
 
	//Configure FV to use StructureMap
	var factory = new StructureMapValidatorFactory();
 
	//Tell MVC to use FV for validation
	ModelValidatorProviders.Providers.Add(new FluentValidationModelValidatorProvider(factory));        
	DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
}

…and that’s it. FluentValidation will now use StructureMap to instantiate validator instances as it requires them.

Sample code from this post can be downloaded from here.

Introducing .NET 4

I recently had a chance to read through the book Introducing .NET 4 by Alex Mackey.

In this book Alex provides an overview of the new technologies that will be coming along with .NET 4 and Visual Studio 2010 ranging from the IDE enhancements in Visual Studio to major new features in the BCL including (but not limited to) the Entity Framework, Code Contracts, Parallel Extensions and the Microsoft AJAX Library (there’s also a section on MVC with some quotes from yours truly).

Code samples are mainly in C# and are clear to understand and to the point.

This is not a book for beginners (despite the “introducing” in the title). The book is probably most useful to developers who already have some familiarity with .NET 3.5 and Visual Studio 2008 and are looking to see what’s new in the next version of Microsoft’s development ecosystem.

I did notice some odd formatting issues in some areas, but I believe these have been fixed in the revised eBook and do not significantly affect the readability.

I thought the approach taken in the book was quite interesting – Alex focuses on “breadth rather than depth” and provides you with just enough information to help you get a basic understanding of the topics involved rather than focusing on any one area in significant detail. At first, I wasn’t sure whether this would appeal to me (most of the tech books on my bookshelf are focused on a particular topic) but I found myself really enjoying Alex’s style. I picked up some interesting pieces of information about some areas of the Framework that I’d normally not be exposed to in my day-to-day work. I particularly enjoyed the chapter on BCL changes that shines a light on some of the new classes and methods that are available.

Alex also has a great post on his experiences working on the book for Apress – be sure to check it out.