Monday 14 January 2013

Twitter.Bootstrap.MVC4 meet Bootstrap Datepicker *and* get your Internationalization on...

Last time I wrote about marrying up Twitter.Bootstrap.MVC4 and Bootstrap Datepicker. It came together quite nicely but when I took a more in depth look at what I'd done I discovered a problem. The brief work on regionalisation / internationalisation / localisation / globalisation / whatever it's called this week... wasn't really working. We had problems with the validation.

I also discovered that Stefan Petre's Bootstrap Datepicker appears to have been abandoned. Andrew Rowls has taken it on and created a GitHub repository for it here. Besides bug fixes he's also introduced the ability for the Bootstrap Datepicker to customised for different cultures.

Since these 2 subjects are linked I tackled them together and thought it might be worth writing up here. You can find the conclusion of my work in a GitHub repository I created here.

Going global down in Acapulco

First step in internationalising any ASP.Net web app is adding the following to the web.config:

Then I pulled Globalize and the Andrew Rowls fork of Bootstrap Datepicker into the project (replacing Stefan's original assets). As well as this I pulled in the jQuery.validate.globalize.js extension I wrote about here. (This replaces some of the default jQuery Validate functionality for culture-specific functionality based on Globalize.) This extension depends on a meta tag that is generated using the following file (which also handles the serving up of the relevant JavaScript culture bundles, more of which shortly):

Culture-specific script bundles

With all of my dependancies in place I was now ready to press on. Since both Globalize and the new Bootstrap Datepicker come with their own culture-specific JavaScript files it seemed a good idea to make use of ASP.Nets new bundling functionality. This I did here:

The code above creates a script bundle for each culture when the application starts up. This script bundle contains the culture-specific Globalize and Bootstrap Datepicker JavaScript files. If further culture-specific components were added to the application it would make sense to include these here as well.

_BootstrapLayout.basic.cshtml has been amended to make use of the new bundles and also to include a meta tag that will used to drive regionalisation:

To illustrate how this works, a German user running a machine with the de-DE culture would be served up the following 2 files:

  • globalize.culture.de-DE.js
  • bootstrap-datepicker.de.js

Where have we got to?

With all this done we have now fixed the validation issues we were experiencing previously. This was done by including the Globalize library, the accept-language meta tag and the jQuery Validate Globalize extensions.

Besides this we've laid the groundwork for introducing internationalised datepickers by introducing Andrew Rowls fork of the Bootstrap Datepicker. That's what we'll do next...

International Bootstrap Datepicker

The final steps of switching over to using a culture-specific date picker are achieved by making a change to the Scripts section in the Create.cshtml file. The existing (and very simple) section should be replaced with this:

The script above takes the region from the accept-language meta tag and attempts to look up an associated "language" for the Bootstrap Datepicker. If it finds one it uses it, if not then the default language of "en" / English will be used.

Summary

In this post we:

  1. fixed the validation issues we'd introduced by marrying up Twitter.Bootstrap.MVC4 and the Bootstrap Datepicker
  2. switched over to using the Andrew Rowls fork of Bootstrap Datepicker and made use of the internationalisation functionality it exposes.

Wednesday 9 January 2013

Twitter.Bootstrap.MVC4 meet Bootstrap Datepicker

Update 14/01/2013

Since I wrote this I've taken things on a little further - to read about that go here.

Getting Responsive

It's the new year, it's time for new things. Long on my list of "things to do" was getting up to speed with Responsive web design. No doubt like everyone else I've been hearing more and more about this over the last year (by the way there was a good article on Mashable about this last month). RWD (in case you don't already know) is pretty much about having web interfaces that format their presentation based on the device they're running to provide a good user experience. (I kind of think of it as a write once, run anywhere approach - though hopefully without the negative connotations...)

Rather than diving straight in myself I'd heard at a user group that it might be worth taking Twitter Bootstrap as a baseline. I'm a lazy busy fellow so this sounded ideal.

I like ASP.Net MVC...

... and this flavoured my investigations. I quickly stumbled on an article written by Eric Hexter. Eric had brought together Twitter Bootstrap and ASP.Net MVC 4 in a NuGet package. Excellent work chap!

To get up and running with Eric's work was a straightforward proposition. I...

  1. Created new MVC 4 application in Visual Studio called “BootstrapMvcSample” using the “Empty” Project Template.
  2. Executed the following commands at the NuGet Package Manager Console:
    • Install-Package twitter.bootstrap.mvc4
    • Install-Package twitter.bootstrap.mvc4.sample

Check out the responsive goodness I had when I ran it:


It's big, big, big....

and it's titchy, tiny small!

This is just 1 page, with @media queries doing the heavy lifting.

Bootstrap Datepicker

