Writing on Tablets Tech stuff from @yeltzland

Showing my current location using Virtual Earth

Originally posted on my old MSDN blog

As I’m often switching location between my home in the UK and working out in Redmond, I’ve been thinking for a while about how best to easily let people know where I am. As you can hopefully see, I’ve added a map to every page on this blog and I thought that maybe people might be interested how I did this, as I learnt a few things on the way that were reasonably interesting.

The first challenge was to figure out the best way around the limitations of adding a map to the blog page. Although the Community Server software that this site runs on is pretty flexible, you can only add elements to every page in various sections – in my case in the News section. Luckily there don’t appear to be any restrictions on the actual HTML you can add, so I was left with a choice of options.

My first thought was to add an <IFRAME… /> section that would call out to a page on my own server that would use Windows Live Maps to display where I am by adding a pushpin at the appropriate location. However this didn’t really work very well, as the map code didn’t really like being in an IFrame and the flow of the page around the map was broken.

Therefore the solution I hit on was to add the following code:

<h3>LIVE LOCATION</h3>
<div id='myMap' style="position:relative; width:150px; height:200px;"></div>
<script type<="text/javascript" src="http://www.metanetsolutions.co.uk/mapscript.aspx?mapElement=myMap" defer="true"></script>

The ‘myMap’ element is the div where the map will be placed by the JavaScript that I create on my server. Note that I am passing the name of this element into my script so I can use it.

