Using JavaScript from a Windows Batch File

I’m using Unity on the Mac at the moment trying to create a game. One of the attractive aspects of Unity is the scripting; I can use C#. Because I’m creating an IOS game I have to use Unity on a Mac. As a result I have to use Mono IDE, which is fine and it works. But despite my best efforts I still hate using a Mac instead of Windows. I’m not a hater, but I hate it.

Rather than spend 10000 hours catching up I just copied the Unity project over to my Windows machine and edited the files in Visual Studio. Bliss.

The problem I then had was how to copy the files back to the Mac so I could complile the game and test it. It had to be a one click process otherwise it’ll be just as fiddly as using the Mac. The two machines are on the same network.

%The Solution%

I created a simple batch file to copy the files to my DropBox but that wasn’t enough. I needed more :

  • Prompt me to make sure I really want to copy the scripts over to the Mac
  • Create a backup folder in my DropBox. The folder name is date/time based eg; “2012-11-22 22_17_11″. Also create a Mac folder here.
  • Copy the scripts I edited on the PC to the new backup folder (version control?)
  • Copy the Mac scripts to the 2012-11-22 22_17_11\Mac folder for safekeeping
  • Remove all the scripts from the Mac
  • Copy the PC scripts over to the Mac

Stuck, I was on the brink of finally having to learn PowerShell when I discovered a fabulous solution (reality). So here it is; a 21st century one-click backup-and-copy solution :

I never knew you could call dynamic javascript from a batch file!

This odd piece of awkward magic performs the following unwieldy tasks :

  1. creates a tmp.js file which uses familiar javascript to create a variable whose value is the formatted date and time.
  2. Tmp.js then invokes WScript.Echo to output a dynamic batch file command which sets a batch file variable named YYYYMMDD (not my idea).
  3. Back in the original batch file tmp.js is executed
  4. The output (the dynamic batch command) is piped into a temp.bat which is then executed, and you get the formatted date/time filename in the YYYMMDD variable.

It’s like a wormhole that goes from .bat to .js and back again. Insane. I’m sure there’s a more modern solution than this; tell me please!

Wire this up to a button in Visual Studio (reality).

UPDATE

I’ve switched to robocopy now. I use it to mirror the whole unity project from the pc to the mac (but not before a whole heap of project issues sorted themselves out magically). Unity projects are interchangeable between mac and pc and this allows me to do all my development on the pc and switch to the mac when I need to run the game. This is fine for an ios project because at runtime it’s detached from unity anyway so it doesn’t make a lot of difference.

I host a website which remotely sends parameters to the game so I can experiment like you can in the unity ide when running a game from with unity. I debug/log the ios game by using an adapted version of DebugStreamer which outputs text to the screen which can be handy.

I still use the above batch file to backup the script source though I’ll probably switch to bitbucket soon. I can’t really store the whole unity project in bitbucket as it’s 450MB and growing.

Backbone.ModalDialog.js v0.3

Recently at work I gave my Backbone.js modal dialog a good run out on a fairly complex edit profile screen. Each distinct element of a user’s profile is editable separately in a modal dialog. I made a few changes along the way so now here’s the 0.3 release.

The changes in v0.3 are :

  • Added option showModalAtScrollPosition (default true) to determine whether the modal dialog is displayed so it is visible in a scrolled viewport (a sensible default), or is displayed at the top of the document where it might be invisible if the window has been scrolled down.
  • Fixed a problem where the opaque blanket div didn’t cover the entire screen when the window was scrolled. The modal blanket div’s height is recalculated every time a dialog is displayed (in case the window height has changed since last time).
  • Added the recentre() function which you can call to recentre a modal dialog in case the content has changed. Useful if errors messages have been added for example. Americans can use recenter().
  • Improved how the positioning works.
  • The showModal() function now returns this.
  • Added validation to the demo using Thomas Pederson’s excellent backbone.validation.js.

See the demo page live in action.

Backbone.ModalDialog.js v0.2

I’ve made a few changes to my Backbone.js modal dialog plugin. I’m using it in my own web app and I needed to make some changes and hopefully others will need them too.

Here’s a quick demo :

The new features are :

  • Added option to render the modal dialog into a given container element allowing relative absolute positioning.
  • Added option to slide the modal dialog down from above or up from below.
  • You can now provide an css properties to be applied to the modal dialog.
  • Clicking on a jQuery ui calender control no longer causes the modal dialog to close.
  • Improved the default position of the modal dialog to be more central.

