Archive for August, 2011

Blog has moved! You should check this post out on kevinpelgrims.com

Since I had fun using the Bing Maps API in C# (see Bing Maps – Geocoding and Imagery), I decided to try and do the same in PowerShell. This didn’t seem to be very hard either, as it’s possible to use the same objects as you would in a regular .NET application. Go PowerShell!
The only difference is the web service trick on the second line.

$key = "apikey";
$ws = New-WebServiceProxy -uri http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc?wsdl;
$wsgr = New-Object Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1ervice_geocodeservice_svc_wsdl.GeocodeRequest;

$wsc = New-Object Microsoft.PowerShell.Commands.NewWebserviceProxy.AutogeneratedTypes.WebServiceProxy1ervice_geocodeservice_svc_wsdl.Credentials;
$wsc.ApplicationId = $key;
$wsgr.Credentials = $wsc;

$wsgr.Query = 'Brussels, Belgium';
$wsr = $ws.Geocode($wsgr);

$wsr.Results[0] | select {$_.Address.FormattedAddress}, {$_.Locations[0].Longitude}, {$_.Locations[0].Latitude};

When you execute this in PowerShell, it looks like this:

Geocoding in PowerShell

Things like this make you think about the power of PowerShell. If you can do it in .NET, you can do it in PS!

Read Full Post »

Bing Maps – Geocoding and Imagery

Blog has moved! You should check this post out on kevinpelgrims.com

Since I did a lot of GIS related stuff recently for work, I decided I’d have some fun with the Bing Maps API. I’ve been using Bing to display maps as a base for multiple layers of data in combination with MapGuide OS and needed to convert addresses to geocodes (coordinates). Afterwards I decided to play with it some more and I created a little app in C# that makes more use of Bing Maps.

If you want to get started with the Bing API, you’ll first need to get a key. More info on that can be found on MSDN.

Alright, now you got your key, let’s get started!

First thing you need to do to use the Bing Maps service, is adding a service reference. We’ll start out with some geocoding, so we need the geocode service. The addresses of the available services can be found here.

Click "Add Service Reference..." to open the service reference dialog

The we can use the following code to “geocode” an address (get the coordinates):

private String Geocode(string address)
    GeocodeRequest geocodeRequest = new GeocodeRequest();

    // Set credentials using a Bing Maps key
    geocodeRequest.Credentials = new GeocodeService.Credentials();
    geocodeRequest.Credentials.ApplicationId = key;

    // Set the address
    geocodeRequest.Query = address;

    // Make the geocode request
    GeocodeServiceClient geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
    GeocodeResponse geocodeResponse = geocodeService.Geocode(geocodeRequest);

    return GetGeocodeResults(geocodeResponse);

GetGeocodeResults is just a function that I made to print out the response on the screen. As seen here:

Get the coordinates for an address

(There are some extra options available. You could, for example, tell the service to only return “high confidence” results. But I’m not going to talk about that here.)

Because getting the coordinates was so easy, I decided to also implement reverse geocoding. Which is (as you would expect) converting coordinates to an address.

private String ReverseGeocode(double latitude, double longitude)
    ReverseGeocodeRequest reverseGeocodeRequest = new ReverseGeocodeRequest();

    // Set credentials using a Bing Maps key
    reverseGeocodeRequest.Credentials = new GeocodeService.Credentials();
    reverseGeocodeRequest.Credentials.ApplicationId = key;

    // Set the coordinates
    reverseGeocodeRequest.Location = new BingMapsSoap.GeocodeService.GeocodeLocation() { Latitude = latitude, Longitude = longitude };

    // Make the reverse geocode request
    GeocodeServiceClient geocodeService = new GeocodeServiceClient("BasicHttpBinding_IGeocodeService");
    GeocodeResponse geocodeResponse = geocodeService.ReverseGeocode(reverseGeocodeRequest);

    return GetGeocodeResults(geocodeResponse);

Converting coordinates to addresses is easy!

After getting this far in about 15 minutes of figuring it out and coding, I couldn’t stop there! I decided to add some basic imagery for the address/coordinates that are converted. For imagery you need to add a reference to the imagery service first. Writing code for this is also pretty easy, as there are plenty of examples on MSDN that can be useful. It seems Microsoft really put some effort into  documenting this right 🙂

private void GetImagery(double latitude, double longitude)
    MapUriRequest mapUriRequest = new MapUriRequest();

    // Set credentials using Bing Maps key
    mapUriRequest.Credentials = new ImageryService.Credentials();
    mapUriRequest.Credentials.ApplicationId = key;

    // Set the location of the image
    mapUriRequest.Center = new ImageryService.Location();
    mapUriRequest.Center.Latitude = latitude;
    mapUriRequest.Center.Longitude = longitude;

    // Set map style and zoom level
    MapUriOptions mapUriOptions = new MapUriOptions();
    mapUriOptions.Style = MapStyle.AerialWithLabels;
    mapUriOptions.ZoomLevel = 17;

    // Set size of the image to match the size of the image control
    mapUriOptions.ImageSize = new ImageryService.SizeOfint();
    mapUriOptions.ImageSize.Height = 160;
    mapUriOptions.ImageSize.Width = 160;

    mapUriRequest.Options = mapUriOptions;

    ImageryServiceClient imageryService = new ImageryServiceClient("BasicHttpBinding_IImageryService");
    MapUriResponse mapUriResponse = imageryService.GetMapUri(mapUriRequest);
    BitmapImage bmpImg = new BitmapImage(new Uri(mapUriResponse.Uri));
    bingImage.Source = bmpImg;

