Step by Step Guide to Building a Cross-Platform Application in HTML, CSS & Javascript

January 19, 2012 Leave a comment

Back in the days when your computers came in options of the cream, the white, the off-white, the ivory or the beige, it was very frustrating that an application you put so much effort into wasn’t usable on other computers.

You had to make a choice, and my choice was Windows.  It was just when Microsoft .Net came out and we figured it was a pretty good bet, which it was I reckon.

Then came the web…

A year or so later, despite many of our customers still being in dial-up, I moved to the web.  Unfortunately, this came with almost more headaches – Internet Explorer 6 was the king of browsers, but we had a few Netscapes and this rogue called Firefox was starting to make waves.

Over the last 10 years, while I moved completely away from desktop applications, the browser wars just got worse – even IE couldn’t get versions working nicely together (compatibility mode??? WTF?).

Finally, although IE is still not perfect, it is definitely better and more importantly – you can pretty much ignore it and code just for ‘standards compliant’ browsers – Firefox and Chrome predominantly. 

And then the iPhone came along.

…then came the iPhone…

Actually, the iPhone web browser is incredible – I’m more confident of my websites running on the iPhone than I am in Internet Explorer.  And on top of this, they have to cram your site into a tiny little screen.  I’m very impressed.

Of course, the iPhone really comes into itself with its applications (as opposed to websites).  Not only do they run beautifully, but the entire App Store infrastructure exposes a developer’s work to millions of ready and willing credit card holders, eager to part with a couple of dollars just for the pleasure of the App Store buying experience. 

Unfortunately, the iPhone also forced you to code in yet another language – Objective C – and I’m sorry, but I can barely keep up with .Net let alone learn another language built on C of all things.  I guess I wasn’t the only one to mourn this because there came a slew of WYSIWYGs and cross-platform compilers (Moonlight anybody?).  And to the top rose PhoneGap – an platform that essentially ‘wraps’ a web application in Objective C to convert it into a regular iOS application.  Note only that, it will also wrap it in the relevant languages to support Android, BlackBerry, Windows Phone, Symbian etc…  Such a simple concept, but just amazing.

…and the desktop comes full circle…

Windows 8 purportedly supports native HTML/Javascript/CSS applications. 

Woah – so suddenly, my old-school web-coding skills can be deployed on the web, major mobile devices and 90% of the world’s desktops?  Amazingly, yeah – I think they can.

The HTML/CSS/Javascript Application

So, sorry for the long pre-amble – I just need noobs to appreciate that this next decade of development shouldn’t be taken for granted.

The point is that now you can build an application in ONE language and deploy to multiple platforms.  However, it’s not quite as easy as that – there are many restrictions to what can be built and how.  In this article I’m going to walk you right through from start to finish.  I’ve built a few of these applications by now (the most recent is www.stringsof.me) so I’ll point out the pitfalls and hopefully save you a bit of time.

Know the Goal

I should point out that it is FAR easier to build an application with the knowledge of its intended use.  If it’s going to be used on iPhone or wrapped in PhoneGap, then you can test it incrementally on these platforms as you go.  Far far easier than trying to retro-fit an existing web application.  In fact, I recommend to anybody that no matter how big your web application is, you just start from scratch. Copy/paste what you need from the old one, but start with a clean slate – after all, this app will be used for years and years so you better make it a nice one.  So, here’s our goal:

HTML-Architecture-Overview

 

The Application

The application consists of three parts – an HTML file, one or more Javascript files and one or more CSS files. 

Below I’ve created a completely stripped-down application to try to indicate the core functionality, however if you want to see the full-blown thing in action, I suggest you View Source on m.stringsof.me

Index.html

<html>
<script src=“jquery.js" type="text/javascript"></script>
<script src=“phonegap.js" type="text/javascript"></script>
<script src=“settings.js" type="text/javascript"></script>
<script src=“app.js" type="text/javascript"></script>

<link href=“style.css" rel="stylesheet" type="text/css" />
<link href=“settings.css" rel="stylesheet" type="text/css" />
<body>
<div id=“MyContainer” >
    Hi everybody, welcome to my App.
</div>
<script>
    var app = new App(‘MyContainer’);
    app.Start();
</script>
</body>
</html>

