On a site I’ve been working on recently various Css Hacks are used to ensure that the site is displayed consistently on all browsers.  However, as more and more browsers are released the css files just got messier and harder to maintain.  Moving the ‘hacks’ into their own file and selectively including them would make life a lot easier.  The usual way to achieve this is using conditional comments.  This is only supported in IE, but as most of our css hacks were around IE this was acceptable.

The problem with this however, is that the site was using ASP.Net Themes, and that automatically adds the relevant stylesheets to the page for you - meaning that you have no way of selectively choosing the correct stylesheets!  (Incidentally, I’d love to be proved wrong about this so please let me know if I’m missing something!).

I decided to write a more flexible theming system instead.  The plan was to load all the stylesheets in a certain directory and add them to the pages automatically in the same way ASP.Net themes do.  But it would also support convention-based subdirectories containing the ‘hacks’ for the different browsers.  The structure would be something like this:

image

Any css files in the Theme1 directory would always be included, but css files in the IE directory would only be included if the user was using IE.  The convention for the names of the folder is to match the Browser property of the HttpBrowserCapabilities class (accessible from Request.Browser).  I ended up also allowing further sub-directories so that different browser versions could have different stylesheets.

image

If you need a stylesheet for a specific version of a browser, you just create a folder with the version number as its name.  e.g. To have a stylesheet specifically for FireFox v2, create a folder called ‘2’ in the FireFox folder.  If you want a stylesheet for IE versions 6 and below, you can place it in a folder called ‘6-‘.  Likewise, if you want a stylesheet for versions 7 and up, you should place it in a folder called ‘7+’.  In the future I may extend this convention to allow things like ‘1-3’ and ‘4-7’ so that ranges of versions can be included.

I have uploaded this theming engine here.  To use the engine you must register the StylesheetManager control on your webforms/masterpage like so:

<%@ Register Assembly=”SPL.WebSite.Projects” Namespace=”SPL.WebSite.Projects.WebControls.Theming” TagPrefix=”spl” %>

And then in the <head /> section include an instance of the control:

<spl:StylesheetManager runat=”server” ThemeDirectory=”~/DemoPages/DemoStyles” />

The only property you need to set is the location of the root directory of your theme.  When the control renders it will figure out which stylesheets are required based on the user’s browser and write out <link /> tags for each one.

When running in release mode, instead of linking to n stylesheets, the control will link to an HttpHandler instead which will merge the css files into one and write them directly into the response.  To get this working you need to include this handler in your web.config:

<add verb=”GET” path=”CssCombiner.axd” type=”SPL.WebSite.Projects.HttpHandlers.Theming.CssCombineHandler, SPL.WebSite.Projects”/>

Note that the handler will cache the css to avoid multiple disk accesses on each request.  Currently this is cached for a hard-coded time of 1 hour.  Depending on your circumstances you may wish to change this to use a configuration value instead.

Feel free to use this theming engine if it meets your needs and please let me know if you have any improvements.  Note that the uploaded version doesn’t contain things like error handling, logging, etc and the http handler it uses hard-coded.  These are all things you will probably want to modify before using in anger.

A demo page is available here.

I found a good write-up of the PRG pattern in MVC by Matt Hawley this week, and have decided to use it in an MVC project I’m working on.  I have made a few changes to Matt’s code however. 

1 - Use ModelBinders and ModelState to Simplify Code

Firstly, as the new version of MVC (the beta release) supports Model Binders, I updated the example to use these instead.  Now we can just save the ModelState into TempData in one go, instead of saving the error messages and the users input, so the Submit action looks something like:

public ActionResult Submit()
{
    //OMITTED: Do work here...
    if (!ModelState.IsValid)
    {
        //Save the current ModelState to TempData:
        TempData["ModelState"] = ModelState;
    }
}

In the Create action we just need to pull these values out of TempData and add to the ModelState.  MVC will then enter the users input back into the textboxes for you.  The Create action looks like:

public ActionResult Create()
{
    //If we have previous model state in TempData, add it to our
    //current ModelState property.
    var previousModelState = TempData["ModelState"] as ModelStateDictionary;
    if (previousModelState != null)
    {
        foreach (KeyValuePair<string, ModelState> kvp in previousModelState)
            if (!ModelState.ContainsKey(kvp.Key))
                ModelState.Add(kvp.Key, kvp.Value);
    }

    return View();
}

(You will want to wrap this boiler plate code up in a helper class or something though)

2. Fix Scenario where user input will be lost

Secondly, I did find a small issue with the code as posted, when the user does the following:

  • GET the page with a form
  • POST the form with invalid input
  • REDIRECT back to the page (with the users input intact)
  • REFRESH the page - the users input is now lost!

