Bing Maps REST Service .NET Libraries

Bing Maps has two main services for geocoding and routing on the fly. These are the Bing Maps SOAP and Bing Maps REST services. The SOAP services were released before the REST services and have traditionally been the preferred service when working with the .NET framework. The REST services have a lot more features and functionalities than the SOAP services but have been a bit harder to work with in managed code. In addition, many people who have used the REST services with managed code have preferred to work with the XML responses rather than JSON as they are easier to manually parse. This results in losing out on one of the key reasons for using the REST services, smaller responses. There has been some documentation on how to use the REST services in managed code however the it only shows how to handle geocode requests. This post will expand upon that documentation and point you in the right direction to handle the rest of the API’s in the Bing Maps REST services.Note that the Bing Maps REST services have new features and functionalities added to them on a regular basis, the material provided in this blog may become outdated and will not automatically be aware of any new feature in the service.

What I have done is gone through all the documentation for the Bing Maps REST services created a set of C# class definitions that have the same structure as the JSON responses. Note that the XML responses are different and will not work with these classes. In order for these classes to work in your application you will need to add a reference to System.Runtime.Serialization and System.ServiceModel.Web (for Silverlight applications). Doing some tests I have found that these class work great with the Bing Maps WPF, Silverlight, and WP7 map controls. They also work great in console apps as well although a bit hard to visualize that data.

Now on to the fun stuff, I’ll leave the class definitions to the end and first give some examples of how to use them. To start you will want to write some code to query the Bing Maps REST services. This can easily be done using WebClient or a HttpWebRequest. You will then just need to create a query URL to access the service. Once this is done you can take the response from WebClient or HttpWebResponse and serialize it with the Bing Maps REST service class definitions. This can be done using the DataContractJsonSerializer class. Here is an example of a asynchronous method that works well in WPF, and Silverlight:

private void GetResponse(Uri uri, Action<Response> callback)
{
    WebClient wc = new WebClient();
    wc.OpenReadCompleted += (o, a) =>{
        if (callback != null)
        {
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Response));
            callback(ser.ReadObject(a.Result) as Response);
        }
    };
    wc.OpenReadAsync(uri);
}

Here is a screen shot of a Silverlight test application I used to test this out.

image

And here is an example of a test WP7 application I used to test this out.

trafficWP7SS

And finally, here is the class definitions that you can use with the different API’s within the Bing Maps REST services.

using System.Runtime.Serialization;

namespace BingMapsRESTService.Common.JSON
{
    [DataContract]
    public class Address
    {
        [DataMember(Name = "addressLine", EmitDefaultValue = false)]
        public string AddressLine { get; set; }

        [DataMember(Name = "adminDistrict", EmitDefaultValue = false)]
        public string AdminDistrict { get; set; }

        [DataMember(Name = "adminDistrict2", EmitDefaultValue = false)]
        public string AdminDistrict2 { get; set; }

        [DataMember(Name = "countryRegion", EmitDefaultValue = false)]
        public string CountryRegion { get; set; }

        [DataMember(Name = "formattedAddress", EmitDefaultValue = false)]
        public string FormattedAddress { get; set; }

        [DataMember(Name = "locality", EmitDefaultValue = false)]
        public string Locality { get; set; }

        [DataMember(Name = "postalCode", EmitDefaultValue = false)]
        public string PostalCode { get; set; }

        [DataMember(Name = "neighborhood", EmitDefaultValue = false)]
        public string Neighborhood { get; set; }

        [DataMember(Name = "landmark", EmitDefaultValue = false)]
        public string Landmark { get; set; }
    }

