ASP.NET MVC Framework Preview – A review

I’ve just finished reading Steven Sanderson’s book ASP.NET MVC Framework Preview published by APress. While the book was short I felt it did give me a bit of an introduction to ASP.NET MVC. Although I have to admit that I could have probably got that from reading a number of articles.

The book is split in to a number of areas that could be summarised as Why? How? and Where? The Why? (chapter 1) describes why you would want to use ASP.NET MVC over traditional ASP.NET*. The How? (chapter 2) describes how you would create a web application with ASP.NET MVC and the Where? (chapter 3) describes the other architecture that ASP.NET MVC fits in with. Then, finally, there is an appendix that describes some of the new language features of C# 3.0 and I felt that this was added just to try and bulk the book out a little bit.

I have to admit that when I first opened the package containing the book I was a little disappointed by the size. When I opened the book I was more disappointed when I saw that, conversely, the font size was larger than I was expecting too.

If you already have an idea that you want to use ASP.NET MVC and why then chapter 1 can easily be skipped. If you are already familiar with n-tier development, ORM, IoC, unit testing and so on then chapter 3 can be skimmed quite quickly. That leaves the real meat of the book just in the 30 pages that is chapter 2.

Despite all the negative things that I have said up to this point, I rather like Steven’s writing style. It is clear and and easy to follow. There are a fair number of footnotes for clarification or to point you off in the direction of more information that is outside the scope of the book. He’s given enough information that a person could confidently make a stab at creating a starter application using ASP.NET MVC without too much trouble.

In short, I’m looking forward to Steven Sanderson’s 500 page and hopefully much more in depth Pro ASP.NET MVC book coming out in January 2009.

* I think this is where terminology is going to get slightly confusing. We already talk about “Classic ASP” when referring to ASP as it was before .NET came along. Now we have “Traditional ASP.NET” to refer to ASP.NET before MVC. Of course, traditional ASP.NET isn’t going away, just as the traditional songs I was taught at school haven’t gone away just because a bunch of rock-stars have come along and created new songs. (I was going to say pop-stars, then I realised they don’t tend to write their own songs these days)

Some advice on CVs

As a lead developer part of my job is to review CVs for developers that we are potentially going to hire. There are, however, some people that I think do put the most inappropriate things on their CV. I’m not talking about the really obviously inappropriate stuff like admitting you won some competition in an Ibiza nightclub on an 18-30 holiday, I’ve not seen anything a salacious as that. I’m talking about the inappropriate things that sound like they should probably be on a CV.

There have been various reports in the media recently about identity theft and CVs. And yet, I still get emails from people with all sorts of personal information in them. I imagine that recruitment agents get even more than I do. But, if you are sending off your CV can you really be sure that you are sending it to a legitimate source?

There is nothing stopping an identity thief setting themselves up as a fake company and posting job adverts. With a website and a number of job adverts posted around an identity thief could receive hundreds of CVs all containing some very personal information.

Recently I’ve received CVs containing details such as Date of Birth, Address, various government Identifiers (National Insurance numbers, driving license, SSN, Passport numbers, etc.), marital status and so on. Enough for someone to steal the candidate’s identity.

In the UK we have various bits of legislation that mean we are not permitted to discriminate on grounds of age, gender, martial status, race, etc. There is therefore no need to put any of that information on your CV. In fact, some hiring managers might dismiss your CV immediately if it includes information like that because they don’t want to be seen to discriminate in that area.

So what sort of information should you put on the CV?

First, this is obviously just my opinion and some of it is limited to software development roles.

I’m interested in your experience, if you have less than 5 years experience as a developer telling me about any formal education is also useful. After 5 years just some one-liners about your formal education will be sufficient. If you did a computing/computer science/software engineering degree then give some information about your final year project (and the vast majority of university course do) then give some information about that. Obviously, if your final year project was a bit vacuous then you might want to hide it.

Any recent training is also useful, and I do mean recent. If it is older than about 36 months then leave it out. Also, it needs to be relevant. Telling me about the evening classes you took in pottery last year may be interesting to you, but it has nothing to do with software development so leave it out, or move it to your hobbies section.

If you have won any worthwhile awards or if you do volunteer work put that in too. If you have given any presentations at conferences or user groups, written any articles, maintain a blog or personal website then put these things in. If you run a web site that is less than employer friendly then make sure you do that under a pseudonym that can’t be tracked back to you, it might hurt your chances, remember that includes your WHOIS entry.