I’m not sure this is a particularly common scenario, but losing the users input is never a good way to instil trust in your application!  The reason the data is lost in this case is because we stored the users input in TempData which only exists for this request and the next one.  I thought about putting the value into Session instead, but then you’d have to come up with a strategy for removing the items at the right time (you wouldn’t want the form to remember it’s values from the last time it was used for instance).  In the end I decided that just putting the values back into TempData would be the best solution.  This requires the following line to be added to the Create action:

public ActionResult Create() 
{ 
    //If we have previous model state in TempData, add it to our 
    //current ModelState property. 
    var previousModelState = TempData["ModelState"] as ModelStateDictionary; 
    if (previousModelState != null) 
    { 
        foreach (KeyValuePair<string, ModelState> kvp in previousModelState) 
            if (!ModelState.ContainsKey(kvp.Key)) 
                ModelState.Add(kvp.Key, kvp.Value); 
        TempData["ModelState"] = ModelState;  //Add back into TempData
    } 

    return View(); 
}

If the user now refreshes the page after a validation failure, they will no longer lose their input.  If they go on to fix the validation errors and submit the form, the saved TempData value will be automatically cleared by the MVC framework.

Yesterday, I attended my first DeveloperDay at the Microsoft Campus in Reading.  Below are the sessions that I attended and my thoughts on them:

TDD and Hard-To-Test Code - Ian Cooper

The first session of the day was about testing code which is hard to test.  The speaker, Ian Cooper, clearly had a lot of experience and knowledge about the subject.  Unfortunately however, I felt that there wasn’t really enough code.  Most of the presentation was about the sort of code that is hard-to-test, I was hoping for more help with how to test that code.  Having said that, I still found the talk informative and interesting.  The concept of ‘Seams’ was something I hadn’t come across by that name before (see here for a good example), although it is basically the Open/Closed Principle.

ASP.NET MVC - Show me the code - Steve Sanderson

Having followed MVC from the first preview, I was very interested in this presentation.  The format was very much about code not PowerPoint which I personally liked.  I thought Steve was extremely knowledgeable about MVC, and he really showed how easy MVC can be to create a fully functional website.  Despite not really learning much from the presentation (I’d used most of the code he used already myself), I really enjoyed the fast pace of it.  I think anyone in the audience that hadn’t already used MVC will have downloaded it by now!  He sold it very well.  Definitely a speaker to look out for the in future.

Steve also has an MVC book coming out soon - definitely one for the wish list!

ASP.NET 4.0 - TOP SECRET - Phil Winstanley and Dave Sussman

This was my most eagerly anticipated session.  However, it ended up being a bit of a disappointment.  The two speakers were unable to talk much about ASP.NET v4 as Microsoft didn’t announce them at the PDC.  Although they did show some nice features of VS 2010 (adornments look very nice!), it seemed as if the presentation was put together in a rush.  I didn’t feel that there was very much ‘meat’ in the talk, and it was only the ability of the presenters to make the audience laugh that kept it going.

Oslo, Microsoft’s vision for the future of Modelling - Robert Hogg

An interesting session about Oslo, something I didn’t know too much about.  The subject was clearly too big to talk about in just one hour, but Rob did cover quite a few things.  Oslo’s main aim is to increase pretty much everything by TEN TIMES!  Productivity, performance, everything!  Bold aims.  It’ll be interesting to see how much of it they can achieve.  The idea of improving the communication between BA’s, Architects and Dev’s could make a huge difference to the future of the industry if they can pull it off.  Oh, and the modelling tool Quadrant looks like it could become a showpiece WPF application.  Very shiny!

The bleeding edge of web - Helen Emerson

This was a good presentation to finish the day on, as my brain was starting to hurt!  Didn’t contain anything earth-shattering, but was an excellent introduction to the new features we can expect to have in the future versions of browsers.  Just a shame that it will probably take years for all browsers to implement them (I’m looking at you IE!).  Overall, a fun talk which Helen improved by getting some good audience participation.

Overall Thoughts

I enjoyed my first DeveloperDay overall.  I think in the future I will try to attend the sessions that I’m unfamiliar with, as I believe I will get more out of it that way - they are overviews rather than training sessions after all, so if you already have an overview of a technology pick a topic you don’t know instead.

Enjoyable day though, and all of the speakers did a brilliant job.

I have just uploaded my AutoTabExtender control to my Projects page.  Please feel free to take a look at the code and download it if it’s useful for you.