The eagle-eyed amongst you will have noticed that the edit screen above features a date field. I've long been a fan of datepickers to allow users to enter a date in an application in an intuitive fashion. Until native browser datepickers become the norm we'll be relying on some kind of component. Up until now my datepicker of choice has been the jQuery UI one. Based on a quick Google it seemed that jQuery UI and Twitter Bootstrap were not necessarily natural bedfellows. (Though Addy Osmani's jQuery UI Bootstrap shows some promise...)

Since I feared ending up down a blind alley I found myself casting around for a Twitter Bootstrap datepicker. I quickly happened upon Stefan Petre's Bootstrap Datepicker which looked just the ticket.

Shake hands and play nice...

Incorporating the Bootstrap Datepicker into Twitter.Bootstrap.MVC4 was actually a pretty straightforward affair. I added the following datepicker assets to the ASP.Net MVC project as follows:

  • bootstrap-datepicker.js was added to ~\Scripts.
  • datepicker.css was added to ~\Content. I renamed this file to bootstrap-datepicker.css to stay in line with the other css files.

Once this was done I amended the BootstrapBundleConfig.cs bundles to include these assets. Once this was done the bundle file looked like this:

I then created this folder:~\Views\Shared\EditorTemplates. To this folder I added the following Date.cshtml Partial to hold the datepicker EditorTemplate: (Having this in place meant that properties with the [DataType(DataType.Date)] attribute would automatically use this EditorTemplate when rendering an editor - I understand [UIHint] attributes can be used to the same end.)

And finally I amended the Create.cshtml View (which perhaps more accurately might be called the Edit View?) to include a bit of JavaScript at the bottom to initialise any datepickers on the screen.

Et voilà - it works!


A thing of beauty is a joy forever...

My thanks to Eric Hexter and Stefan Petre for doing all the hard work!

Still to do

I haven't really tested how this all fits together (if at all) with browsers running a non-English culture. There may still be a little tinkering require to get that working...

Thursday 3 January 2013

HTML to PDF using a WCF Service

TL; DR - "Talk is cheap. Show me the code."

Some time ago I wrote a post which demonstrated how you could make PDFs from HTML using C# and wkhtmltopdf. To my lasting surprise this has been the most popular post I've written. I recently put together an ASP.NET WCF service which exposed this functionality which I thought might be worth sharing. The code can be found on GitHub here.

A little more detail

I should say up front that I'm still a little ambivalent about how sensible an idea this is. Behind the scenes this WCF service is remotely firing up wkhtmltopdf using System.Diagnostics.Process. I feel a little wary about recommending this as a solution for a variety of not particularly defined reasons. However, I have to say I've found this pretty stable and reliable. Bottom line it seems to work and work consistently. But I though I should include a caveat emptor; there is probably a better approach than this available. Anyway...

There isn't actually a great deal to say about this WCF service. It should (hopefully) just do what it says on the tin. Putting it together didn't involve a great deal of work; essentially it takes the code from the initial blog post and just wraps it in a WCF service called PdfMaker. The service exposes 2 methods:

  1. GetPdf - given a supplied URL this method creates a PDF and then returns it as a Stream to the client
  2. GetPdfUrl - given a supplied URL this method creates a PDF and then returns the location of it to the client

Both of these methods also set a Location header in the response indicating the location of the created PDF.

That which binds us

The service uses webHttpBinding. This is commonly employed when people want to expose a RESTful WCF service. The reason I've used this binding is I wanted a simple "in" when calling the service. I wanted to be able to call the service via AJAX as well as directly by browsing to the service and supplying a URL-encoded URL like this:

http://localhost:59002/PdfMaker.svc/GetPdf?url=http%3A%2F%2Fnews.ycombinator.com/

You may wonder why I'm using http://news.ycombinator.com for the example above. I chose this as Hacker News is a very simple site; very few resources and a small page size. This means the service has less work to do when creating the PDF; it's a quick demo.

I should say that this service is arguably *not* completely RESTful as each GET operation behind the scenes attempts to create a new PDF (arguably a side-effect). These should probably be POST operations as they create a new resource each time they're hit. However, if they were I wouldn't be able to just enter a URL into a browser for testing and that's really useful. So tough, I shake my fist at the devotees of pure REST on this occasion. (If I should be attacked in the street shortly after this blog is posted then the police should be advised this is good line of inquiry...)

Good behaviour

It's worth noting that automaticFormatSelectionEnabled set to true on the behaviour so that content negotiation is enabled. Obviously for the GetPdf action this is rather meaningless as it's a stream that's passed back. However, for the GetPdfUrl action the returned string can either be JSON or XML. The Fiddler screenshots below demonstrate this in action:


JSON

XML

Test Harness

As a final touch I added in a test harness in the form of Demo.aspx. If you browse to it you'll see a screen a little like this:

It's fairly self-explanatory as you can see. And here's an example of the output generated when pointing at Hacker News:

And that's it. If there was a need this service could be easily extended to leverage the various options that wkhtmltopdf makes available. Hope people find it useful.