External hobbies and interests can be useful on a CV, and other people think they are a waste of space. I like to see what other things you are interested in, but I’m not going to be too fussed if you don’t include it.

Finally, make sure that you actually include contact information. Just your name, email and phone number is good enough at this stage.

New article on Code Project: Data Visualisation with Virtual Earth ASP.NET Controls

It has taken a while, but I finally got around to putting another article up on Code Project. The article is based on a series of blog posts (Finding things with Virtual Earth, Using PushPins with the Virtual Earth ASP.NET control, and Drawing lines on the map with the Virtual Earth ASP.NET control) that I wrote on the subject on ASP.NET Controls for Virtual Earth. However, it is updated and includes extra information on Polygons that wasn’t in my original blog post series.

You can find the article here: Data Visualisation with Virtual Earth ASP.NET Controls

So few posts…

It occured to me today as I was driving up the road from the Black Marble event on Software Architecture that the number of posts on my blog has gone down recently. I was thinking about what happened. When I looked over the recent posts I discovered that I’m putting fewer community posts on my blog as I’m putting them up on the Scottish Developers site instead.

So, if you are looking for all the community stuff I used to post then please visit the Scottish Developers website as I’m posting it there instead. However, if it isn’t relevant to Scotland I’ll probably still post it here instead.

The Scottish Developers website also contains details of any developer events in Scotland that I’m told about.

Formatting dates the hard way

I was doing a bit of a code review and I spotted this in the code base.

string[] splitOptions = new string[1] { dayEarlier.Date.Year.ToString() };
string[] earlyDates = dayEarlier.Date.GetDateTimeFormats();
string[] earlySplit = earlyDates[67].Split(splitOptions,
    StringSplitOptions.RemoveEmptyEntries);
earlySplit[0] = earlySplit[0].Replace(",", string.Empty);

Essentially the code gets the date in a specific format. However, it does it in the oddest most convoluted way I’ve ever seen.  Just to explain, here is the code again but this time I’ve added some comments:

// dayEarlier is a business object with a property called Date that returns a DateTime.
// splitOptions will contain the year in an 1-element string array.
string[] splitOptions = new string[1] { dayEarlier.Date.Year.ToString() };

// earlyDates will contain the dayEarlier Date in umpteen different formats.
string[] earlyDates = dayEarlier.Date.GetDateTimeFormats();

// earlySplit will contain the 68th (!) formatted date (out of 89 that get generated).
// Element 0 in this array will contain the bit upto the year, element 1 will contain
// the bit after the year. The year itself is discarded.
string[] earlySplit = earlyDates[67].Split(splitOptions,
    StringSplitOptions.RemoveEmptyEntries);

// The first element (element 0) of earlySplit is then modified to remove the comma.
earlySplit[0] = earlySplit[0].Replace(",", string.Empty);

In short, what is actually being looked for is the day name, day of the month and the month. That’s it. And that, apparently, isn’t even in the 89 permutations of the date that .NET generated in the second line of code. To add to the potential problems with this, I’ve not seen any documentation that states that the permutations given by this method will stay the same.

All this code could easily be re-written simply as:

dayEarlier.Date.ToString("ddd dd MMM");

And the bonus here is that we are not generating 88 completely useless permutations, nor are we generating the permutation that is simply the closest match that we still have to futz around with. We are generating the date in exactly the format that we want. (Current culture permitting)

Throwing exceptions

When reviewing some code today I noticed some code that catches an exception, does something with it and then explicitly throws it again. The code looked something like this:

try
{
    // Do something that might cause an exception
}
catch (Exception ex)
{
    // Some stuff
    throw ex;
}

The problem with the above code is that when you throw the exception again the details about where the exception originated from are lost because the throw populates that part of the exception object. So the original details are replaced with the details about the current location in the code.

Consider the following program:

static void Main(string[] args)
{
    try
    {
        A();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        Console.WriteLine(ex.StackTrace);
    }
    Console.ReadLine();
}

private static void A()
{
    B();
}

private static void B()
{
    try
    {
        C();
    }
    catch (Exception ex)
    {
        // I can do something
        Console.WriteLine("Method C() catches the exception and partly handles it");
        Console.WriteLine();
        throw ex;
    }
}

private static void C()
{
    D();
}