Happy modalizing.

PS: The YouTube video quality is quite poor isn’t it, looks ok outside of YouTube. What’s wrong with it? Can anyone recommend a YouTube compatible screen capture app?

Backbone.js collections can listen to their models’ changes

I wanted to know if Backbone.js collections can listen to their models’ events. It turns out they can. In your collection you just need to use the same binding mechanism that you would in a view.

initialize:
      function()
      {
            this.on( "change:name", this.changeName);
            this.on( "change:age", this.changeAge);
      },

Here’s a JSFiddle test :

I looked in the Backbone.js source code and found where it happens :

// Internal method called every time a model in the set fires an event.
// Sets need to update their indexes when models change ids. All other
// events simply proxy through. "add" and "remove" events that originate
// in other collections are ignored.
_onModelEvent : function(ev, model, collection, options) {
    if ((ev == 'add' || ev == 'remove') && collection != this) return;
    if (ev == 'destroy') {
    this._remove(model, options);
    }
    if (model && ev === 'change:' + model.idAttribute) {
    delete this._byId[model.previous(model.idAttribute)];
    this._byId[model.id] = model;
    }
    this.trigger.apply(this, arguments);
}

Many-to-many relationships with PetaPoco

An example of a many-to-many relationship in a database are blog post tags. A blog post can have many tags and a tag can have many blog posts. So how do you do this in PetaPoco? I’ve added tag support to my PetaPoco A Simple Web App project on GitHub so I’ll explain what I did.

To start with you need to create a link table in your database which will stitch the article and tag tables together. So I created the articleTag table to contain lists of paired article ids and tag ids. This is all the info we need to persist this relationship in the database.

So if we have an article with 5 tags you’ll end up with 5 records in articleTag like this :

Creating these records is a one-liner if you have the article and tag ids :

_database.Execute(
            "insert into articleTag values(@0, @1)",
             article.Id, tagId);

There is a bit more complexity when it comes to reading article pocos and their tags. There are two ways of doing it :

The naughty+1 way

You could do this :

  1. Load the articles without the tags.
  2. Loop through each article and retrieve its tags
  3. Assign the list of tags to each article in the loop.

This is the N+1 problem and it doesn’t scale well. The more articles you’re loading the more database round trips you’ll make and the slower your app will run. Nobody should recommend this approach, but let’s see it anyway :

public Article RetrieveById( int articleId)
{
	var article = _database.Query(
		"select * from article " +
		"join author on author.id = article.author_id " +
		"where article.id=@0 " +
		"order by article.date desc", articleId)
			.Single
<article>();

 var tags = _database.Fetch(
 "select * from tag " +
 "join articleTag on articleTag.tagId = tag.id " +
 "and articleTag.articleId=@0", articleId);

 if( tags != null) article.Tags = tags;

 return article;
}

This example is just for one article. Imagine it if we were pulling back 50 articles. That would be 51 database round trips when all we really need is 1.

The right way

public Article RetrieveById( int articleId)
{
	return _database.Fetch(
		new ArticleRelator().Map,
		"select * from article " +
		"join author on author.id = article.author_id " +
		"left outer join articleTag on " +
				"articleTag.articleId = article.id " +
		"left outer join tag on tag.id=articleTag.tagId " +
		"where article.id=@0 ", articleId).Single();
}

Here I am pulling back a dataset that includes the article record, the author record and the tag records. You can tell this is a many-to-many relationship by the double joining first on the articleTag then on tag itself. The results that come back to PetaPoco look like this :

As you can see there is a fair bit of duplication here and this is a trade off you will want to think carefully about. The trade off is between the number of database round trips (number of queries) and result set efficiency (network traffic from the sql server to the web server (or service layer server)). It is best to have as few database round trips as possible. But on the other hand it is better to have lean result sets too. I’m sticking with the right way.

If I was writing a real blogging app I would think long and hard about a single joined query like this because the body content, which could be thousands of bytes, would be returned as many times as there are tags against the blog post. I would almost certainly use a stored procedure to return multiple result sets so there is only one database round trip. However typical non-blogging datasets won’t contain such unlimited text data eg; orders and order lines. So there’s no problem.

Document databases suit this type of arrangement. The tags would be embedded in the article document and would still be indexable.

Stitching the pocos together

