Customizing your Worldmaps

I admit that site design is something that often takes a back seat when developing Worldmaps, but in the recent migration to Windows Azure, I added a few new minor customizations to the maps. When you log into your account, you should see a list that contains all of your current maps: From this screen, you can either modify a map, or create a new one.   When creating a new map, you’ll see a simple form to fill out: All of the information that is required for the map is the URL and Leaderboard.  The latitude and longitude fields indicate your home location.  You can use the home locator map on the bottom of the screen to help in this regard, or you can leave this blank.  Without this information, some statistics cannot be calculated.  The Leaderboard indicates which category best suits your map.  Is it a personal blog?  A technology blog?  A personal site?   Pick the one that best fits your site – this can be changed later. The last box, Invitation Code, is for premium accounts and changes the way the data is stored for the given map.  I described this briefly in my last post.   For scalability reasons, most new accounts will be under the new scheme – if you need more detailed information (such as # of unique IPs), contact me for invitation code.  Customizing your Map Once your map is created, click the edit button next to your map to customize the colors.  The form should look similar to: When the app is drawing your maps, you can control the colors used in drawing the circles.  Feel free to experiment with some color choices.  The four values you can customize are explained on the form.  Use the Silverlight-based Color Picker to find a color and copy that value into the text box of the value you’d like to change.  Or, you can enter values directly into the box if you know the hex-value of the color you’d like to use.  When done, click Save.  In general, the maps will be redrawn reasonably quick depending on how much work is currently in the queue.  Customizing the colors is a great way to add a little personalization to your maps!

Pay Attention to your Azure Blobs

I have a fairly large Windows Azure migration I’m working on, and there are dozens of tips, recommendations, gotchas, etc. I’ve learned in the process.  This is one small item that cost me quite a bit of time, and it’s so simple I’m detailing it here because someone will run into this one. First a bit of background: if you’re deploying a Windows Azure application, the package is uploaded and deployed as a whole.  If you have dynamic content or individual files that are subject to change, it’s a good idea to consider placing it in Azure Storage, otherwise you’ll have to redeploy your entire application to update one of these files.  In this case, I’d like to put a Silverlight XAP file in Azure storage, instead of the typical /ClientBin folder. There are a number of references on the net for setting this up – searching for “XAP” and “Azure” returns a lot of good references including this one.  After checking my Silverlight project’s app manifest file, ensuring everything was correct, and uploading the XAP to my Azure storage account, my Silverlight app would refuse to run.  The page would load, but then … nothing.  I also checked Fiddler – the XAP file _was_ getting downloaded (and was downloading fine via a browser).  This is typically a tell-tale sign of a policy issue – yet I was certain everything was correct.  Here’s a screenshot (click for larger) of Fiddler downloading the file.  Can you spot the problem here? The problem was indirectly with Cerebrata’s Cloud Storage Studio.   Cerebrata’s product is really nice and I enjoy working with it quite a bit to work with Azure storage (uploading/downloading files).  CloudBerry’s Explorer for Azure Blob Storage is another good one – I typically work with Cerebrata’s simply because it was easier to connect to development storage (not sure if this is possible in CloudBerry’s app). Fast-forward and hour or two of frustration.  Staring at Cloud Storage Studio, I see: Zip file as a content type?  This was in the Fiddler screenshot above, too.  I figured this was fine because after all, a XAP file is a zip file.  But as it turns out, this was the problem.   For kicks, I tried re-uploading the XAP file from CloudBerry to see how it handled the content type, and:   Cloud Storage Studio does allow you to alter the content types, but truthfully I didn’t think this was all that important.  When I reloaded my application, though, the app loads and Fiddler comes to life as it should: For kicks I changed the content type back to Zip, and the app would fail to load.  So, lesson learned!  Don’t forget about the content types.

Persisting User Settings in Silverlight

One topic that comes up frequently in dev circles is persisting data in Silverlight applications.  There are a number of ways to do this, and the right solution depends on the data that is being stored.  In ASP.NET applications, user settings are typically stored in a database and often abstracted through a mechanism like the ASP.NET Profile provider in conjunction with the ASP.NET Membership provider.  The make the end user experience a bit better, log in state (or simply the username) is persisted in a cookie.  In Silverlight, this is still a viable approach (although the data is typically exposed via webservices, depending on the application). Another approach, however, is to use isolated storage.  Isolated storage can be an effective tool for caching data (with a number of caveats).  In the example below, I’ve created a very simple class that contains the application settings I’d like to persist.   The key methods are Load() and Save().   Out of the box, this will work and you can simply add/remove properties as you’d like.  1: public class ApplicationSettings 2: { 3: [DefaultValue(6)] 4: public int MinZoom { get; set; } 5:  6: [DefaultValue(13)] 7: public int MaxZoom { get; set; } 8:  9: [DefaultValue(8)] 10: public int PlotDelay { get; set; } 11:  12: [DefaultValue(false)] 13: public bool RememberSettings { get; set; } 14:  15: public ApplicationSettings() { } 16:  17: public static WorldmapsSettings Load() 18: { 19: ApplicationSettings settings = new ApplicationSettings(); 20:  21: using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) 22: { 23: if (!store.FileExists(@"ApplicationSettings.xml")) 24: { 25: return settings; 26: } 27:  28: using (var isoStream = store.OpenFile(@"ApplicationSettings.xml", 29: FileMode.Open)) 30: { 31: XmlSerializer s = new XmlSerializer(typeof(ApplicationSettings)); 32: TextReader r = new StreamReader(isoStream); 33: settings = (ApplicationSettings)s.Deserialize(r); 34: r.Close(); 35:  36: if (settings != null && settings.RememberSettings) 37: { 38: return settings; 39: } 40: else 41: { 42: return new ApplicationSettings(); 43: } 44: } 45: } 46: } 47:  48: public void Save() 49: { 50: using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) 51: { 52: using (IsolatedStorageFileStream isoStream = store.OpenFile(@"ApplicationSettings.xml", 53: FileMode.Create)) 54: { 55: XmlSerializer s = new XmlSerializer(typeof(ApplicationSettings)); 56: TextWriter writer = new StreamWriter(isoStream); 57: s.Serialize(writer, this); 58: writer.Close(); 59: } 60: } 61: } 62: } [EDIT] Silverlight guru Tim Heuer pointed out I’m doing a lot of extra work I don’t need to.   The ApplicationSettings of the IsolatedStorageSettings allows us to stuff objects in it pretty cleanly – so the above could be implemented like so: 1: public static WorldmapsSettings Load() 2: { 3: 4: WorldmapsSettings settings = null; 5: 6: if (IsolatedStorageSettings.ApplicationSettings.Contains("foo")) 7: { 8: settings = IsolatedStorageSettings.ApplicationSettings["foo"] as WorldmapsSettings; 9: } 10: 11: if (settings == null) 12: { 13: settings = new WorldmapsSettings(); 14: } 15:  16: return settings; 17: } 18:  19: public void Save() 20: { 21: IsolatedStorageSettings.ApplicationSettings["foo"] = this; 22: } I can’t think of a good reason not to do it this way, unless some more complex serialization is called for, but even then I can’t come up with a good scenario for that.  [/EDIT]   Now for the caveat.  Isolated storage isn’t secure unless you take some measures to secure it manually.  While you could encrypt the contents, I’d probably recommend not storing data on the client if you’re saving sensitive data.  In the above example, I’m serializing the data using the XML serializer, so the data is obviously in plain text and stored locally: … and it contains the expected object: 1: <ApplicationSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2: xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 3: <MinZoom>2</MinZoom> 4: <MaxZoom>16</MaxZoom> 5: <PlotDelaySeconds>14</PlotDelaySeconds> 6: <RememberSettings>false</RememberSettings> 7: </ApplicationSettings> Isolated storage offers a lot of potential, but it’s also important to remember the security implications in both exposing the data as well as potential injection points.