private static void D()
{
    Exception ex = new Exception("This exception is thrown in D");
    throw ex;
}

The original exception is thrown by method D. The code in method B catches the exception and partly handles it, it then explicitly throws the original exception again. When the exception is finally caught in the Main method the call stack is truncated to method B. It can no longer see that method C and D were also called.

The output of the application is:

Method C() catches the exception and partly handles it

This exception is thrown in D
   at ConsoleApplication1.Program.B() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 40
   at ConsoleApplication1.Program.A() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 26
   at ConsoleApplication1.Program.Main(String[] args) in d:DevelopmentConsoleA
pplication1ConsoleApplication1Program.cs:line 14

As you can see, the stack trace only goes from the point of the second throw to the point that the exception is caught.

There are two correct solutions to this problem.

Solution 1: Wrapping the Exception

If you have additional information to add to the exception object you can create a brand new Exception and then put the original exception in as an inner exception like this:

try
{
    // Do something that might cause an exception
}
catch(Exception ex)
{
    // Some stuff
    Exception moreDetailedEx = new Exception("A message with more details", ex);
    throw moreDetailedEx;
}

NOTE: Please use a specific exception class and not Exception this makes catching specific types of exception easier and more efficient as the compiler can put in place some optimisations for you over you catching the base Exception class and examining it. I’m using Exception here simply to make the example easier to read.

So, if we change our program above to create a new exception and wrap the old one in it it will now look like this:

static void Main(string[] args)
{
    try
    {
        A();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.InnerException.Message);
        Console.WriteLine(ex.InnerException.StackTrace);
        Console.WriteLine();
        Console.WriteLine(ex.Message);
        Console.WriteLine(ex.StackTrace);
    }
    Console.ReadLine();
}

private static void A()
{
    B();
}

private static void B()
{
    try
    {
        C();
    }
    catch (Exception ex)
    {
        // I can do something
        Console.WriteLine("Method C() catches the exception and partly handles it");
        Console.WriteLine();
        Exception newEx = new Exception("This exception is thrown in B", ex);
        throw newEx;
    }
}

private static void C()
{
    D();
}

private static void D()
{
    Exception ex = new Exception("This exception is thrown in D");
    throw ex;
}

I’ve added some extra bits to the Main method to show the InnerException details too. The output of the program now looks like this:

Method C() catches the exception and partly handles it

This exception is thrown in D
   at ConsoleApplication1.Program.D() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 56
   at ConsoleApplication1.Program.C() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 50
   at ConsoleApplication1.Program.B() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 36

This exception is thrown in B
   at ConsoleApplication1.Program.B() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 44
   at ConsoleApplication1.Program.A() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 29
   at ConsoleApplication1.Program.Main(String[] args) in d:DevelopmentConsoleA
pplication1ConsoleApplication1Program.cs:line 14

As you can now see all the information is available. It can now be seen the patch from the final point the exception was caught to the point it was originally thrown.

Solution 2: Re-throwing the Exception

If you do not have any additional information to add to the exception you can simply use the throw keyword on its own and it will keep the existing exception object without altering it. For example:

try
{
    // Do something that might cause an exception
}
catch (Exception ex)
{
    // Some stuff
    throw;
}

Changing our program above to use the throw statement on its own will mean the program now looks like this:

static void Main(string[] args)
{
    try
    {
        A();
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        Console.WriteLine(ex.StackTrace);
    }
    Console.ReadLine();
}

private static void A()
{
    B();
}

private static void B()
{
    try
    {
        C();
    }
    catch (Exception ex)
    {
        // I can do something
        Console.WriteLine("Method C() catches the exception and partly handles it");
        Console.WriteLine();
        throw;
    }
}

private static void C()
{
    D();
}

private static void D()
{
    Exception ex = new Exception("This exception is thrown in D");
    throw ex;
}

And the output now looks like this:

Method C() catches the exception and partly handles it

This exception is thrown in D
   at ConsoleApplication1.Program.D() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 52
   at ConsoleApplication1.Program.C() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 46
   at ConsoleApplication1.Program.B() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 40
   at ConsoleApplication1.Program.A() in d:DevelopmentConsoleApplication1Cons
oleApplication1Program.cs:line 26
   at ConsoleApplication1.Program.Main(String[] args) in d:DevelopmentConsoleA
pplication1ConsoleApplication1Program.cs:line 14