Nothing particularly flash here, but of note:

  • We are using jQuery, but that is just my preference
  • The PhoneGap.js file is required for our various AppStore installations, but on the web server we replace with just a stub file
  • The Settings.js and Settings.css files enable us to manage the minor variations between our various platforms.  For example, iOS requires you to ask people before sending them push messages, Android doesn’t care, and push messages are irrelevant on a web-based app

      Settings.js

      The Settings file contains platform-specific variables.

      var Settings = function(){
          return {
              SiteRoot:'http://api.stringsof.me/’,
              ConfirmPushNotificationsOnStartup: false
          }
      }();

      Data.js

      Data provides connectivity to our server.  This class could be stored in the main App.js file, but I’ve split it out here because in a bigger application you’d have lots of Javascript files and you don’t want circular references if you can help it (not that Javascript minds, grrrrr).

      var Data = function () {
          var that = this;
          this.SiteRoot = Settings.SiteRoot;
          return {
              CallJSON : function(route, params, callback) {
                  var triggerName = new Date().getTime().toString();
                  $("body").bind(triggerName, function(e, result) {
                      callback(result);
                  }); 
      
                  // Add the JSON callback to the parameters
                  params._JsonPCb = 'Data.OnCallJSON‘;
                  params._JsonPContext = "'" + triggerName + "'";
      
                  // Make the JSON call
                  $.ajax({
                      url: that.SiteRoot + route,
                      data: params,
                      type: 'GET‘,
                      dataType:"jsonp“
                  });
              },
      
              OnCallJSON : function(result, triggerName) {
                  $("body").trigger(triggerName, result);
                  $("body").unbind(triggerName); }
          };
      } (); 

      App.js

      Encapsulates our main application code.  This file will usually get pretty big, but you can split it up later depending on your coding style.

      var App = function(containerID){
          this.ContainerID = containerID;
          var that = this;
          this.Start = function(){
              var $con = $(‘#’ + that.ContainerID);
      
              // Get user
              Data.CallJSON(‘Person/GetPerson’, {userName: ‘ben’}, function(person){
                  $con.html(‘Welcome ‘ + person.FirstName);
              });
      
          }
          return {
              Start: that.Start
          }
      };

    Pretty simple.  All it does is get the user by their username (I have hard-coded ‘ben’ in this example).  On the callback, you display their name in our main <div/> element.

    One flashy thing I’ve done is use my method for calling JSONP with callbacks.  You can read up on it here, or take my word for it that it works.

    Data Access

    Most of us are used to dealing with server-side languages such as ASP.Net or PHP.  Despite some efforts (MVC perhaps), these technologies still leave the HTML dependent, and to a certain extent aware, of the code that generated them.  For example, ASP.Net is heavily dependent on ViewState.  This may be fine for your web application – even your mobile web application – but it is worthless in your iPhone or Android app. 

    Without a server-side language to create and bind our HTML, we must defer to Javascript.  And to get the data required to bind, we must make some kind of web service call.  Because we are using Javascript, it makes sense to return JSON-formatted objects.

    Cross-Domain Data Access Using JSONP

    Using JSON would be all you had to do (and in fact frameworks like ASP.Net MVC have excellent JSON support baked in), except that we want to use the same web service (and therefore the same returned objects) in our iPhone/Android application.  Consider our mobile web application:

    Essentially therefore, our application is getting JSON objects from the same domain (m.stringsof.me) as where it resides.  Now consider our iPhone/Android application:

    • our web service (written in ASP.Net for example) is at http://m.stringsof.me/service
    • our application is stored on the phone – it doesn’t have a concept of ‘domain’

    It doesn’t have a domain, which means we are doing something called cross-site scripting.  Unfortunately, despite many many modern web applications using it (check out the source of the Google home page), all web browsers consider this a gross security risk and your Javascript will error if you try to do it.  Enter JSONP…

    JSONP (JSON with Padding) gets around this issue with a crafty little trick which I’ve covered in another article.  You need to know how JSONP works in order to build your mobile application, so I suggest you brush up.

    Returning JSONP from an ASP.Net MVC Application

    As an aside, if you are an ASP.Net MVC user, you can create your own JsonpResult:ActionResult to return from your Views:

        public class JsonPResult : JsonResult
        {
            public override void ExecuteResult(ControllerContext context)
            {
                var response = context.HttpContext.Response;
                var request = context.HttpContext.Request;
    
                // Open the JSONP javascript function
                var jsonpCallback = request.Params["_jsonpcb"];
                response.Write(jsonpCallback + "(");
    
                // Defer to base class for rendering the javascript object. Because we
                // have opened a javascript function first, it gets rendered as the first parameter
                base.ExecuteResult(context);
    
                // Add any additional parameters - this is not part of JSONP, but
                // a construct I've written to allow me to pass extra 'context' to the server and back
                var extraParams = request.Params["_jsonpcontext"];
                if (!string.IsNullOrEmpty(extraParams)) response.Write(extraParams);
    
                // Close the JSONP function
                response.Write(");");
            }
        }

     

    Using this, you can return JSONP directly from your regular MVC Controllers:

        public class PersonController : Controller
        {
            public ActionResult GetPerson(string username) {
                var person = new DataService().GetPerson(username);
                var result = new JsonPResult {Data = person};
                return result;
            }
        }

     

    Awesome huh?

    Rendering your Data

    Because I have returned JSON from the server, the next step is to render it to HTML.  Without going into too much detail, I personally use a couple of methods:

    • HTML templating.  I store HTML in a separate file (or hidden DIV in the Index.html page) and then bind sections of it using jQuery
    • use jQuery to create html such as $(‘body’).append($(‘<div></div>’).html(‘Hi there’));

    Why not just return HTML from the server?

    Good question, glad I thought of it.  Technically, there’s no reason why you shouldn’t.  In fact, if you did, you wouldn’t need to jump through all those cross-domain hoops with JSON etc.

    Frameworks like ASP.Net MVC actually encourage you to do this with their ‘View’ system and when I built the www version of stringsof.me (www.stringsof.me) I used these and they worked great. 

    When I moved to a mobile version of the application however, I found that this was a little short sighted.  What if I expose my objects to a third party who wants to use them in, for example, a Facebook plugin?  The HTML I return for ‘GetPerson()’ is not likely to suit their purposes so best to return the object and let them format it themselves.  Or what if the returned HTML expects Javascript to scroll it into place, but the requesting device doesn’t support Javascript?

    Although it is easier to specifically write your HTML (and even binding if you are using MVC), I eventually concluded that plain JSON objects are the most versatile mechanism.  By using Javascript as the rendering agent, you can make decisions based on the state of the client (such as width or support for location-based queries) which aren’t necessarily available to a server-rendered page.

    Media Queries

    Now that you are getting your data, the next step is adjusting the presentation between the various platforms.  For example, a full-blown website may have a big background image and the mobile version may remove this to account for low-bandwidth phones visiting it.  The fashionable way to do this these days is via CSS Media Queries.

    The basic premise is that your CSS reacts according to the type of media that is using the device.  For example:

    body{
        background-image:url(‘bg.jpg’);
    }
    @media screen and (max-device-width : 320px){
        body{
            background-image:none;
        }
    }

    The code above says:

    • for the body of the page, use a background image of bg.jpg
    • however, if the screen is smaller than 320px, do not show a background image

    The beauty of this is that it is platform independent – you don’t have to detect an iPhone or Android, you just have to know what its screen resolution is.  You can also switch out based on orientation (if the device is held upright or on it’s side):

    @media screen and (orientation: portrait){
        body{
            background-image:url('bg_narrow.jpg');
        }
    }
    @media screen and (orientation: landscape){
        body{
            background-image:url('bg_wide.jpg');
        }
    }

    Now, if the user turns their iPhone on its side, the background image will switch out to one that better suits its new dimensions.  Snazzy huh?

    Testing your Code

    Now that you have your HTML, Javascript and CSS working, you need to test it.  I have found that the best mechanism is Firefox using the Firebug plugin.  This will get you 99% of the way there, even for your iOS/Android applications later.

    You can test your media queries simply by resizing your browser window to the appropriate dimensions – getting a pretty decent idea of how your site will look on an iPhone compared to a full-size desktop browser.  Check it out by opening m.stringsof.me in a new browser window now and resizing.

    Deploying your Application as a Regular Website

    This is the easy one you’re probably used to – just create the website on IIS/Apache or whatever you are using and copy the HTML/Javascript/CSS files over.  The first time you deploy, remember to create Settings.css and Settings.js files and set them appropriately – they shouldn’t be in the main solution because they differ for other deployments.

    Remember you’ll also need to create an empty (or stubbed) PhoneGap.js file, as per the file reference in your Index.html file.  If you don’t, your site will still run but your visitors will get an unprofessional ‘404 Page Not Found’ error.

    Deploying your Application as a Mobile Website

    If you’ve used your CSS media queries correctly, your main website will double as your mobile website – no changes are required. 

    Deploying your Application as an iPhone and/or iPad App

    Ah, the part you’ve probably been waiting for all along. 

    • download www.phonegap.com and follow their instructions for creating a new project in xCode on your Mac (sorry, you need a Mac computer to build an iPhone app)
    • PhoneGap has comprehensive help files, so you are best off following them, but essentially the next step is to copy your HTML/Javascript/CSS files into the ‘www’ folder that PhoneGap provides.  Again create new Settings.js and Settings.css files accordingly.
    • note that PhoneGap also includes a PhoneGap.*.js file which contains the Javascript wrapper code to access the device hardware such as the camera.  Make sure the file is named exactly the same as that referenced in your Index.html file.

    Compiling and building your PhoneGap application is beyond the scope of this article sorry. 

    Beginner’s tips:

    • iOS is case-sensitive, so the <link/> and <script/> file references in your Index.html file must match the case of the files themselves.  If your CSS refers to images or folders, these are also case-sensitive. This took me about two hours to figure out – too much PC for me I guess.
    • I use DropBox to synchronize changes between my PhoneGap application and my website application.  Even though you are using the same HTML/Javascript/CSS files, they are copies of each other so a change in one must be copied to the other.  If you’re a PC user, you may also like to use File Backup Pro to quickly prepare and copy your changes to your server.

    Deploying your Application to Android (and other mobile devices)

    This uses PhoneGap again, and is the same as the iPhone installation above.  Again, the PhoneGap documentation does a much better job of explaining this than I can.

    Limitations

    The solution I have presented involves building a website predominantly in Javascript, and I have a few problems with this:

    • there is no compile-time checking.  I have colleagues that rave about Script#, but I don’t like the additional learning curve.
    • mainly because of point 1 above, it is hard to enforce architecture or development styles.  This makes working in a multi-developer team environment quite a bit tougher
    • search engines do not execute Javascript which means all they see on your web page is a little bit of HTML wrapper.  This means your website will not rank in Google, Yahoo etc.  You must therefore invest more in other SEO methods such as Site Maps and friendly URLs
    • JSONP can only be executed using GET requests, so if you need to upload a huge amount of data, such as an image, you are out of luck.  In m.stringsof.me, I had to deal with this when uploading the image that the user draws on the <canvas/> element.  I eventually solved it by breaking the base64-encoded representation of the image into 1000kb chunks and sending them to the server one after the other.  The server remembers what it gets and joins them together into a proper image at the end.  (This is why you see a percentage completion status when saving your work – each increment is a chunk of image).  You can View Source on the page to see how it was done, if you like.

    Summary

    Everybody likes a summary section so they know it’s the end of the article.  So, there you go.

    Using jQuery Binding to make cross-domain calls with Closure Callbacks

    December 18, 2011 1 comment

    It was hard to come up with a title to this post because I somehow needed to convey the awesomeness for a problem which I don’t think a lot of people realise they have.

    Quite simply, it is to do with the asynchronous manner in which we make JSONP calls (if you’re not sure how JSONP works, I recommend this simple article from Rick Strahl).  As you know (or will after reading the article), JSONP relies on dynamically injecting a <script/> tag into our document.  Within this tag are two parts of javascript:

    1. the object you are returning from the server (in JSON format)
    2. a function wrapper which ‘pads’ the object (the ‘P’ in JSONP).

    For example, if I wish to return Person object from the server, I would stream down:

    1. on the server, create the object in JSON (using Response.Write() for example in .Net):
     

    Person{FirstName : Larry, LastName : Phillips}

     

    2. wrap the object in a function name ‘mycallback’:

     

    mycallback({Person{FirstName : Larry, LastName : Phillips }})

     

    On the awaiting HTML page, I would have already written the following javascript function:

    function mycallback(person){

        alert(person.FirstName);

    }

     

    The script tag is injected into the page, the response is sent back, the browser automatically runs the Javascript within the script tag, the awaiting function is thereby called and voila – an alert() box is shown

    Problem: the callback is decoupled from the caller

    This looks tidy enough with one example, but when you have dozens or even hundreds of callbacks (such as I have on www.stringsof.me, which prompted this solution) it becomes very hard to manage because for every server call you need to write a separate corresponding callback.  It’s not shown in the example, but often the callback needs to tie back to the caller in some way to alter its state, which makes things even more complicated.

    This is extra frustrating because if you are working with jQuery (for example), you are dealing with nice ‘inline’ callbacks when using regular AJAX calls:

    $.ajax({

        url: that.SiteRoot + route,

        data: params,

        type: 'GET',

        dataType:"json",

        success:function(person){

            alert(person.FirstName);

        }

    });

     

    See?  The callback is written right within the AJAX call.  For programmers, it is tidy and easy to follow.  Unfortunately, if you specify the dataType property as ‘jsonp’, the callback doesn’t work.

    Unfortunately, we can’t do this with a cross-domain call….

    The reason the callback above doesn’t work for jsonp/cross-domain is (presumably) because it is not technically an AJAX call.  From Javascript’s point of view, it is just injecting a new DOM element into the page (the <script/> tag).  Once the tag’s src is downloaded, Javascript has already moved on to the next task.  It is the hack I described above which allows us to link the two.

    …until now!  Using jQuery’s bind and trigger

    Enter jQuery’s bind and trigger functionality.  Observe…if I write…

    $(‘body’).bind(‘foo’, function(){alert(“I’m called");});

     

    …and then at any time later, I write….

    $('body').trigger('foo');

     

    …the popup appears.  So I saw this, and I thought, perhaps I can fake a callback between the two JSONP events.  So, here goes…

     

     

    var Data = function () {

        var that = this;

        

        

        return {

            CallJSON : function(route, params, callback) {

                // The trigger name must be unique for each call, so that multiple (almost) concurrent AJAX

                // calls can be made and assigned back to the same trigger each time

                var triggerName = new Date().getTime().toString();

                params._JsonPCbTrigger = triggerName;

     

                // The traditional JSONP callback is provided, and points to the OnCallJSON function below

                // Note that because it is hard-coded (and therefore the same each time), it could equally be hard-coded on the server

                params._JsonPCb = 'Data.OnCallJSON';

                

                // Use jQuery to prepare for a trigger called triggerName                

                $("body").bind(triggerName, function(e, result) {

                    // Within the callback, we ignore the 'e' parameter (a jQuery artifact), and

                    // just pass the result straight through to the callback we passed into the main function

                    callback(result);  

                });

            

                // Make the JSON call as usual

                $.ajax({

                    url: 'http://www.stringsof.me/ + route,

                    data: params,

                    type: 'GET',

                    dataType:"json"

                });

            },

            

            // This is the generic handler for *all* JSONP calls.

            OnCallJSON : function(result, triggerName) {

                $("body").trigger(triggerName, result);

     

                // We unbind afterwards, simply to release memory

                $("body").unbind(triggerName);

            }

        };

    } ();

    Now, anywhere in my code, I can call (for example):

    var params = { personID: 1 };

    Data.CallJSON('GetPersonByID', params, function(person) {

        alert(person.FirstName);

    });

     

    The Server Code

    That actually concludes the article, but for completeness and in case readers are still a little confused over JSONP, I’ll include the server code that is required to make this work.  It’s in C#, but in essence it is simply writing regular Javascript to the response.

    // Get the variables from the Request that we have sent up from Javascript

    var callBackTrigger = context.Request.Params["_JsonPCbTrigger"];

    var callbackFunctionName = context.Request.Params["_JsonPCb"];

    var personID = int.Parse(context.Request.Params["personid"]);

     

     

    // Defer to service to get the requested person

    var person = new PersonManager().GetPerson(personID);

     

    // Encode to JSON format e.g. {FirstName:'Larry', LastName:'Phillips'}

    var personJSON = Newtonsoft.Json.JsonConvert.SerializeObject(person);

     

    // The callback function on the client receives TWO parameters - the result that

    // we want, and the name of the trigger that jQuery needs for the .trigger()

    var parameters = personJSON + ", " + callBackTrigger;

     

    // Finally, wrap the parameters in the function so that it is automatically

    // executed when the client renders it

    var functionCall = callbackFunctionName + "(" + parameters + ")";

     

    // Write to response

    context.Response.Write(functionCall);

    context.Response.End();

    Woody’s Bike Goodles

    November 8, 2011 Leave a comment

    My pal Woody has started a great new business importing bike parts into New Zealand. Not nerdy bikes, cool bikes. For a good time, follow here.

    Categories: General Rambling & Ranting Tags: ,

    Architecting Cascading Style Sheets (CSS)

    August 26, 2011 1 comment

    There is one big problem with CSS, and that is its lack of ‘structure’.  When you have a 20-page project, fine – dump everything in one file.  When you have hundreds of pages, across half a dozen different design agencies, things start to become very messy.

    And I hate mess.

    A client of mine is in this situation.  Over three years, they have had 6 different designers, each with different visual styles – but, more importantly for me – each with different CSS requirements and implementations.

    The impact of this has been bothering me ever since I began, but I’ve always had more ‘architectural’ problems to deal with.  However, I decided enough is enough when I realized our total CSS payload was 1Mb, and our biggest CSS file consisted of over 5,000 lines.

    Architecting CSS

    There are a few things I want from my CSS:

    • I’m mostly a C# developer these days, so I like the object-oriented thing – I get it, it’s tidy, it’s re-usable.
    • The ‘cascading’ part of CSS is wonderful, but it is a double-edged sword.  When some designer submits a stylesheet with a tag like “.main h2”, then it will inevitably affect portions of the site they weren’t even involved in.
    • Problems with CSS only manifest themselves when you actually view it – in other words, they are runtime errors.  And when you have hundreds of pages in the site, it is often the users that report a styling problem, not our testers.

    Close, but not close enough

    Unfortunately, I can’t claim to fix any of these problems. I admire the ambition of projects like .less (www.dotlesscss.org/) but something about these didn’t really feel right to me.  I guess its because there is no mainstream support (mainstream support is very important to me as we have a constant stream of new developers coming through – standards are my friend).

    I’ve also read a lot of people’s opinions on CSS – how we need to move away from semantics, how we need to move towards semantics, etc….but again, I need something that has plenty of community support on the internet, and that my new developers will be able to hit the ground running with.

    A brilliant compromise

    So, in the interim, while I search for the perfect solution, I’ve come with with a pretty-damn-good solution.  It consists of a single user control. You might call it WonderControl, but I call it simply CssContainer.ascx:

    ASCX

    <asp:PlaceHolder runat="server" ID="PHStyle" />

    Pretty simple huh?  One line.

    Code-behind

    public partial class CssContainer : BaseUserControl
        {
    
            [
            PersistenceMode(PersistenceMode.InnerProperty),
            TemplateContainer(typeof(CssContainer)),
            TemplateInstance(TemplateInstance.Single),
            ]
            public ITemplate Style { get; set; }
    
            /// <summary>
            /// Init
            /// </summary>
            /// <param name="e"></param>
            protected override void OnInit(EventArgs e)
            {
                // Instantiate any CSS in our template
                this.EnableViewState = false;
                base.OnInit(e);
                if (Style != null) Style.InstantiateIn(PHStyle);
            }
    
            /// <summary>
            /// Pre render
            /// </summary>
            /// <param name="e"></param>
            protected override void OnPreRender(EventArgs e)
            {
                base.OnPreRender(e);
    
                // If, for some reason, the control is called twice, we ignore
                if (!HasRegisteredOnThisRequest())
                {
                    this.Visible = true;
                    this.RegisterStyles();
                }
                else
                {
                    this.Visible = false;
                }
            }
    
            /// <summary>
            /// This control is designed to render styles only once per request - duplicate styles are a waste of resources
            /// </summary>
            /// <returns></returns>
            private bool HasRegisteredOnThisRequest()
            {
    
                // Has this control been rendered before?
                Control parent = this.Parent;
                while (true)
                {
                    if (parent == null) break;
                    if (parent.GetType().IsSubclassOf(typeof(BaseUserControl)) || parent.GetType().IsSubclassOf(typeof(PageBase)))
                    {
                        break;
                    }
                    parent = parent.Parent;
                }
                if (parent == null)
                {
                    // I'll throw an exception here, but really you could just render it anyway - it would just result in multiple renderings per page
                    throw new Exception("CssContainer may only be used on classes inheriting from BaseUserControl or PageBase");
                }
    
                // The count is kept in the PageBase so that we may retain it per-request, but share across all instances of this CssContainer control
                if (!this.Page.GetType().IsSubclassOf(typeof(PageBase)))
                {
                    // I'll throw an exception here, but really you could just render it anyway - it would just result in multiple renderings per page
                    throw new Exception("CssContainer may only be used on pages inheriting from PageBase");
                }
    
                // This control is probably specified multiple times on any one page. Here, we record that its' been done already or not
                if (pageBase.CssContainerCount.ContainsKey(parent.GetType())) return true;
                pageBase.CssContainerCount[parent.GetType()] = 1;
                return false;
            }
    
            /// <summary>
            /// Register the script contents, if any, to the page
            /// </summary>
            private void RegisterStyles()
            {
                // Pull template string OUT of the template we rendered in initially
                var sb = new StringBuilder();
                var tw = new StringWriter(sb);
                var writer = new HtmlTextWriter(tw);
                this.PHStyle.RenderControl(writer);
                writer.Close();
                tw.Close();
                var css = sb.ToString();
                if (string.IsNullOrWhiteSpace(css)) return;
    
                // User controls can be in multiple folder paths, so we must normalize any URLs
                css = css.Replace("~/", WebHelpers.GetFullUrlForPage(""));
    
                // Compress CSS etc
                css = Yahoo.Yui.Compressor.CssCompressor.Compress(css);
    
                // Render to page
                this.PHStyle.Visible = false;
                this.Controls.Add(new LiteralControl("<style type=\"text/css\">" + css + "</style>"));
            }
        }

    Okay, a little flasher, but really very simple.  I have tried to comment the code intuitively so you can follow it, but the general idea is:

    1. the user of the control specifies regular CSS in a template (called Style)
    2. we render that content into the PHStyle placeholder, just as you would a normal template
    3. we later get that CSS back out of the template, and render to the page between regular <style/> tags

    So, the end usage is something like this:

    <wc:Css runat="server">
    <Style>
    .column-con {
        overflow: hidden;
    }
    .column-con .column {
        background-color: #fff;
    }
    </Style>
    </wc:Css>

    The intention is that you drop this CSS directly into the page/usercontrol that is using it.

    Why this is bad…

    Yip, I understand what the problems are with this:

    1. It is inline, meaning page requests are bigger
    2. It can’t be cached on the browser
    3. It can only be re-used as far as the page or usercontrol it is sitting on

    But the answer to all of these is simple: if the pain of breaking these rules, for this set of styles, is too great, then just put them back in your regular external CSS style sheet.

    This control is not intended to replace your external sheets, but rather complement them.

    So, why it’s good…

    There’s only one reason: it’s tidy.  Where we have an obscure user control or page whose styles depart significantly from our usual styles, this is a brilliant way of isolating the styles without cluttering the main style sheet.

    And because it is rendered in code (as opposed to using direct <style/> tags), I know that I have a lot of control over what I might want to do with this in the future.  For example, I could:

    1. fake an external ‘file’ reference using a handler, thereby allowing the resulting request to be cached in the browser
    2. minimize the CSS (actually, I’m already doing this in the example above)
    3. perform replacements such as variable names – just like they do at www.dotlesscss.org/
    4. I can easily find the styles which apply to my HTML, by just browsing to the top of the UserControl – no more ‘Search Entire Project’ to track down a CSS source (update: Resharper 6 has a fairly good implementation of ‘Go To Definition’ for CSS)
    5. etc etc etc

    But until I know how to handle my styles, this solution allows me to contain and manage them far better than regular ‘client-side’ CSS files and embedded <style/> tags allow.

    What about re-usable external style sheets?

    Previously, where we had isolated CSS, we would create separate CSS files and then pull them into the request ‘on-demand’.  Technically, this worked just as well as my solution above – in fact, it was better in that the resulting file would be cached on the client browser and thereby improve overall visit speed.

    But this can result in dozens (or much more) of CSS files cluttering up your project, confusing your developers, slowing your project load time etc.  And besides, as I said above, I know that later, when I’m less busy, I’ll be able to create ‘external’ references using ASHX handlers.

    But embedded styles are terrible!

    In theory, yes – but in practice, definitely not.  One of the worst things a developer can do is get caught up in ‘best practice’.  As long as you understand the reasoning behind the rules, you’re able to break them when you find the reasoning doesn’t apply to your current project.

    Besides, go do a ‘view source’ on any of these home pages – you’ll see a lot of embedded styles:

    See? I’m in good company.

    Conclusion

    This is not the most technically-brilliant piece of work I’ve done, but I have to say it’s one of the most exciting.  I love being able to recklessly add styles exactly how I like with little regard for structure – content in the knowledge that future-Ben will be able to easily tidy it up one day.

    I strongly urge other developers to consider this type of structure for any medium-large projects they are undertaking.

    Installing Very Simple Database Inspector on 64-bit Computers

    August 4, 2011 3 comments

    The Very Simple Database Inspector itself is compatible with 64 bit machines, however the Microsoft Jet driver which we use to access our database is not.  The fix for this is quite simple however…

    • install VSDI as usual via the download at www.blackballsoftware.com
    • browse to the location on your computer where VSDI was installed.  The default is "C:\Program Files\Very Simple Database Inspector" or "C:\Program Files (x86)\Very Simple Database Inspector"
    • within that folder, you’ll see a sub-folder called "App"
    • download this file, unzip it, and copy its contents "dbinspector.exe" into the "App" folder – overwriting the existing file of the same name

    image

    Cheers,

    IOS fails AJAX POST using full URL of short domain name

    July 7, 2011 1 comment

    Well, here’s a weird one which I’ll try to share although I can’t seem to find a heading which Google will pick up to let others know I’ve solved their problem.

    I was building a MVC/JQuery app and had a form posting to the server as follows:

    var model = {

        AnswerText:'',

        QuestionID:60,

        QuestionDate:'2011-2-1'

    };

     

    $.ajax({

        url: siteRoot + 'Question/SaveAnswer',

        data: model,

        type:'POST',

        success: function(data){

            alert('success');

        }

    });

    The system worked fine on localhost, and fine on production using our old .com domain name.

    However, when we switched to a new domain name (www.stringsof.me), the system started failing, but only when browsed from the iPad – other browsers continued to work fine (although I admit I didn’t test it in Safari).

    The problem, as it turns out was the *siteRoot* variable which prefixes the AJAX URL.  Although you can’t see it in code, this variable is set to the domain name of the site (e.g. http://www.stringsof.me:80/).  When I changed siteRoot to just an empty string, it began working fine.

    Whew.

    How to apply for a job as a beer taster

    June 30, 2011 1 comment

    Here’s an application letter my brother wrote when he saw an advertisement requiring beer tasters.

    To whom it may concern

    To be honest, I shouldn’t even be doing this. I’ve been told that I’m too generous and that I put the needs of others before mine far too often. But upon reading your Trade Me ad and learning of your need for help I was moved by your candour and I feel compelled to extend my support.

    You’ve got some pretty stringent criteria on the ad and – if I may be so bold – I think you’ll struggle to find 999 superhumans who can meet those requirements. But, fortunately for you, and less so for my waistline, I am one such super person.

    My aptitude in opening, pouring and lifting beer to my open mouth is impressive, with a success rate of approximately 80%. In my early years I would get the order mixed up, and would end up getting beer all over the place – so silly! I remember my primary school teacher writing in a report that I had a problem with beer, but thanks to that feedback I learnt how to drink it properly. I think she was really proud, because she said “I give up” – so clearly she meant that I had achieved awesomeness and she could take me no further.

    I’m a bit confused with the next point as you have used a fancy word. But chances are I can do what’s needed as I’m, well, amazing…and I’ve got the notes from mum to prove it. Not sure what rudimentary means. I guess that’s pronounced rude-imentary…? Is that like a dirty documentary? If so…sign me up!

    Past beer achievements

    Like any good application I’ve included a selection of hard facts. The part where I tell you what I’ve achieved and you realise that I’m perfect for this role. Try these on for size:

    • Age 0: I was born with a big, round, pot belly just waiting to be filled with beer. Had a beer and slapped the doctor before he could slap me.
    • Age 4: Finished my morning beer and then started fight with the dog because he stood on the picture I was drawing. Then I hit on my friend’s hot mum.
    • Age 9: Drank a six pack, stole a bike, beat up a gang of 10-year-olds and then in class won a gold star for getting 4th place in the times tables test. BEST. DAY. EVER.
    • Age 15: Drank an entire keg. Ran with scissors, loitered under a “No Loitering” sign, swam within 30 minutes of eating.
    • Age 22: Poured a beer, added the usual nails and broken glass to it, drank that easily. Built a beer drinking robot whose sole purpose is to drink beer. Out-drank the robot and made it cry (even though it wasn’t even programmed to cry!). Then I saw the robot’s hot sister and made sweet bionic love aaalllllllll ad-break. Woke up next morning and realised it was just a dishwasher. Still counts though. Still counts.

    That’s just a selection of achievements. Some have described the list as awesome (1), others as super-neat (2); whereas I’m inclined to describe it as a normal Wednesday.

    So anyway, I’d love to help you help me help you.
    A little boy waits.
    Sam Liebert

    Appendix
    (1) January 2009. Bunch of kids I bought booze for in exchange for being allowed to use their rollerblades for 10 sweet minutes.
    (2) March 2010. That homeless guy that gave me some spare change

    How far would your business guy go to promote your stuff?

    Business guys don’t seem to be very popular with tech guys these days – http://quist.co/post/5004683561/why-engineers-distrust-business-people.  But after what he did this week, I know he is definitely the business guy for me.  While he doesn’t have a bunch of VCs on speed dial, he will make it up with blood, tears and sweat.

    So what did he do that got me to be so sure?  Well – he literally put his body on the line for our project.  Unlike other companies that acquire fans with money (e.g. “like our Facebook page to win an iPad”), James promised he would eat a clove of raw garlic for 10 new Facebook “likes”.  I thought he was just joking and won’t actually go through with it…until I saw this video – http://www.youtube.com/watch?v=6NHLLHPq8-Q

    Anyway, I am sure James is not the only business guy that has gone the extra mile to back up their tech co-founder.  Anyone else got a story to share?

    Comparing the performance of AppFabric against Sql Server

    May 19, 2011 4 comments

    I’ve been doing a lot of work lately implementing distributed caching systems for various clients. During my initial scoping, I found a lot of information out there comparing the performance between cache types (AppFabric, Memcached etc), however I could find very little comparing the performance of caching vs the actual database (in my case, AppFabric vs Sql Server 2005), just that it’s “much better”.

    Despite this lack of statistical information, I went ahead with caching anyway (after all, ‘much better’ sounds pretty good), and because I’m a Microsoft shop, I left it tidy by selecting AppFabric to ease the load on Sql Server.

    Now that I’ve implemented the code to a decent extent through a particular website, I’ve been able to conduct my own performance benchmarks and here I’d like to share the results.

    Note in particular that these are what I would call real-world results. I didn’t attempt to isolate cache access based on particular SQL queries or size of the item. I didn’t reset the cache between web pages. I simply used the website in the same way I’d expect my users to, and recorded the overall times.

    Methodology

    My methodology was fairly simple and certainly prone to a margin of error:

      • installed a ASP.Net website to a development machine which I knew I had sole access to. Sql Server is installed on the same box as the web server, however I had a separate (and dedicated) server containg the cache.
      • switch the cache off (via AppSettings configuration)
      • browse through a set number of web pages, without refreshing the client browser or anything tricky
      • made a note of the pages I travelled through, then turned the cache on and went through the same pages again

    I had simple code around my ‘cache access’ block which simply counted the number of milliseconds the application spent trying to Save/Load the items (or bypassing if the cache was off) and logged them to a text file.

    Results

    Data access is split into two parts – Save and Load. Note that Sql Server does not have the burden of a Save method, and AppFabric of course only calls Save the first time the item is accessed.

    AppFabric Sql Server Ratio
    Load 81,960ms 372,318ms 22%
    Save 2,265ms NA NA
    Total 84,225ms 372,318ms 22%

    Interesting results:

        • AppFabric increases my data-access speeds by almost 5x over Sql Server. Thank goodness for that, and of course the longer you cache an item, the greater this efficiency will get. Again, this is not saying that AppFabric accesses data 5x faster than Sql Server on a call-by-call basis, it is the overall time benefit of implementing caching
        • AppFabric has an additional overhead in saving a newly calculated item back to the cache. In my case it was 2,265ms for the 81,960ms I spent loading items – a ratio of about 1/36. The longer I ran the test (or cached the items before they expired), the better this ratio would have become

    To conclude

    AppFabric clearly has performance gains over Sql Server – in my limited test it made my data access 5x faster, and a longer test expiry period would have made this much much greater.

    Note also that the website I was using had (test) database tables less than ~1,000,000 records, although some fairly funky SQL queries are being made here and there. For an even larger database such as Facebook (or my client’s database, hopefully) the SQL queries would take longer, but (I suspect) the caching times would remain exactly the same – another point in favour of AppFabric.

    Uh-oh…one more thing (and it sucks)

    Now that you’ve read this far, I’ll tell you the real reason I ran these tests, which is that I was convinced that AppFabric actually made my site slower. Not because SQL was better, but because the previous caching system I switched out was in fact the good old ASP.Net HttpCache utility. Like AppFabric, this cache is entirely in-memory but because it doesn’t concern itself with regions, tags, (and much more), it actually runs much much much faster. Let me type that again so Google picks it up – AppFabric is not nearly as fast as the built-in ASP.Net HttpCache utility. I ran the same test as above, but using the HttpCache:

    AppFabric Sql Server HttpCache
    Load 81,960ms 372,318ms 38,866ms
    Save 2,265ms NA 9ms
    Total 84,225ms 372,318ms 39,875ms

    Yes, that’s right – AppFabric is 2.1x slower than the built-in ASP.Net caching utility. Very sad, especially when I see my site slow down after all my hard work. However, I’m sticking with AppFabric:

        • HttpCache resets whenever the IIS App Pool resets, when you redeploy and any other time it feels like it. I suspect if I ran this test over a long time (say, a week) then the results would be closer
        • There is no tagging in HttpCache – you have to roll your own by integrating into the key – and the subsequent parsing to ‘find by tag’ is slow
        • HttpCache cannot be expanded easily to hold gigabytes of data – it simply won’t work when my sites expand
        • The distributed nature of AppFabric allowed me to build a separate ‘admin’ tool where I can look into the cache from another website, count it, clear it etc
        • And if I’m honest, the final reason is that this type of caching is all in vogue at the moment and it’s something I feel I should be part of

    One thing I’m wondering about is actually using a combination of both – extremely high-access queries (like user permissions) could be HttpCache, leaving AppFabric to handle the larger datasets. Bit of an art form I reckon.

    Gather quick and informative feedback about your website using our new off-screen widget

    Many people own websites and some of them gather quantitive like page hits or the length of time people stay on the site.  But very few people are gathering qualitative data about how their site is being used.  Rate-It’s new off-screen widget is perfect for these people – it is a free and easy way to gather user feedback from any page on your site.

    How it works

    Our new off-screen widget provides all the power of our other widgets but sits subtly off to the side of the page.  Users simply click the tab on the right hand side to reveal the widget:

     

    image

     

    image

     

    This is totally free

    As usual, the Rate-It widget is totally free, so there’s no harm in seeing if its right for your site.

    Categories: Rate-It
    Follow

    Get every new post delivered to your Inbox.