Worldmaps Stumbler

I’m happy to announce I’ve finally completed a cool little Silverlight app entitled “Worldmaps Stumbler” (thanks Andrew for the name!).  So what is it?  Worldmaps Stumbler essentially plots Worldmaps data in near-real time using Silverlight and Virtual Earth.   While the current stats maps currently use Virtual Earth and web services to plot data, the experience is largely utilitarian, and due to the nature of the application, I wasn’t able to incorporate any real-time information. With Silverlight, it’s much easier to enhance the experience to include not only real time data, but more of a stylish presentation.  As the application runs, it watches for changes and plots the data on the map – for example: The app will zoom in, show the browser used, the URL of the map, and the date/time of the hit and how long ago that was. When the Worldmaps server records the hit with the time, it bubbles up to the Stumbler to get plotted.  When the hit is plotted, the age of the hit is calculated so you can see precisely how long ago the hit was.  This process can take anywhere from about 4 seconds to about a minute, depending on a number of factors.  The folks at Earthware have posted a great tutorial on how to create a minimap using the Silverlight Virtual Earth control.  (They also have a cool demo called Silverlight Twitter Map.  Although a word of warning: while it’s a great background show while discussing Virtual Earth and Silverlight integration, a lot of potty-mouth tweets always seem to end up on screen.) There are a few options in the app: The maps button allows you to select which Worldmaps maps to plot.  By default it is all of them, but it can be narrowed to your preference.  The slider to the right of the minimap controls the delay between plotting hits.  Higher is slower.   Also, if the dot in the middle of the minimap is blue, the app is running fine.  Yellow circles indicate network activity (polling for data – this should barely be perceptible) and red means an error of some kind.  Hopefully you won’t see red, but if you do, no data will be available. To use the Stumbler, simply visit:  http://www.myworldmaps.net/sl/WorldmapsStumbler.aspx If you’re a Worldmaps user and want a customized experience for your maps on startup, your map IDs can be passed in through the maps parameter in the querystring (pipe delimited).  For example, to launch the app observing only my two maps, I can use the following URL:  http://www.myworldmaps.net/sl/WorldmapsStumbler.aspx?maps=FECB0AFF-083E-4F42-9B08-9A01E3CB714A|495A96ED-A6AC-495B-A134-72C434EEA880 At this time, only the top twenty or so maps are plotted, however more will be added soon.  So go check it out – it’s fun to watch!

My Apps

Dark Skies Astrophotography Journal Vol 1 Explore The Moon
Mars Explorer Moons of Jupiter Messier Object Explorer
Brew Finder Earthquake Explorer Venus Explorer  

My Worldmap

Month List