As you can see the stack trace now shows you the entire route between the point the exception was caught and when it was thrown. We can also see from the message that the method C still caught and partly handled the exception.

Using the throw keyword like this actually translates to the CIL (MSIL) rethrow command. When you use throw with an Exception object it translates to the CIL throw command.

When the exception is thrown in D the CIL looks like this:

.method private hidebysig static void D() cil managed
{
    .maxstack 2
    .locals init (
        [0] class [mscorlib]System.Exception ex)
    L_0000: nop
    L_0001: ldstr "This exception is thrown in D"
    L_0006: newobj instance void [mscorlib]System.Exception::.ctor(string)
    L_000b: stloc.0
    L_000c: ldloc.0
    L_000d: throw
}

The key above is L_000d where it throws the exception.

Compare that to method B:

.method private hidebysig static void B() cil managed
{
    .maxstack 1
    .locals init (
        [0] class [mscorlib]System.Exception ex)
    L_0000: nop
    L_0001: nop
    L_0002: call void ConsoleApplication1.Program::C()
    L_0007: nop
    L_0008: nop
    L_0009: leave.s L_0020
    L_000b: stloc.0
    L_000c: nop
    L_000d: ldstr "Method C() catches the exception and partly handles it"
    L_0012: call void [mscorlib]System.Console::WriteLine(string)
    L_0017: nop
    L_0018: call void [mscorlib]System.Console::WriteLine()
    L_001d: nop
    L_001e: rethrow
    L_0020: nop
    L_0021: ret
    .try L_0001 to L_000b catch [mscorlib]System.Exception handler L_000b to L_0020
}

In the above CIL code the key is L_001e where it rethrows the exception. This is where the CIL is much more explicit than C#. In C# the throw keyword is overloaded and functions differently depending on whether it receives an exception object or not.

Training Developers

Software development is a very fast moving business and it is therefore vitally important to keep up with what is happening with technology. If you don’t you could be left behind pretty quickly. When the proverbial hits the fan you don’t want to be left behind.

If you remember back to your school days you might remember Æsop’s fable The Ant and the Grasshopper. The grasshopper did no work in the summer while the ant worked hard in preparation of the lean times. When the lean times came the ant was able to provide for himself, while the grasshopper starved. A lot of software developers are like the grasshopper, they are not planning for their future. You might think it unfair of me to tar all developers with that brush, but I don’t mean to. I did say “a lot” not “all”. So why do I think that?

Last year I spent three months trying to hire a developer. I was shocked at the number of developers that I saw had the attitude that they didn’t need to learn anything unless their employer put them on a training course. Some seemed surprised when I asked how they kept up to date with the industry they are in. Most just mumbled something about reading books and articles online. Given the answers to other questions I don’t think they spent all that much time reading.

Software development knowledge fades faster than ever these days. It seems like only yesterday that I was learning .NET 1.0, yet .NET 4.0 is just around the corner. In a couple of years I’ll be using it commercially. Technologies like LINQ to SQL which has only been released will be dead soon, if recent reports are to be believed. That’s a lot of new information to take in only for it to go stale. This week I’m immersing myself in ASP.NET MVC. I’ve been to a talk on the subject at it looks like that’s the way forward so I want to be at the head of the pack. I’ll also be taking a first look at Subversion this week also. On top of that I’ve got a stack of other things to get through.

When I left university I had the arrogance to think that I knew it all and for a few years I worked on that principle. But that attitude eventually caught up with me and I spent some time unemployed partly as a result of that attitude. I am determined not to let that happen again. These days I am acutely aware of what I don’t know. I think that now I am more aware of my limitations I am a better developer. Because I’m more aware of what I don’t know I strive to fill those gaps by ensuring my own education – I don’t let an employer dictate what I should be learning. I am pro-active and go out there and ensure I’m educated. Of course, if my employer wants to put me on a specific training course I’ll accept it.

I did a little calculation last weekend that surprised me. Actually it shocked the heck out of me. Last year my employer spend roughly £200 on training materials for me. However, I spent a lot more. Of the things that I can remember (so I suppose the things that were worth it) I spent £2500 on my own education.

So, who gets the benefit out of this? For the most part my employer gets the benefit. While I enjoy developing software, it is my employer that profits from it at the end of the day.