I decided to create this control when I had a broken hand.  While entering my memorable to login to my online bank account, I realised that having to press ‘tab’ to move from day to month to year was really slowing me down with only one typing hand!!  This control can extend a textbox so that focus automatically moves on when the length of the text entered equals the MaxLength property.  The usage of the extender is as follows:

<asp:TextBox runat="server" ID="txtPart1"MaxLength="2" Columns="2"></asp:TextBox>
<asp:TextBox runat="server" ID="txtPart2"MaxLength="2" Columns="2"></asp:TextBox>
<asp:TextBox runat="server" ID="txtPart3"MaxLength="2" Columns="2"></asp:TextBox>

<spl:AutoTabExtender runat="server" ID="ate1" TargetControlID="txtPart1" NextControlID="txtPart2"></spl:AutoTabExtender>

<spl:AutoTabExtender runat="server" ID="ate2" TargetControlID="txtPart2" NextControlID="txtPart3"></spl:AutoTabExtender>

 

So, you need an extender for each textbox that should auto-tab.  You then need to specify the NextControlID to indicate to which control the focus should be moved.  In the example above I have used a form for entering a sortcode, so we need an extender for the first and second textboxes.  The extender will also allow ‘natural’ deleting between textboxes.  See the live demo for this here.

The extender should work in IE, FF and Chrome.

As promised, this is my follow up post to this post.  This time I will show how to use the DynamicProxy library with mixins.  Using mixin’s you can add functionality to an object at runtime.  In this example, I will continue the lazy load theme from the previous post.

Imagine we have a contacts application, which contains a Person object.  This all works splendidly until one day we are asked to create a sales application.  This application must use our existing repository of contacts, but cannot use the same database.  In this new application we derive a new class from Person, with a few new attributes defining how the customer is to be treated:

public class Customer : Person
{
    public bool ApplyDiscount { get; set; }
    public bool AllowFreeDelivery { get; set; }
}

Now, to load a Customer, we must first load the main person data from the contacts database, and then load the extended data from the new sales database.  This means that each time a Customer object is loaded, there will be two database calls (no, we can’t use linked servers to join the databases!).  Most of the time, this would be fine, but if you don’t need the extended Customer information, then it’s still a wasted database call.  (I know this sounds like a very contrived example, but I have really worked on a project where we needed to do just this).