See that new ArticleRelator().Map line above? PetaPoco can utilise a relator helper function for multi-poco queries so that each poco is correctly assigned in the data hierarchy. Having the function wrapped in a class instance means it can remember the previous poco in the results.

If you’re using multi-poco queries I urge you to read the PetaPoco documentation on the subject and experiment for an hour or two. All the relator class does is take the pocos coming in from each row in the resultset and stitch them together. It allows me to add each tag to the article as well as assign the author to the article.

Turn around sir

And what about from the other angle? Where we have a tag and we want to know the articles using the tag? This is the essence of many-to-many, there are two contexts.


public Tag RetrieveByTag( string tagName)
{
	return _database.Fetch(
		new TagRelator().Map,
		"select * from tag " +
		"left outer join articleTag on articleTag.tagId = tag.id " +
		"left outer join article on " +
		"article.id = articleTag.articleId " +
		"where tag.tagName=@0 order by tag.tagName asc", tagName)
		.SingleOrDefault();
}

This is an identical process as with retrieving articles but the tables are reversed. One tag has many articles in this context.

More responsibilities

Having many-to-many relationships does add more responsibilities to your app. For example when deleting an author it’s no longer sufficient to just delete the author’s articles followed by the author record. I have to remove the author’s articles’ tags from the articleTag table too otherwise they become data orphans pointing to articles that no longer exist. Add because we’re performing multiple database calls that are all required to succeed (or not at all), we need a transaction. Like this :

public bool Delete( int authorId)
{
	using( var scope = _database.GetTransaction())
	{
		_database.Execute(
			"delete from articleTag where articleTag.articleId in " +
			"(select id from article where article.author_id=@0)",
			authorId);
		_database.Execute( "delete from article where author_id=@0", authorId);
		_database.Execute( "delete from author where id=@0", authorId);

		scope.Complete();
	}

	return true;
}

Adding many-to-many support to PetaPoco – A Simple Web App was fairly painless and should fill a small hole in the internet. I’ve had a few people ask about it and it seemed the natural next step for the project.

Am I doing many-to-many wrongly? Would you do it differently? Let me know so I can learn from you.

Using jQuery to display a form validation error

I’m obsessed with best practice form design and usability. There are lots of guidelines about validation messages.

I’ve decided on a way of displaying validation errors and success messages on forms for my current project. I’ve turned this into a jQuery form error plugin on GitHub which provides some quick wins :

  • A single function call to display a validation message next to a field.
  • A single function call to remove a validation message and optionally displays a success image in its place.
  • No additional css is required.

In the GitHub project you’ll find the Index.html which demonstrates a simple form with some validation. Here’s a video of the plugin in action :

How do I use jquery.formError?

First of all you need to know when a form control has invalid data because it’s then that you want to call the plugin. I’ve kept the validation logic in the demo simple so the focus is on the plugin. If you’re using Backbone.js I can recommend the excellent backbone.validation plugin as it has the required valid/invalid callbacks you’ll need.

First you’ll need to include the jQuery.formError.js plugin javascript file. Then, to display a validation error message on an input with an id of “name” :

$("#name").formError(
       "Name cannot be greater than 15 characters long");

To remove the validation message when you have successfully revalidated the value :

$("#name").formError( {remove:true});

By default removing the validation message will place a validation success image in place of the error. So you’ll need an icon for this like the one in the demo. To disable this behaviour :

$("#name").formError(
   {
      remove:true,
      successImage: {enabled:false}
   });

The default image url is just “success.gif” which you can easily modify on a per-call basis :

$("#name").formError(
   {
      remove:true,
      successImage: {src:"img/success.gif"}
   });

The plugin also gives an invalid control the css class invalid. I leave it up to you to decide the visual effect .invalid has on the control. In the demo.css file you’ll see that it applies a red border. This css class is removed when you remove the error message.

Why not put the validation message underneath the control?

It’s common for web forms to put their validation messages directly underneath the invalid control. Like this :

I’ve had two problems with this approach :

  1. The insertion of the message makes the whole form increase in size. This is a visually jarring experience for the user but there is another problem with this.
  2. If you type in some invalid data and then press the submit button the first even to fire is the control’s change event. If the user has just corrected some data (a common pattern just prior to pressing the submit button) a validation message may be removed from underneath the control thanks to the control’s change handler. The whole form then shrinks a little and the mouse click, whose event fires next, is no longer on the submit button. The button has moved! So you have to click it again. This is an annoying and confusing user experience.

