ASP.NET Website #4: Jon Skeet Quotes

This is the fourth website of my project where I practise using elements of ASP.NET in order to exercise my frivolous ideas!

For this one, I wanted to do something involving data and after a brief discussion with a friend, I decided upon using XML at his suggestion. That proved to be a good interim measure before I embark on some DB examples, so thank you @byteblast!

As the name of this post suggests, this is all about Jon Skeet quotes. Well, they aren’t his quotes, really, but ones others have made up about him to match the esteem he is held in by the C# community. Before we begin though, let’s take a quick look at what we can expect to see with this project.

The Screenshot

When you are as good at design as I am….Alright, hands up, it doesn’t look like much, but there is so much going on underneath the surface. Maybe :-) In the image, you can see we have a title which you can click on and which will take you to the Stack Overflow page of Jon. Underneath is the actual quote with a (funny looking) bar on the left, and finally a button. You can see that the background is green, but that does change each time you run it.

How To Use It

Here come the shortest instructions ever.

  1. Click the button labelled “Next…”
  2. Go to 1.

That’s it really! This simply shows a different (randomish) quote each time you either visit the page or click “Next…“.

The Data - Where I Found It And How I Use It

I took all of the quotes from here and they can be attributed to a variety of users (please see the linked page for who). The process I took was to copy them out, clean up any typos, replace all special characters like “&” with & and remove any quotes which I felt were a little too cheeky or riskué! That left me with a list of quotes, one per line. The next step was to store them in an XML format. For this, I just used something simple with an outer tag of <quotes> followed by each individual quote wrapped in <quote>....</quote>.

1
2
3
4
5
<?xml version="1.0" encoding="utf-8" ?>
<quotes>
<quote>Google is Jon Skeet behind a proxy.</quote>
...
</quotes>

So, as you can see, the actual structure is quite simple and all-in, there were only about 90 quotes. Note the ellipses (…) are just how I have skipped the other 89 lines or so for illustration purposes.

Reading the XML File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System.Xml;

private XmlDocument _xmlDocument;
private XmlNodeList _xmlNodeList;
public const string QUOTE_PATH = "Data/jon-skeet-quotes.xml";

public QuoteEngine()
{
String path = HttpContext.Current.Server.MapPath(QUOTE_PATH);
try
{
_xmlDocument = new XmlDocument();
_xmlDocument.Load(path);
_xmlNodeList = _xmlDocument.GetElementsByTagName("quote");
}
catch (System.IO.FileNotFoundException e)
{
throw new QuoteEngineException("File not found at path: " + path + ". " + e.Message);
}
catch (Exception e)
{
throw new QuoteEngineException(e.Message);
}
}

The fields are all part of a class called QuoteEngine whose sole purpose is to deliver text-based quotes to a caller. In this extract, you can see that it effectively loads up the XML document and strips out the nodes which match quote. I created my own exception, QuoteEngineException, to wrap around the other exceptions that might be thrown. Line 9 is a little bit interesting. In the past, I have been able to refer to resources using paths like: “Data/file.img” but here, that doesn’t work. The trick is that you need to use the MapPath member function to help you find the root of where the resources are. On your machine, it will very likely have a different path to where you eventually host the application, so you need to do this whether this is running locally or hosted.

Selecting a Quote

This part is quite easy.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/// <summary>
/// Returns a randomly selected quote from the XML file as a string.
/// </summary>
/// <returns></returns>
public string GetRandomQuote()
{
if (_xmlNodeList == null)
{
throw new QuoteEngineException("XML Node List has not been initialised.");
}
if (_xmlNodeList.Count == 0)
{
throw new QuoteEngineException("XML Node List is empty.");
}
Random rnd = new Random();
return _xmlNodeList.Item(rnd.Next(_xmlNodeList.Count)).InnerText;
}

Simply put, I take a random number between 0 and the total number of quotes (-1) and select that element from the list of quote nodes, returning the text between the angle brackets. This is then placed into the label on the main page but I won't show that - it is quite straight forward. Oh...let's not forget the bar on the side.

## That Funny Looking Bar

That funny bar was inspired by a quote website that I found that looked really beautiful. And. I. Lost. The. Address. Rats! Sadly then, I can't link to it and show you, but, basically, the way I accomplished it was via CSS:

```css
.quote {
margin-left: auto;
margin-right: auto;
width: 40%;
font-size: x-large;
border-left-color: black;
border-left-width: thick;
border-left-style: solid;
margin-bottom: 50px;
}

The key part is of course the border-X-X parts. For some reason, though, I had a lot of trouble on Chrome trying to do that in one line (which should have been possible).

Changing The Background

Just because I like to add some jQuery in, I made the background colour of the page change with each iteration. The code to achieve that was:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$(document).ready(function () {
var colors = [
"#00FFFF",
"#CCFFFF",
"#CCFF66",
"#99FF00",
"#FFFF00",
"#FFFF99",
"#00FF00",
"#FF6666",
];
var rand = Math.floor(Math.random() * colors.length);
$("body").css("background-color", colors[rand]);
});

Looking at the code above, you can see that I created 8 optional backgrounds and then used a random number between 0 and 7 to select one. This is then used to alter the page bodies background-color.

What I Could Have Done Better

  • I think this could have looked a lot better. The website that I was inspired from to do this looked so much more professional. It’s not easy, this design lark :-)
  • I didn’t really have any NUNIT tests for this. It is a quite small amount of code, but I still feel a little guilty.
  • Instead of publishing all the final files to GitHub, I did it in dribs and drabs, which is what I ought to do. Except, I ran into some real problems when I accidentally deleted the assembly info file! Note to self: don’t ever do that again. That caused me so much pain, trying to get to a previous commit where it existed, and then bring it forward. I am sure much of my stress is down to needing to get better with the git command line, though.

What I Learnt From This

  • Make sure the cache is empty when using stylesheets/jquery files. How many times am I going to fall foul of this mistake?!
  • The assembly microsoft.msmxl must be referenced  and not system.xml for the XML methods and approach I used.
  • When referencing embedded files, use Server.MapPath to set up the root path to the resource.
  • I still find some CSS quite tricky. I suspect part of my issue is browser differences but nonetheless, I need to try and make it work!
  • The XML file had a build action of resource and copy always, but that didn’t seem to get included when publishing to a disk folder. A change to build action being set to content seemed to fix this. I need to look into this further to make sure it is as I describe.

You can find the source in the GitHub repository.


Hi! Did you find this useful or interesting? I have an email list coming soon, but in the meantime, if you ready anything you fancy chatting about, I would love to hear from you. You can contact me here or at stephen ‘at’ logicalmoon.com