Most employer attitudes to training developers are that it isn’t worth it because the developer will just leave with the additional knowledge they’ve received for a higher salary else where. Well, I suppose they will if the employer has that kind of cynical attitude. Employers think that they have to find a replacement soon so why bother training a developer only for another company to take advantage of that. But the a lot of the knowledge that is walking out the door cannot be replaced easily. A lot of the knowledge walking out the door is about the employer’s business and that is unique. You can’t hire that in.

There are a number of “solutions” to this problem. Some employers go for the stick method. “If I train you up and you leave within X months then you have to pay part of the training costs back.” The disturbing thing is that I used to think that was an acceptable solution. But it really isn’t. It is a form of financial handcuffs, and the developer being trained is going to resent it. Quite possibly they’ll be off as soon as the handcuffs are removed or simply not accept the training.

The more reasonable attitude, I think, to take about training is to realise that the developer that’s just been trained has increased their market value. So, pay market value for the developer. You don’t necessarily have to do it straight away, give the training time to sink in if you want, but do increase the developers salary within a few months and don’t tie it to anything else. Don’t roll it in with inflation based increase, an annual increase, or other bonus schemes. Make it very clear that the increase is solely as a result of the greater ability or productivity as a result of the training previously received.

Drawing lines on the map with the Virtual Earth ASP.NET control

This uses the July 2008 CTP of the Windows Live tools. You can download the Windows Live Tools for Visual Studio.

In this post, we’re taking a look at drawing lines on the map with the Virtual Earth ASP.NET control.

In the a previous post (Using PushPins with the Virtual Earth ASP.NET control) I showed how to create a Shape object that represents a point on the map. In that post the Shape constructor took a parameter that described the type of object and a point. With Polylines more than one point is required. To construct an appropriate Shape object a list of points is needed. A point is represented by an LatLongWithAltitude object.

List<LatLongWithAltitude> points = new List<LatLongWithAltitude>();

Once the list is populated the Shape can be created:

Shape result = new Shape(ShapeType.Polyline, points);

Alternatively, it is possible to defer the addition of the points until a later time by assigning them through the Points property.

Lines and Pushpins

One thing you have to be careful of when creating shapes that are lines (or polygons, but we’ll come to that later on) is that by default a pushpin is also displayed to go along with the line (see right) in order to give the user something to hover over so they can gain more information. If these pushpins are not desired then the IconVisible property needs to be set to false.

shape.IconVisible = false;

On the other hand, if a pushpin is desired for each line then you can control where the pushpin appears. By default they are somewhere along the middle of the line. The IconAnchor property can be set to the point at which the pushpin is to appear. For example, to set the pushpin to appear at the start of a line use:

shape.IconAnchor = shape.Points[0];

You can also do the other customising of the pushpin as I showed you in my previous post (Using PushPins with the Virtual Earth ASP.NET control).

Customising the Line

There are also many ways to customise the line as well. You can change the colour and width of the line on the Shape object.

In the example on the left the data has been customised to reflect two attributes. The data is rail services in Scotland and includes information on the route, start and end stations, the length of the route and the train franchise operator.

In the example, the train franchise operator is reflected in the colour of the lines while the length of the route is reflected in the width of the line. The shorter suburban routes are quite thin lines, while the intercity lines are much thicker.

The LineWidth property accepts the width in pixels of the line, while the LineColor property accepts a Color object (from the Microsoft.Live.ServerControls.VE namespace). The Color object allows you to specify the standard red, green and blue values (each 0-255) along with an alpha blend value (a double from 0 to 1.0).

Line Generalisation

So far this is pretty easy, however, what appears on the map isn’t necessarily what you put into the Shape object. Virtual Earth generalises the shape that you create, presumably to improve performance. I suspect the idea was to generalise in a way that the user wouldn’t notice, however, it some situations it is very obvious that the line is not displaying its original points.

Take a look at these two maps. They both display exactly the same data. One is just a zoomed in version of the other (I’ve enlarged the zoomed out version so they are the same size to make them easier to compare).

The map on the left shows the naturally zoomed in version. The one on the right shows the zoomed out version (which I then resized back so that both maps are the same size for this blog post)

Because central Scotland is quite busy and has a lot of rail routes, have a look at the routes in the Highlands (north of Scotland) to see this phenomenon more easily. Take the most northern route for example. The map on the left shows it weaving in and out of the mountains reasonably clearly, while the map on the right shows the route slightly more straightened out. Also the map on the right doesn’t even appear to hit some of the points.

 