Finally

I did start with the qTip jQuery plugin for these messages but I wanted something simpler whose html I could control.

Creating A Modal Dialog In A Backbone.js Kind Of Way

I’m finally using Backbone.js. It’s brilliant and I can’t recommend it enough. Backbone is not trivial but it solves a difficult problem.

So I needed a modal dialog. I messed about with a couple of modal dialog plugins but had problems getting them to work in a way that fits in with Backbone.js. After finding out how easy it is to create your own modal dialogs I decided to create a new Backbone.js view from which other views can derive and inherit modal functionality.

You can download a demo of my Backbone modal view from my Github page which looks like this :

The demo doubles as a basic demonstration of Backbone.js and of my modal view. When you click “Add another person to the list” a Backbone view is created which derives from ModalView. This gives the child Backbone view a showModal() method. You just render your view as normal and then call showModal(). For example here is the click handler for the add person button :

$("#addPersonButton").click(
	function( event)
	{
		// Create the modal view
		var view = new AddPersonView();
		view.render().showModal(
			{
				x: event.pageX,
				y: event.pageY
			});
	});

The AddPersonView class extends my ModalView class like this :

AddPersonView = ModalView.extend(
{
	name: "AddPersonView",
	model: PersonModel,
	templateHtml:
		"<form>" +
 "<label for="personName">Person's name</label>" +
 "<input id="personName" type="text" />" +
 "<input id="addPersonButton" type="submit" value="Add person" />" +
 "</form>",
	initialize:
		function()
		{
			_.bindAll( this, "render");
			this.template = _.template( this.templateHtml);
		},
	events:
		{
			"submit form": "addPerson"
		},
	addPerson:
		function()
		{
			this.hideModal();
			_people.add( new PersonModel({name: $("#personName").val()}));
		},
	render:
		function()
		{
			$(this.el).html( this.template());
			return this;
		}
});

Because AddPersonView extends ModalView you can call showModal() on your view and this happens :

What you’re seeing is the el property of the AddPersonView instance being rendered into a modal container which gives you a few things for free :

  • You can close the dialog by either pressing escape, clicking outside of the dialog or pressing the close icon
  • The background is shaded back to highlight the modal view
  • The focus is automatically set on the first form control in the modal view
  • The modal dialog is, by default, positioned in the centre of the screen

In this example I’m positioning the dialog at the mouse cursor coordinates at the point when you click the “Add another person to the list” button. You can pass an options object to showModal() which gives you a bit of control of the internals of the modal dialog code. Here are the defaults that you can override :

defaultOptions:
{
	fadeInDuration:150,
	fadeOutDuration:150,
	showCloseButton:true,
	bodyOverflowHidden:false,
	closeImageUrl: "close-modal.png",
	closeImageHoverUrl: "close-modal-hover.png",
}

And as you have seen you can also pass in x and y properties. Hopefully these options are self explanatory except perhaps bodyOverflowHidden which helps the dialog stay on screen. The new Twitter add new tweet dialog does something like this too.

The demo includes two images that represent the close button and its hover state (it goes red when you hover over it). You can override the images easily through the showModal() parameter.

Back to the demo

If you type a name in and press the Add person button then a person model is added to the person collection. Because this is Backbone.js this automatically triggers the rendering of a new PersonItemView into the PersonListView :

I’m Happy

I’m happy I stepped back and learned javascript properly and got into Backbone.js. I find that being self critical and determined makes you a better developer. Backbone.js forces you to break your UI down into small units and collections of units, each with their own set of event handlers. And it forces you to do this before you start creating your UI. This is crucial because it enforces design and forethought, the absence of which normally leads to big balls of code mud.

To learn Backbone.js I found the following resources useful :

Finally I know that modal dialogs are known to be not in the best interests of usability but there is a subtle difference between true I-want-to-take-over-your-app-and-secretly-own-the-whole-world modal dialogs and these soft easily-closed dialogs. Facebook uses soft dialogs, as does Twitter. Use inline editing where it makes sense and a separate page where a modal dialog is being asked to do too much.

Download the code and demo from github or see the demo page live in action

Update: v0.3 is complete adding a few new features I needed.

Javascript Sandbox for ASP.NET MVC 3

I’ve started reading more about Javascript this year. My home project is coming up to the point where I’m making some important client side decisions and I want to make sure I’m making the best choices.