Interesting point to note is adding the defer=true on to the script call. Without it, I was occasionally hitting a known issue in Internet Explorer due to a bug in the IE parser :-(

The ASPX page that generates the JavaScript is shown below. I won’t show the pretty simple code behind just yet, as I’m hoping to add more functionality to this soon before I share the code. However in this initial version it just creates a “LocationEntry” object from an XML file held on the server, and then uses this object to set various parts of the script.

The interesting things of note in the JavaScript are:

  • Note the excellent "delayed loading of the map code" that was written by Soul Solutionsthat I used here. This:
    • Sets an animated GIF as the background to the map div while the code is loading
    • Dynamically adds the Virtual Earth required JavaScript files to the head element of the page
    • Sets a callback to the function to setup the map once the VE API scripts have loaded
  • The onscriptload callback function removes the dashboard and scalebar to make the map cleaner, sets the zoom level – defaults to 10 but can be overwritten by setting a zoom=n on the query parameters to the page request, and then simply adds a pushpin at the location set by the LocationEntry in the code behind

Hopefully this is pretty self-explanatory – see http://dev.live.com/virtualearth/ for more details about the Virtual Earth API.

 

Here’s the ASPX/JavaScript code:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="MapScript.aspx.cs" Inherits="DefaultPage" %>
var mapElementName = '<%= this.MapElementName %>';
var mapControlVersion = '6.2';

// Dynamic loading script from http://www.soulsolutions.com.au/examples/VE62/loadondemand.htm
var loaded = false;
var map = null;

function onscriptload()
{
    // Get rid of our load animation
    document.getElementById(mapElementName).style.background = "";

    var locationLatLong = new VELatLong(<%= this.CurrentLocation.Latitude %>, <%= this.CurrentLocation.Longitude %>);
    map = new VEMap(mapElementName);
    map.LoadMap(locationLatLong, 1, VEMapStyle.Road, true, VEMapMode.Mode2D, false, 0);
    map.HideDashboard();
    map.HideScalebar();
    map.SetZoomLevel(<%= this.MapZoomLevel %>);

    AddLocationPushpin(locationLatLong);
}

function loadVEAPI()
{
    if (!loaded)
    {
      loaded = true;

      // Set a nice animated gif to show the map is loading
      document.getElementById(mapElementName).style.background = "url(images/ajax-loader.gif) center center no-repeat";
      
      if (!(window.attachEvent))
      {
        appendJS("http://dev.virtualearth.net/mapcontrol/v" + mapControlVersion + "/js/atlascompat.js");
      }

      appendJS("http://dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v="+ mapControlVersion + "&onScriptLoad=onscriptload");
    }
}

function appendJS(filename)
{
    var fileref = document.createElement('script');
    fileref.setAttribute("type", "text/javascript");
    fileref.setAttribute("src", filename);
    document.getElementsByTagName("head"[0].appendChild(fileref);
}

function AddLocationPushpin(myLocation)
{
    map.SetCenter(myLocation);

    var myPushpin = new VEShape(VEShapeType.Pushpin, myLocation);

    myPushpin.SetTitle("<%= this.CurrentLocation.Title %>");

    var description = "<p><%= this.CurrentLocation.Description %></p>";
    description += "<p><%= this.CurrentLocation.UpdateTime.ToString("u<") %></p>";
    myPushpin.SetDescription(description);

    map.AddShape(myPushpin);
}

// Start the loading
loadVEAPI();

Future plans (which I suspect are overly ambitious!) for this application involve:

  • A JavaScript and VE enabled form to easily update my location
  • Mesh-enabling the application
  • Hooking up my GPS so I can automatically update my location when I’m on the move
  • Possibly hooking everything up to FireEagle
Location Maps Fireeagle JavaScript

ASP.Net Compilation Tool - do you want to allow updates without redeploying?

Originally posted on my old MSDN blog

We found an interesting issue today regarding our use of pre-compiled ASP.Net websites that I thought I would share, as we learnt something that we didn’t know before.

In our particular setup (for reasons too complicated to go into here), we have an ASP.Net website that:

  1. We want to pre-compile before deploying to the live servers for the usual reasons of performance (no delay on first hit) and security (source code not hosted on the servers)
  2. Before starting the web application, we automatically generate its web.config file
  3. By default we want to disable view state in all the pages by adding a <pages enableViewState=”false” /> node in the generated web.config

Our issue was that even though the generated web.config file had the correct setting in it, the view state wasn’t being disabled. This had us confused for quite a while.

It turns out that the default setting when a website is compiled by the ASP.Net compiler doesn’t allow subsequent updates to the site.

In our particular case, this meant the compiled pages were using the (default) value in our non-existent web.config at compile time, not the one actually on the server at runtime.

Once we realised that, the solution was easy: simply add a –u parameter to the compiler flags which meant:

-u specifies that the Aspnet_compiler.exe should create a precompiled application that allows subsequent updates of contents such as .aspx pages.

If this option is omitted, the resulting application contains only compiled files and cannot be updated on the deployment server. You can update the application only by changing the source markup files and recompiling.

(Stolen from http://msdn.microsoft.com/en-us/library/ms229863(VS.80).aspx from where you can see all the available compiler parameters)

I guess a more common scenario is that you want to hot fix your web.config file – perhaps your database connection strings need changing immediately – but unless you’ve compiled with the –u flag, you’ll have to do a full build and redeployment.

ASP.Net Tip

Using a parameter in a SELECT TOP statement in SQL

Originally posted on my old MSDN blog

As usual, this may well be common knowledge but I found this useful.

In a stored procedure we were passing in a parameter (say @maxRows) which we wanted to use to dynamically limit the number of rows returned by the query.

For ages we couldn't find a way to do this without building up the SQL in a string using the parameter and then executing it e.g. something horrible like 'SELECT TOP ' + CAST(@MaxRows AS varchar(10)) + '...'

Now it turns out you are supposed to put the value used by the TOP in brackets anyway - see http://msdn2.microsoft.com/en-us/library/ms189463.aspx - so putting the parameter in brackets e.g. SELECT TOP (@MaxRows) ... is not only correct but gets around the horrible cast.

SQL Server Tip

debugger command in JavaScript

Originally posted on my old MSDN blog

I don't do much client-side JavaScript programming, and I've always had intermittent issues when trying to attach a Visual Studio debugger to a instance of IE when I'm trying to figure out what's going on.

However in August 2007's MSDN Magazine (doesn't seem to be available online yet - page 52 in magazine) it talks briefly about the debugger JavaScript command, which forces the browser to bring up the elusive "debugger dialog". Very useful!

I'm not sure how well this is supported across different browsers, but for my non-expert use knowing about the debugger command certainly will make my life easier when I step into the crazy world of JavaScript.

Some more details at http://support.microsoft.com/kb/816173 

JavaScript Tip

SQL Parameters and Types

Originally posted on my old MSDN blog

I found the following page interesting when having issues setting a value in a SqlParameter constructor.

From http://msdn2.microsoft.com/en-us/library/0881fz2y.aspx:

When you specify an Object in the value parameter, the SqlDbType is inferred from the Microsoft .NET Framework type of the Object.

Use caution when you use this overload of the SqlParameter constructor to specify integer parameter values. Because this overload takes a value of type Object, you must convert the integral value to an Object type when the value is zero, as the following C# example demonstrates

Parameter = new SqlParameter("@pname", Convert.ToInt32(0));

I guess it makes sense once it's explained, but it's not immediately clear when you just use 0 rather than Convert.ToInt32(0) why it doesn't work as expected

SQL Server