That code gives us this result:

Looks pretty good for a small app that took almost no time to make. The Bing Maps API is pretty straight-forward to work with and MSDN has some good samples to get started. So if you’re interested in working with Bing Maps, be sure to check out the documentation.

Now go and have fun with this!

Read Full Post »

PowerShell Script Commander

Blog has moved! You should check this post out on kevinpelgrims.com

I wrote this entry last year September, but for several reasons the post and the code never made it to the interwebs. After running into it again I decided to post it anyway and upload the code to Codeplex. So, here goes!

A while back I created this PowerShell script to remotely manage services (see Remote Service Manager), a bit later I made the available help a bit more professional (see Add help to your own PowerShell scripts). Now I was thinking it would be cool to create an interface in .NET for this script. So I started developing a WinForm application around the script. Initially, it looked like this:

This was the first (working) prototype of the RSM-GUI. But then I started thinking it would be much cooler to create an application that can run all scripts, even those with parameters. I started thinking about how to do this and actually it didn’t seem so hard. I started by creating a form that can execute simple PowerShell commands and show the output, then added support for running scripts stored on the hard drive. For the parameters I just made sure they are all displayed in a grid, where you can give them a value by simply typing something in. And that was it! I now have a Windows application that can run scripts on a more visual way. Now you can simply load the script with an OpenFileDialog and see what parameters are available. If you still don’t fully understand how the script works, you can press the Get-Help button to display the help information in the outputbox.

And now, it looks like this:

PowerShell Script Commander help function

PowerShell Script Commander running the RSM script, with parameters

A lot of work needs to be done to make this more reliable and to make it work with all scripts on the planet 😉 But I think it’s already pretty cool.

The source code can be found here: http://pscommander.codeplex.com/

Read Full Post »

Blog is moving! You should check this post out on kevinpelgrims.com

When you are installing MapGuide OS and you encounter following error:

Failed while processing WebVirtualDirs

Fear not, because here is the solution!

The problem is with how MapGuide OS is trying to install its websites. This is not configurable during the installation and will by default be installed in a website called “Default Web Site” on port 80. This is the website that is created for you when IIS is installed. If you change the name of the website or the port number, the MapGuide OS installation freaks out!
So the simplest solution is to create a website called “Default Web Site” and have it run at port 80. You can then edit those settings after the installation is done without any problems, so you can still run the MapGuide OS websites on a different port.
If you need some more explanation, this is an interesting thread http://osgeo-org.1803224.n2.nabble.com/Installation-error-td3858392.html with a good answer by Jason Birch.

Read Full Post »

Blog is moving! You should check this post out on kevinpelgrims.com

Autodesk Infrastructure Map Server logoI encountered a problem today while working on a website that uses Autodesk Infrastructure Map Server 2012 (aka MapGuide) and it’s API. To programmatically create a new layer on a map it seems to be recommended to use the LayerDefinitionFactory that is provided with the installation of the server. Now the problem is that this factory is only provided in PHP and I am working in C#. I could install PHP on the server and try to get all freaky with .NET-PHP communication. But it seemed easier to just port the factory to C# (it’s not that big anyway).

I wrote some basic functions and then only converted the stuff I need for this particular project, but it should be very easy to convert the other functions when you need them. I did not rewrite the sprintf() function that can be found in PHP, because it is a lot easier to use String.Format() if you adjust the template files. So, this is what one of the templates now look like after changing all the occurrences of %s to the C# version with {0}, {1}, etc.:

<?xml version="1.0" encoding="UTF-8"?>
<LayerDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="LayerDefinition-2.3.0.xsd" version="2.3.0">

And here is the code:

using System;
using System.Text;
using System.IO;

/// <summary>
/// Factory for MapGuide layer definitions.
/// </summary>
public class LayerDefinitionFactory
	string templatePath;

	public LayerDefinitionFactory(string path)
		templatePath = String.Concat(path, "{0}.templ");

	/// <summary>
	/// Read the template required for the layer definition.
	/// </summary>
	/// <returns>Returns (a part of) the layer definition in XML.</returns>
	private string ReadTemplate(string filename)
		StreamReader reader = new StreamReader(String.Format(templatePath, filename));
		string templateDefinition = reader.ReadToEnd();
		return templateDefinition;

	/// <summary>
	/// Create a new layerdefinition.
	/// </summary>
	public string CreateLayerDefinition(string resourceId, string featureClass, string geometry, string featureClassRange)
		string[] values = new string[] { resourceId, featureClass, geometry, featureClassRange };
		return String.Format(ReadTemplate("layerdefinition"), values);

	/// <summary>
	/// Create a new line rule for the layer definition.
	/// </summary>
	public string CreateLineRule(string lineStyle, string thickness, string color)
		string[] values = new string[] { lineStyle, thickness, color };
		return String.Format(ReadTemplate("linerule"), values);

	/// <summary>
	/// Create the line type style with line rules for the layer definition.
	/// </summary>
	public string CreateLineTypeStyle(string lineRules)
		string[] values = new string[] { lineRules };
		return String.Format(ReadTemplate("linetypestyle"), values);

	/// <summary>
	/// Create the scale range for the layer definition.
	/// </summary>
	public string CreateScaleRange(string minScale, string maxScale, string typeStyle)
		string[] values = new string[] { minScale, maxScale, typeStyle };
		return String.Format(ReadTemplate("scalerange"), values);

Read Full Post »