    [DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
    public class BirdseyeMetadata : ImageryMetadata
    {
        [DataMember(Name = "orientation", EmitDefaultValue = false)]
        public double Orientation { get; set; }

        [DataMember(Name = "tilesX", EmitDefaultValue = false)]
        public int TilesX { get; set; }

        [DataMember(Name = "tilesY", EmitDefaultValue = false)]
        public int TilesY { get; set; }
    }

    [DataContract]
    public class BoundingBox
    {
        [DataMember(Name = "southLatitude", EmitDefaultValue = false)]
        public double SouthLatitude { get; set; }

        [DataMember(Name = "westLongitude", EmitDefaultValue = false)]
        public double WestLongitude { get; set; }

        [DataMember(Name = "northLatitude", EmitDefaultValue = false)]
        public double NorthLatitude { get; set; }

        [DataMember(Name = "eastLongitude", EmitDefaultValue = false)]
        public double EastLongitude { get; set; }
    }

    [DataContract]
    public class Detail
    {
        [DataMember(Name = "compassDegrees", EmitDefaultValue = false)]
        public int CompassDegrees { get; set; }

        [DataMember(Name = "maneuverType", EmitDefaultValue = false)]
        public string ManeuverType { get; set; }

        [DataMember(Name = "startPathIndices", EmitDefaultValue = false)]
        public int[] StartPathIndices { get; set; }

        [DataMember(Name = "endPathIndices", EmitDefaultValue = false)]
        public int[] EndPathIndices { get; set; }

        [DataMember(Name = "roadType", EmitDefaultValue = false)]
        public string RoadType { get; set; }

        [DataMember(Name = "locationCodes", EmitDefaultValue = false)]
        public string[] LocationCodes { get; set; }

        [DataMember(Name = "names", EmitDefaultValue = false)]
        public string[] Names { get; set; }

        [DataMember(Name = "mode", EmitDefaultValue = false)]
        public string Mode { get; set; }

        [DataMember(Name = "roadShieldRequestParameters", EmitDefaultValue = false)]
        public RoadShield roadShieldRequestParameters { get; set; }
    }

    [DataContract]
    public class Generalization
    {
        [DataMember(Name = "pathIndices", EmitDefaultValue = false)]
        public int[] PathIndices { get; set; }

        [DataMember(Name = "latLongTolerance", EmitDefaultValue = false)]
        public double LatLongTolerance { get; set; }    
    }

    [DataContract]
    public class Hint
    {
        [DataMember(Name = "hintType", EmitDefaultValue = false)]
        public string HintType { get; set; }

        [DataMember(Name = "text", EmitDefaultValue = false)]
        public string Text { get; set; }
    }

    [DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
    [KnownType(typeof(StaticMapMetadata))]
    [KnownType(typeof(BirdseyeMetadata))]
    public class ImageryMetadata : Resource
    {
        [DataMember(Name = "imageHeight", EmitDefaultValue = false)]
        public string ImageHeight { get; set; }

        [DataMember(Name = "imageWidth", EmitDefaultValue = false)]
        public string ImageWidth { get; set; }

        [DataMember(Name = "imageUrl", EmitDefaultValue = false)]
        public string ImageUrl { get; set; }

        [DataMember(Name = "imageUrlSubdomains", EmitDefaultValue = false)]
        public string[] ImageUrlSubdomains { get; set; }

        [DataMember(Name = "vintageEnd", EmitDefaultValue = false)]
        public string VintageEnd { get; set; }

        [DataMember(Name = "vintageStart", EmitDefaultValue = false)]
        public string VintageStart { get; set; }

        [DataMember(Name = "zoomMax", EmitDefaultValue = false)]
        public int ZoomMax { get; set; }

        [DataMember(Name = "zoomMin", EmitDefaultValue = false)]
        public int ZoomMin { get; set; }
    }

    [DataContract]
    public class Instruction
    {
        [DataMember(Name = "maneuverType", EmitDefaultValue = false)]
        public string ManeuverType { get; set; }

        [DataMember(Name = "text", EmitDefaultValue = false)]
        public string Text { get; set; }
    }

     [DataContract]
    public class ItineraryItem
    {
        [DataMember(Name = "childItineraryItems", EmitDefaultValue = false)]
        public ItineraryItem ChildItineraryItems { get; set; }

        [DataMember(Name = "compassDirection", EmitDefaultValue = false)]
        public string CompassDirection { get; set; }

        [DataMember(Name = "details", EmitDefaultValue = false)]
        public Detail[] Details { get; set; }

        [DataMember(Name = "exit", EmitDefaultValue = false)]
        public string Exit { get; set; }

        [DataMember(Name = "hints", EmitDefaultValue = false)]
        public Hint[] Hints { get; set; }

        [DataMember(Name = "iconType", EmitDefaultValue = false)]
        public string IconType { get; set; }

        [DataMember(Name = "instruction", EmitDefaultValue = false)]
        public Instruction Instruction { get; set; }

        [DataMember(Name = "maneuverPoint", EmitDefaultValue = false)]
        public Point ManeuverPoint { get; set; }

        [DataMember(Name = "sideOfStreet", EmitDefaultValue = false)]
        public string SideOfStreet { get; set; }

        [DataMember(Name = "signs", EmitDefaultValue = false)]
        public string[] Signs { get; set; }

        [DataMember(Name = "time", EmitDefaultValue = false)]
        public string Time { get; set; }

        [DataMember(Name = "tollZone", EmitDefaultValue = false)]
        public string TollZone { get; set; }

        [DataMember(Name = "towardsRoadName", EmitDefaultValue = false)]
        public string TowardsRoadName { get; set; }

        [DataMember(Name = "transitLine", EmitDefaultValue = false)]
        public TransitLine TransitLine { get; set; }

        [DataMember(Name = "transitStopId", EmitDefaultValue = false)]
        public int TransitStopId { get; set; }

        [DataMember(Name = "transitTerminus", EmitDefaultValue = false)]
        public string TransitTerminus { get; set; }

        [DataMember(Name = "travelDistance", EmitDefaultValue = false)]
        public double TravelDistance { get; set; }

        [DataMember(Name = "travelDuration", EmitDefaultValue = false)]
        public double TravelDuration { get; set; }

        [DataMember(Name = "travelMode", EmitDefaultValue = false)]
        public string TravelMode { get; set; }

        [DataMember(Name = "warning", EmitDefaultValue = false)]
        public Warning[] Warning { get; set; }
    }

    [DataContract]
    public class Line
    {
        [DataMember(Name = "type", EmitDefaultValue = false)]
        public string Type { get; set; }

        [DataMember(Name = "coordinates", EmitDefaultValue = false)]
        public double[][] Coordinates { get; set; }
    }

    [DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
    public class Location : Resource
    {
        [DataMember(Name = "name", EmitDefaultValue = false)]
        public string Name { get; set; }

        [DataMember(Name = "point", EmitDefaultValue = false)]
        public Point Point { get; set; }

        [DataMember(Name = "entityType", EmitDefaultValue = false)]
        public string EntityType { get; set; }

        [DataMember(Name = "address", EmitDefaultValue = false)]
        public Address Address { get; set; }

        [DataMember(Name = "confidence", EmitDefaultValue = false)]
        public string Confidence { get; set; }

        [DataMember(Name = "matchCodes", EmitDefaultValue = false)]
        public string[] MatchCodes { get; set; }

        [DataMember(Name = "geocodePoints", EmitDefaultValue = false)]
        public Point[] GeocodePoints { get; set; }
    }

    [DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
    public class PinInfo
    {
        [DataMember(Name = "anchor", EmitDefaultValue = false)]
        public Pixel Anchor { get; set; }

        [DataMember(Name = "bottomRightOffset", EmitDefaultValue = false)]
        public Pixel BottomRightOffset { get; set; }

        [DataMember(Name = "topLeftOffset", EmitDefaultValue = false)]
        public Pixel TopLeftOffset { get; set; }

        [DataMember(Name = "point", EmitDefaultValue = false)]
        public Point Point { get; set; }
    }

    [DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
    public class Pixel
    {
        [DataMember(Name = "x", EmitDefaultValue = false)]
        public string X { get; set; }

        [DataMember(Name = "y", EmitDefaultValue = false)]
        public string Y { get; set; }
    }

    [DataContract]
    public class Point : Shape
    {
        [DataMember(Name = "type", EmitDefaultValue = false)]
        public string Type { get; set; }

        /// <summary>
        /// Latitude,Longitude
        /// </summary>
        [DataMember(Name = "coordinates", EmitDefaultValue = false)]
        public double[] Coordinates { get; set; }

        [DataMember(Name = "calculationMethod", EmitDefaultValue=false)]
        public string CalculationMethod { get; set; }

        [DataMember(Name = "usageTypes", EmitDefaultValue = false)]
        public string[] UsageTypes { get; set; }
    }

    [DataContract]
    [KnownType(typeof(Location))]
    [KnownType(typeof(Route))]
    [KnownType(typeof(TrafficIncident))]
    [KnownType(typeof(ImageryMetadata))]
    public class Resource
    {
        [DataMember(Name = "bbox", EmitDefaultValue = false)]
        public double[] BoundingBox { get; set; }

        [DataMember(Name = "__type", EmitDefaultValue = false)]
        public string Type { get; set; }
    }

    [DataContract]
    public class ResourceSet
    {
        [DataMember(Name = "estimatedTotal", EmitDefaultValue = false)]
        public long EstimatedTotal { get; set; }

        [DataMember(Name = "resources", EmitDefaultValue = false)]
        public Resource[] Resources { get; set; }
    }

    [DataContract]
    public class Response
    {
        [DataMember(Name = "copyright", EmitDefaultValue = false)]
        public string Copyright { get; set; }

        [DataMember(Name = "brandLogoUri", EmitDefaultValue = false)]
        public string BrandLogoUri { get; set; }

        [DataMember(Name = "statusCode", EmitDefaultValue = false)]
        public int StatusCode { get; set; }

        [DataMember(Name = "statusDescription", EmitDefaultValue = false)]
        public string StatusDescription { get; set; }

        [DataMember(Name = "authenticationResultCode", EmitDefaultValue = false)]
        public string AuthenticationResultCode { get; set; }

        [DataMember(Name = "errorDetails", EmitDefaultValue = false)]
        public string[] errorDetails { get; set; }

        [DataMember(Name = "traceId", EmitDefaultValue = false)]
        public string TraceId { get; set; }

        [DataMember(Name = "resourceSets", EmitDefaultValue = false)]
        public ResourceSet[] ResourceSets { get; set; }
    }

    [DataContract]
    public class RoadShield
    {
        [DataMember(Name = "bucket", EmitDefaultValue = false)]
        public int Bucket { get; set; }

        [DataMember(Name = "shields", EmitDefaultValue = false)]
        public Shield[] Shields { get; set; }
    }

    [DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
    public class Route : Resource
    {
        [DataMember(Name = "id", EmitDefaultValue = false)]
        public string Id { get; set; }

        [DataMember(Name = "distanceUnit", EmitDefaultValue = false)]
        public string DistanceUnit { get; set; }

        [DataMember(Name = "durationUnit", EmitDefaultValue = false)]
        public string DurationUnit { get; set; }

        [DataMember(Name = "travelDistance", EmitDefaultValue = false)]
        public double TravelDistance { get; set; }

        [DataMember(Name = "travelDuration", EmitDefaultValue = false)]
        public double TravelDuration { get; set; }

        [DataMember(Name = "routeLegs", EmitDefaultValue = false)]
        public RouteLeg[] RouteLegs { get; set; }

        [DataMember(Name = "routePath", EmitDefaultValue = false)]
        public RoutePath RoutePath { get; set; }
    }

    [DataContract]
    public class RouteLeg
    {
        [DataMember(Name = "travelDistance", EmitDefaultValue = false)]
        public double TravelDistance { get; set; }

        [DataMember(Name = "travelDuration", EmitDefaultValue = false)]
        public double TravelDuration { get; set; }

        [DataMember(Name = "actualStart", EmitDefaultValue = false)]
        public Point ActualStart { get; set; }

        [DataMember(Name = "actualEnd", EmitDefaultValue = false)]
        public Point ActualEnd { get; set; }

        [DataMember(Name = "startLocation", EmitDefaultValue = false)]
        public Location StartLocation { get; set; }

        [DataMember(Name = "endLocation", EmitDefaultValue = false)]
        public Location EndLocation { get; set; }

        [DataMember(Name = "itineraryItems", EmitDefaultValue = false)]
        public ItineraryItem[] ItineraryItems { get; set; }
    }

    [DataContract]
    public class RoutePath
    {
        [DataMember(Name = "line", EmitDefaultValue = false)]
        public Line Line { get; set; }

        [DataMember(Name = "generalizations", EmitDefaultValue = false)]
        public Generalization[] Generalizations { get; set; }   
    }

    [DataContract]
    [KnownType(typeof(Point))]
    public class Shape
    {
        [DataMember(Name = "boundingBox", EmitDefaultValue = false)]
        public double[] BoundingBox { get; set; }
    }

    [DataContract]
    public class Shield
    {
        [DataMember(Name = "labels", EmitDefaultValue = false)]
        public string[] Labels { get; set; }

        [DataMember(Name = "roadShieldType", EmitDefaultValue = false)]
        public int RoadShieldType { get; set; }
    }

    [DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
    public class StaticMapMetadata : ImageryMetadata
    {
        [DataMember(Name = "mapCenter", EmitDefaultValue = false)]
        public Point MapCenter { get; set; }

        [DataMember(Name = "pushpins", EmitDefaultValue = false)]
        public PinInfo[] Pushpins { get; set; }

        [DataMember(Name = "zoom", EmitDefaultValue = false)]
        public string Zoom { get; set; }
    }

    [DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
    public class TrafficIncident : Resource
    {
        [DataMember(Name = "point", EmitDefaultValue = false)]
        public Point Point { get; set; }

        [DataMember(Name = "congestion", EmitDefaultValue = false)]
        public string Congestion { get; set; }

        [DataMember(Name = "description", EmitDefaultValue = false)]
        public string Description { get; set; }

        [DataMember(Name = "detour", EmitDefaultValue = false)]
        public string Detour { get; set; }

        [DataMember(Name = "start", EmitDefaultValue = false)]
        public string Start { get; set; }

        [DataMember(Name = "end", EmitDefaultValue = false)]
        public string End { get; set; }

        [DataMember(Name = "incidentId", EmitDefaultValue = false)]
        public long IncidentId { get; set; }

        [DataMember(Name = "lane", EmitDefaultValue = false)]
        public string Lane { get; set; }

        [DataMember(Name = "lastModified", EmitDefaultValue = false)]
        public string LastModified { get; set; }

        [DataMember(Name = "roadClosed", EmitDefaultValue = false)]
        public bool RoadClosed { get; set; }

        [DataMember(Name = "severity", EmitDefaultValue = false)]
        public int Severity { get; set; }

        [DataMember(Name = "toPoint", EmitDefaultValue = false)]
        public Point ToPoint { get; set; }

        [DataMember(Name = "locationCodes", EmitDefaultValue = false)]
        public string[] LocationCodes { get; set; }

        [DataMember(Name = "type", EmitDefaultValue = false)]
        public int Type { get; set; }

        [DataMember(Name = "verified", EmitDefaultValue = false)]
        public bool Verified { get; set; }
    }

    [DataContract]
    public class TransitLine
    {
        [DataMember(Name = "verboseName", EmitDefaultValue = false)]
        public string verboseName { get; set; }

        [DataMember(Name = "abbreviatedName", EmitDefaultValue = false)]
        public string abbreviatedName { get; set; }

        [DataMember(Name = "agencyId", EmitDefaultValue = false)]
        public long AgencyId { get; set; }

        [DataMember(Name = "agencyName", EmitDefaultValue = false)]
        public string agencyName { get; set; }

        [DataMember(Name = "lineColor", EmitDefaultValue = false)]
        public long lineColor { get; set; }

        [DataMember(Name = "lineTextColor", EmitDefaultValue = false)]
        public long lineTextColor { get; set; }

        [DataMember(Name = "uri", EmitDefaultValue = false)]
        public string uri { get; set; }

        [DataMember(Name = "phoneNumber", EmitDefaultValue = false)]
        public string phoneNumber { get; set; }

        [DataMember(Name = "providerInfo", EmitDefaultValue = false)]
        public string providerInfo { get; set; }
    }

    [DataContract]
    public class Warning
    {
        [DataMember(Name = "warningType", EmitDefaultValue = false)]
        public string WarningType { get; set; }

        [DataMember(Name = "severity", EmitDefaultValue = false)]
        public string Severity { get; set; }

        [DataMember(Name = "text", EmitDefaultValue = false)]
        public string Text { get; set; }
    }
}
About these ads

19 thoughts on “Bing Maps REST Service .NET Libraries

  1. Pingback: Bing Maps REST Service JSON libraries « Ricky's Bing Maps Blog

    • I have not tested it with the metro apps but there is no reason why this shouldn’t work as it works in all the other flavour of .NET apps such as WPF, Silverlight, and standard console type applications.

  2. Hi, I am a newbie.. I wonder where the REST methods are here. I mean I couldn’t see GET, POST, DELETE, PUT declarations in the code.

  3. Hi Ricky,

    Great blog – been going through them for a project of mine – and found them to be very informative.. thank you!

    I was wondering if you have encountered the following problem – and suggestions on how to solve it:

    Problem: How to translate local (x,y) from a floor map into a point in the bing-map-custom-tile map.

    Background:
    I have a floor plan, with a resolution of 1 meter/pixel. I generated tiles using MapCruncher and made it show up in Bing-Silverlight-map. (Zoom level=19)

    Now, I have a path description of: StartXY:(2,5), EndXY:(10,40).

    I would like to draw a line between StartXY and EndXY in the map…

    Any ideas?

    Thank you,

    Ravi

    • This can be done although it would require a decent amount of math. Most of the math you will need can be found here: http://msdn.microsoft.com/en-us/library/bb259689.aspx The key thing to note is for every zoom level a pixel represents about twice the distance as the previous zoom level. Since you are working with a floor plan the distances will be relatively small so you won’t need to worry too much about the curvature of the earth and can use flat 2D math once you translate your reference point and resolution.

      I’m assuming all your data was created at a specific resolution (1 m/pixel). Based on this I would suggest the following. At a zoom level calculate the ground resolution of the map. Use this to scale your data to fit this resolution. (should be a simple multiplication). Then use the LatLong to Pixel method in the link I provided on your reference point to get the global pixel coordinate of your reference point. Then use this global pixel as an offset to your data to get global pixel coordinates for your data. Then use Pixel to latlong function to convert this data into usable coordinates that can be overlaid on the map.

      • Hi Ricky,
        Thank you so much for the quick response. I tried out your recommendations – and was able to get my floor plan onto the bing map!!!!

  4. Pingback: Using Bing Maps in WinForms - Ricky's Bing Maps Blog - Site Home - MSDN Blogs

  5. Pingback: Bing Maps REST Service Tips & Tricks - Ricky's Bing Maps Blog - Site Home - MSDN Blogs

  6. I’m newbie using Bing Maps. I’m investigating about it.

    Any full source code samples using Bing Maps API, GeocodeSErvice and Windows Forms ?

  7. Great post. Thank you.
    I have list of geo coordinates (latitudes and longitudes ) , how do I obtain a route path map/image using these list of coordinates ? Thanks.

    • Simply use those as way points for a route. If you have more than 25 points you will need to calculate multiple routes. If the data you have is already the hi-definition line of a route then simply overlay it on the map as a Polyline.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s