Technorati Tags: ,,

Using a different map server with the Virtual Earth ASP.NET controls.

This uses the July 2008 CTP of the Windows Live tools. You can download the Windows Live Tools for Visual Studio.

One of the interesting features of Virtual Earth is that it doesn’t have to use the maps provided by Microsoft. You can set it up to point to another tile server so that you can use your own maps. This could be extremely useful for people who want to show static visualisations of data, or simply display something different to what Microsoft give you.

Setting up the tile server is likely the more difficult part as setting up the client to point at a new tile server is incredibly easy. I’m not going into setting up the tile server in this post.

First setting up the ASPX page to handle this:

<form id="form1" runat="server">
    <div>
       <asp:ScriptManager ID="ScriptManager1" runat="server"
         EnablePartialRendering="true" />
       <ve:Map ID="VEMap" runat="server" Height="600px" Width="600px"
         ZoomLevel="8" Center-Latitude="55.75" Center-Longitude="-3.5" />
    </div>
</form>

As you can see there isn’t anything unusual here. There are no additional options to set.

However, in the Page_Load event handler there are some things that need to be set up:

protected void Page_Load(object sender, EventArgs e)
{
    VEMap.DashboardSize = DashboardSize.Tiny;
    List<LatLongRectangle> bounds = CalculateBounds();
    TileSourceSpecification tileSpec = new TileSourceSpecification(
        "OSM", "", 1, bounds, 1, 18, "getTilePath", 1.0, 100, true);
    VEMap.AddTileLayer(tileSpec, true);
}
private static List<LatLongRectangle> CalculateBounds()
{
    List<LatLongRectangle> bounds = new List<LatLongRectangle>();
    LatLongRectangle box = new LatLongRectangle(
        new LatLong(90, -180), new LatLong(-90, 180));
    bounds.Add(box);
    return bounds;
}

First of all, we are reducing the dashboard side down to its minimum because the particular tile server does not support the other features provided in the dashboard such as switching between road and aerial photography.

We create the TileSourceSpecification that defines what the tile server can do and how to interact with it. The parameters are:

  • Id: An identifier for you to use to identify the tile server, if you are using more than one.
  • TileSource: You can set up a string format to define the URL of the tiles, but only if your tile server is using the same naming convention as Virtual Earth itself. It has the ability of switching between road, aerial and hybrid modes and load balancing. More info on the TileSource Property…
  • NumServers: If your tile server is load balanced then this specifies the number of servers.
  • Bounds: This is the bounding box of the tile layer. In our case above the tile server covers the entire world so our bounding box covers +90,-180 to -90,+180
  • MinZoomLevel / MaxZoomLevel: This pair of parameters specify the the minimum and maximum zoom levels. 1=the whole world, 18 = street level.
  • GetTilePath: This is the name of a javascript function that generates the path to the tile. I’ll go into more detail on that javascript function a little later on. However, if this property contains a value then the TileSource and NumServers properties are ignored.
  • Opacity: How opaque is this tile layer. By default the Virtual Earth tiles are drawn first, then your layer is drawn on top. 0 is completely transparent (and a bit pointless) while 1.0 is completely opaque and will hide the layer underneath. At present you cannot turn off the layer underneath so if you only want to see your layer set the opacity to 1.0. This is because Virtual Earth ASP.NET controls are based on Virtual Earth 6.1. 6.2 is now released which does have the ability to turn off the base layers.
  • ZIndex: Tile layers can be stacked on top of each other, this indicates the positioning of this layer in that stack.
  • Visible: Indicates whether the layer is visible or not.

In the example above the tile server does not support the virtual earth naming convention. In that case a javascript function to define the name of each tile is needed. In our example it looks like this:

function getTilePath(tileContext)
{
    return "http://tile.openstreetmap.org/" + tileContext.ZoomLevel +
         "/" + tileContext.XPos + "/" + tileContext.YPos + ".png";
}

The server for the tiles is http://tile.openstreetmap.org. If you are unfamiliar with it, Open Street Map is an open source map of the world.

The tile server refers to the individual tiles in the format “/{ZoomLevel}/{X}/{Y}.png”. These values can be obtained by the tileContext parameter (see right) passed into the javascript function.

The tile context also contains a map style property which can be “r” (road), “a” (aerial) or “h” (hybrid).

The final result looks like this:

For information about doing the same purely in javascript see this post by John O’Brien.