As anyone who has looked beyond the surface will tell you, Javascript is deceptively complex and capable. I have four books helping me out at the moment :

I recommend all four. I started reading Javascript Web Applications by Alex MacCaw because I wanted to understand how Javascript frameworks like KnockoutJS, BackboneJS and JavascriptMVC are constructed rather than just use them and this book is exactly for that purpose. For me it quickly proved to be a bit too “in at the deep end” so I’ve switched to Javascript Enlightenment by Cody Lindley to get a solid and deep understanding of Javascript.

All these books have code examples and I learn best by following, experimenting and pushing the samples with questions that pop up. So how does an ASP.NET MVC developer play around with Javacsript?

  • You could have a folder full of HTML files and chuck your javascript in there, and run them individually
  • You could use JS Fiddle
  • You could spend three hours creating a modest little sandbox framework built as an ASP.NET MVC app

I did the last one. At one point I abandoned it and switched to JS Fiddle, but then I went back to it. I prefer messing about in my own environment sometimes.

I’ll call your individual Javascript fiddles a sandcastle because I’m looking left and right and can’t see anyone telling me not to (although I am alone in my upstairs office). A Javascript sandcastle is created as a view like this :

There are three @sections you can use.

  1. Description : Optional description of what your javascript is testing
  2. Javascript_Setup : Stick your setup code in here
  3. Javascript_Test : The code that runs against the Javascript_Setup code

Then edit the Home/Index view to add a link to your new test. As you can see from the screenshot in the link I’ve added the html helper @Html.SandboxLink( sandboxViewName, description) to simplify generating links to your Javascript tests. I want to automate this at some point in the future so you only need to create the views.

The advantage you will notice at this point is that you get Intellisense in your sandcastle because it’s all in an ASP.NET MVC view in Visual Studio. The other advantage comes from how the _SandboxLayout.cshtml  page presents the results. Here’s what you see when you’ve run a test :

Your sandcastle is presented nicely and formatted using the terrific Syntax Highlighter by Alex Gorbatchev. There is a generous 500ms pause while I wait for the formatting to complete then I run your test code. In your JavaScript you can call the helper log() function which outputs to the Log area at the bottom thus completing your test and showing you what happened. Logging helps to see the flow of the code which isn’t always obvious with Javascript, look at a slightly more complex example to see what I mean.

When I’ve grokked the good parts of Javscript the next step on my client side journey is Javascript unit testing. When I mention “test” in this blog post I’m not talking about unit testing an application’s code, I’m talking about isolated tests that’ll help you figure out some code – a tiny bit like how we use LinqPad (but that’s in a different league of course).

You can download this project from my Javascript Sandbox For ASP.NET MVC 3 Github page (I’m really enjoying using it to learn Javascript) or you could use JSFiddle and wonder with bemusement why I spent 3 hours putting this project together, 2 hours writing this blog post and 15 minutes messing about with Git when I could have finished the book by now and be back working on my home project.

My home project is such a long way off because every little step of the way I’m going down all these rabbit holes and discovering that rabbit droppings taste good.

Added MVC Mini Profiler to PetaPoco – A simple web app

I saw a question on Stack Overflow asking how to setup Sam Saffron’s MVC Mini Profiler to work with PetaPoco and realised it would be a good idea to implement the mini profiler into my PetaPoco example app.

The latest release of PetaPoco included a change that made it very easy to integrate the profiler with PetaPoco if you want to. Prior to the latest version you had to hack the PetaPoco.cs file a little bit or implement your own db provider factory.  Pleasingly there is now a virtual function called OnConnectionOpened(), which is invoked by PetaPoco when the database connection object is first created. Being a virtual function you can override it in a derived class and return the connection object wrapped in the MVC Mini Profiler’s ProfiledDbConnection class. Like this :

public class DatabaseWithMVCMiniProfiler : PetaPoco.Database
{
   public DatabaseWithMVCMiniProfiler(IDbConnection connection) : base(connection) { }
   public DatabaseWithMVCMiniProfiler(string connectionStringName) : base(connectionStringName) { }
   public DatabaseWithMVCMiniProfiler(string connectionString, string providerName) : base(connectionString, providerName) { }
   public DatabaseWithMVCMiniProfiler(string connectionString, DbProviderFactory dbProviderFactory) : base(connectionString, dbProviderFactory) { }