How can we get round this?  Well, in a similar way to the previous post, we need to dynamically load the data when it’s requested.  In the previous example however, when we intercept to ‘get’ call, we check to see if the data has already been loaded to prevent it hitting the database every time we get the property.  However, in this case the Customer object only has boolean fields - we can’t check these to see if the data has already been loaded as neither true nor false imply that we haven’t loaded the properties from the database.  We could change the properties to use nullable boolean’s (bool?  in c#), then the lazy load method could check that one of the properties was null before loading the data.  Alternatively, we could add a boolean field called isLoaded to the class and check that instead.

The problem with both of these solution though is that we would then have data-access concerns in our entity model.  This is not good SOC!  The solution we are going to use is to add the isLoaded flag at runtime!  We will not have to make any modifications to the Customer class defined above.  To do this, we need to add the following interface and implementation:

public interface ILazyLoad
{
    bool IsLoaded { get; }
}

public class LazyLoadImpl : ILazyLoad
{
    bool _isLoaded;
    public bool IsLoaded
    {
        get { return _isLoaded; }
    }
}

Now we need our Customer object to implement this interface, so when we create a new object we instead tell Castle to create us a proxy (as per previous post), but also add the ILazyLoad interface:

//Create a proxy object instead of a standard Customer object.
Castle.DynamicProxy.ProxyGenerator a = new Castle.DynamicProxy.ProxyGenerator();
//Create an instance of our Lazy Load Implementation and pass that to Castle.
ILazyLoad mixin = new LazyLoadImpl();
ProxyGenerationOptions pgo = new ProxyGenerationOptions();
pgo.AddMixinInstance(mixin);
Customer c = a.CreateClassProxy(typeof(Customer), pgo, new CustomerInterceptor());

Now our CustomerInterceptor can intercept calls to the ‘get’ properties of the Customer object, then cast the Customer instance to ILazyLoad and check the value of the IsLoaded property to see if the data needs to be loaded.  If it does, then the data is retrieved and the properties are set.  The _isLoaded field is then set to ‘true’ using reflection.  Next time we access a property, the interceptor will know that we’ve already loaded the data so won’t need to hit the database again.  We now have a Customer object that loads it’s data only when required.  (Please refer to the previous post to see how to setup the interceptors).

 

Note:  This example uses DynamicProxy v1.  I believe version 2 of DynamicProxy works in the same way, but having not personally used it I can’t guarantee this.

I ran into a problem with registering a client script resource this week which had me confused for a while.  I had an existing custom control which registered a script resource and worked as expected.  When I created a new custom control (in another assembly) derived from this control however, I kept getting a ‘‘Resource xyz.js could not be found’’.  The line in the base class that registered the script looked like:

ScriptManager.RegisterClientScriptReource(this.Page, this.GetType(), "xyz.js");

The reason this didn’t work when using the derived control was because the 2nd parameter is used by .NET to find the assembly containing the resource, so it (incorrectly) looked in the assembly containing the derived class instead!  The fix is simply to change the line above to explicitly specify the correct type instead:

ScriptManager.RegisterClientScriptResource(this.Page, typeof(MyBaseCustomControl), "xyz.js");

The resource will then be picked up from the correct assembly.

I have pretty much recovered from my broken hand now, and have (thankfully!) had the cast removed.  I have enough movement left to type again, so I’m now going to write up my next post.

Earlier this week I had to implement an auto-complete textbox (ala Google Suggest) in a web application.  As much as I wanted to use the newly-supported-by-MS jQuery framework, the application was already using the ASP.NET Ajax library, so I used the AutoCompleteExtender control from the AjaxToolkit.

However, the implementation took longer than expected, so I thought I’d better blog the problem so I don’t spend too long debugging it the next time it happens!

After five minutes later, I had the extender control wired into the page, and set it to call a PageMethod - which returned a hard-coded list of strings for testing.  However, when I ran the page I didn’t get any suggestions.  A quick check of the JavaScript console in FireFox didn’t report any errors, so I returned to the PageMethod to check that the required attributes ([WebMethod], and [ScriptService]) were present.  No problems there.  Hmm, load the page again, this time with the debugger attached to IIS and a break point in the page load.  Nothing - the callback to the PageMethod clearly wasn’t happening but no errors on the client.  Try again in IE.  Same problem.  Argh.

Right, back to basics, so I used the fantastic FireBug add-on to check what was being requested from the server, and there was the problem.  The request to the PageMethod was returning 500 - Server Error.  However, IIS was serving this error before any of my code was being executed.  I decided to create a simple project with the AutoCompleteExtender so that I could test in isolation.

ARGH!  It works in the test project!  It’s exactly the same!!  Then, it twigged, the ‘real’ application uses cookieless sessions.  Set that in the web.config of the test application.  Boom!  IIS returned Server Error.  Excellent.  PageMethods don’t work with SessionID’s in the Url.  Thanks. For. That.

By setting the Extender control to use a WebService instead of a PageMethod everything worked as expected.  Now to get the wasted 2 hours of my life back…

Earlier this week I had to implement an auto-complete textbox (ala Google Suggest) in a web application.  As much as I wanted to use the newly-supported-by-MS jQuery framework, the application was already using the ASP.NET Ajax library, so I used the AutoCompleteExtender control from the AjaxToolkit.

However, the implementation took longer than expected, so I thought I’d better blog the problem so I don’t spend too long debugging it the next time it happens!

After five minutes later, I had the extender control wired into the page, and set it to call a PageMethod - which returned a hard-coded list of strings for testing.  However, when I ran the page I didn’t get any suggestions.  A quick check of the JavaScript console in FireFox didn’t report any errors, so I returned to the PageMethod to check that the required attributes ([WebMethod], and [ScriptService]) were present.  No problems there.  Hmm, load the page again, this time with the debugger attached to IIS and a break point in the page load.  Nothing - the callback to the PageMethod clearly wasn’t happening but no errors on the client.  Try again in IE.  Same problem.  Argh.

Right, back to basics, so I used the fantastic FireBug add-on to check what was being requested from the server, and there was the problem.  The request to the PageMethod was returning 500 - Server Error.  However, IIS was serving this error before any of my code was being executed.  I decided to create a simple project with the AutoCompleteExtender so that I could test in isolation.

ARGH!  It works in the test project!  It’s exactly the same!!  Then, it twigged, the ‘real’ application uses cookieless sessions.  Set that in the web.config of the test application.  Boom!  IIS returned Server Error.  Excellent.  PageMethods don’t work with SessionID’s in the Url.  Thanks. For. That.

By setting the Extender control to use a WebService instead of a PageMethod everything worked as expected.  Now to get the wasted 2 hours of my life back…

Unfortunately I suffered two broken bones in my hand whilst playing football last week.  This means that my follow-on post about using mixin’s with DynamicProxy will have to wait for a few weeks as typing causes my hand to ache quite quickly!  Fortunately it’s only my left hand, so I can just about manage most tasks!  I should be out of plaster in 3-4 weeks from now - I hope anyway, as it is already driving me crazy!