   public override IDbConnection OnConnectionOpened(
      IDbConnection connection)
   {
      // wrap the connection with a profiling connection that tracks timings
      return MvcMiniProfiler.Data.ProfiledDbConnection.Get( connection as DbConnection, MiniProfiler.Current);
   }
}

I didn’t want to lose the existing Glimpse profiling I had in place so I made my class derive from DatabaseWithGlimpseProfiling, which is already in my project’s codebase, so you get both methods of profiling in one app.

public class DatabaseWithMVCMiniProfilerAndGlimpse : DatabaseWithGlimpseProfiling

This is turning into a profile demonstration app with a bit of PetaPoco chucked in :


You can download PetaPoco – A Simple Web App from my GitHub repository.

PetaPoco – A simple web app

I’ve put together a basic web app using PetaPoco to manage a one-to-many relationship between authors and their articles.

The author poco contains just the author’s name, id and a list of articles the author has written :

public class Author
{
	public int Id {get; set;}
	public string Name {get; set;}

	[ResultColumn]
	public List<Article> Articles {get; set;}

	public Author()
	{
		Articles = new List<Article>();
	}
}

The Author.Articles list is a [ResultColumn] meaning that PetaPoco won’t try and persist it automatically, it’s ignored during inserts and updates. The Article poco has more properties :

public class Article
{
	public int? Id {get; set;}
	public string Title {get; set;}
	public string Body {get; set;}

	[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode=true)]
	public DateTime Date {get; set;}

	[ResultColumn]
	public Author Author {get; set;}

	[Column( "author_id")]
	[DisplayName( "Author")]
	public int? AuthorId {get; set;}

	public Article()
	{
		Date = DateTime.Now;
	}
}

The Date property has a date format attribute so that in the \Article\Edit.cshtml view @Html.EditorFor(model => model.Article.Date) will display the date how I want it. The Author property is another ResultColumn only used when displaying the Article, not when updating it. In the ArticleRepository I use the MulltiPoco functionality in PetaPoco to populate the Author when the Article record is retrieved.

Setup

By default the app uses the tempdb at .\SQLEXPRESS. This is defined in the web.config :

<add name="PetaPocoWebTest" connectionString="Data Source=.\SQLEXPRESS;Initial Catalog=tempdb;Integrated Security=True" providerName="System.Data.SqlClient" />

The tempdb is always present in SQL Server and is recreated when the database is stopped and started. You can change this to suit your environment. The app will auto generate the tables for you if they don’t exist. In theory if you have SQL Express running you don’t need to do anything to get started

A few details

There are two repository classes; AuthorRepository and ArticleRepository. These classes are where the PetaPoco work lives. As well as loading the Author the AuthorRepository class also loads in the list of articles by that author. I use a relationship relator callback class as demonstrated in the recent PetaPoco object relationship mapping blog post. I made a slight tweak to handle objects that have no child objects at all otherwise there was always a new() version of Article in the list. The fix is simple :

if( article.Id != int.MinValue)
{
	// Only add this article if the details aren't blank
	_currentAuthor.Articles.Add( article);
}

I tried to get this working with an int? Id, but had type conversion problems in PetaPoco. I’ll investigate that later as it would be useful to have int? Id to indicate a blank record

I’ve used the Glimpse PetaPoco plugin by Schotime (Adam Schroder). Because the Glimpse plugin uses HttpContext.Current.Items all the SQL statements are lost when RedirectToAction() is called from a controller. I got around this by copying the PetaPoco Glimpse data into TempData before a redirect, and from TempData back into the Items collection before the controller executes.

This means you still see update/insert/delete SQL. It is definitely a requirement to perform a RedirectToAction() after such database calls so that it isn’t possible to refresh the screen and re-execute the commands (ie; cause havoc). If the user did refresh the screen (or otherwise repeat the last request) they’d just get the redirect to action and not the request that fired the database action.

I expect this to be a common pattern with Glimpse plugins that use response redirects.

UPDATE
Many thanks to Schotime who showed me that the Remote tab in Glimpse shows you the last 5 requests. All the SQL is there in Glimpse if you look for it. I didn’t realise this when I added the TempData solution :) but at least using TempData the SQL commands prior to a redirect are visible right on the PetaPoco tab without having to drill down to the previous request, which I kinda like as it’s more intuitive and effortless.

Hope this is useful to someone. You can download the source at GitHub. This is my first project using git so if there are any problems please let me know.

Finally, I’ve cut my finger and I’m angry with my cat.