Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Bing Maps in SharePoint 2010 Web Part

0.00/5 (No votes)
17 May 2010CPOL5 min read 55.3K   827  
This article shows how to create a simple web part in SharePoint 2010 and use Bing Maps service to render maps.

Introduction

This article walks you through creating a custom web part for SharePoint 2010 and renders Bing Map in it. Here are some of the few pre-requisites:

  1. You must be familiar with basic SharePoint 2010 functionality
  2. You must have Visual Studio 2010 with SharePoint extensions installed
  3. You must have read Sample WPF application consuming Bing Maps Web Services. This article will walk you through how to create a Bing Maps account and the basic services Bing Map exposes.

You should expect your web part to look something like this:

Snapshot.jpg

Using the Code

The code is divided into the following components:

  1. BingMapsWebPart - This is the actual web part that will hold code to invoke helper methods defined in BingMapHelper (see below).
  2. BingMapNav.ascx - This user control will provide navigation buttons for the map. The buttons include zoom in/out, pane left/right/top/bottom.
  3. BingMapHelper.cs - This class has helper methods that invoke Bing Map services.

In Visual Studio 2010, create a new Visual Web Part project. Alternately, you could just open the code that is in the attached zip file:

01_New_Project.jpg

Visually, here is how the project is structured:

03_Project_Structure.jpg

BingMapHelper.cs

We will start with the BingMapHelper.cs. This class exposes two methods, viz - GeocodeAddressGeocodeResponse and GetImagery. GeocodeAddressGeocodeResponse is basically translating the English like address to GeocodeResponse (longitudes and latitudes). The code is pretty simple. You create an instance of GeoCodeService, set your credentials (the key that you get from your bing account), set the address as its filter and future Geocode() method. Here is how the code looks like:

C#
public static GeocodeResponse GeocodeAddressGeocodeResponse(string address)
{
    GeocodeRequest geocodeRequest = new GeocodeRequest();
    // Set the credentials using a valid Bing Maps key
    geocodeRequest.Credentials = new GeocodeService.Credentials();
    geocodeRequest.Credentials.ApplicationId = key;

    // Set the full address query
    geocodeRequest.Query = address;

    // Set the options to only return high confidence results 
    ConfidenceFilter[] filters = new ConfidenceFilter[1];
    filters[0] = new ConfidenceFilter();
    filters[0].MinimumConfidence = GeocodeService.Confidence.High;

    // Add the filters to the options
    GeocodeOptions geocodeOptions = new GeocodeOptions();
    geocodeOptions.Filters = filters;
    geocodeRequest.Options = geocodeOptions;

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

Next, let's look at the GetImagry() method. This method receives longitude, latitude and the zoom level and passes them as the param to ImageryService. The concept of invoking the service is very similar to the ones mentioned above. You create an instance of ImageryService, set credentials and then set the parameters of MapUriRequest object. Here is how the code looks like:

C#
static string GetImagery(double latitude, double longititude, int zoom)
{
    MapUriRequest mapUriRequest = 
	new MapUriRequest();// Set credentials using a valid Bing Maps key 
    mapUriRequest.Credentials = new ImageryService.Credentials();

    mapUriRequest.Credentials.ApplicationId = key;
    new ImageryService.Credentials();// Set the location of the requested image 
    mapUriRequest.Center = new ImageryService.Location();

    mapUriRequest.Center.Latitude = latitude;

    mapUriRequest.Center.Longitude = longititude;
    new ImageryService.Location();// Set the map style and zoom level 
    mapUriOptions.Style = MapStyle.AerialWithLabels; 

    mapUriOptions.ZoomLevel = zoom;
    MapUriOptions mapUriOptions = 
	new MapUriOptions();MapStyle.AerialWithLabels;// Set the size of the 
						// requested image in pixels 
    mapUriOptions.ImageSize = new ImageryService.SizeOfint();
    mapUriOptions.ImageSize.Height = 400;
    mapUriOptions.ImageSize.Width = 500;
    mapUriRequest.Options = mapUriOptions;
    new ImageryService.SizeOfint();

    //Make the request and return the URI
    ImageryServiceClient imageryService = new ImageryServiceClient();
    MapUriResponse mapUriResponse = imageryService.GetMapUri(mapUriRequest);
    return mapUriResponse.Uri;
}

BingMapWebPart

Once you have this class ready, you are all set to create your web part. In order to do that, just right click the project -> Add new item -> Visual web part. Name this as BingMapsWebPart.

The HTML part of the web part is very simple. Just a label, text box and button to make a call to maps service. Below that, we have an image which will render the map and below that, we have the user control for the navigation:

ASP.NET
<asp:updatepanel runat="server">
    <ContentTemplate>
        <table width="100%" height="500px">
        <tr height="30px" valign="top">
            <td align="center" height="30px">Enter address 
                <asp:textbox runat="server" ID="txtAddress" ValidationGroup="BingMapsWP" 
                Width="300px">Space Needle, WA</asp:textbox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" 
                ControlToValidate="txtAddress" ErrorMessage="* Required" 
                ValidationGroup="BingMapsWP"></asp:RequiredFieldValidator>
            </td>
        </tr>
        <tr height="40px" valign="top">
            <td align="center" height="30px">
                <asp:Button ID="btnGetMap" runat="server" Text="Get Maps" 
                ValidationGroup="BingMapsWP" onclick="btnGetMap_Click" />
                <br />
                <asp:Label ID="lblError" runat="server" Text=""></asp:Label>
            </td>
        </tr>
        <tr>
            <TD align="center">
                <asp:image runat="server" ID="mapImage" Visible="False"></asp:image>
            </TD>
        </tr>
        <tr height="30px">
            <td align="center">
                <uc1:BingMapNav ID="BingMapNav1" runat="server" />
            </td>
        </tr>
        </table>
    </ContentTemplate>
</asp:updatepanel>

Notice how we have kept the entire table inside an update patel. This helps in improving the user experience a bit by not flicking the page when you do any action (click of button).

The code behind of this control is very simple. There are mainly three sections:

  1. Code that runs click of button and invokes help method to get map: Here is how the code looks like:
    C#
    protected void btnGetMap_Click(object sender, EventArgs e)
    {
        lblError.Visible = false;
        try
        {
            //Get map
            GeocodeResponse resp = 
    		BingMapHelper.GeocodeAddressGeocodeResponse(txtAddress.Text);
            latitude = resp.Results[0].Locations[0].Latitude;
            longititude = resp.Results[0].Locations[0].Longitude;
            //Get URI and set image
            mapImage.ImageUrl = BingMapHelper.GetImagery(latitude, longititude, zoom);
            //Show image
            mapImage.Visible = true;
        }
        catch (Exception ex)
        {
            lblError.Visible = true;
            lblError.Text = ex.Message + "<BR>" + ex.StackTrace;
        }
    }        
  2. Code that gets/sets the longititude, latitude and zoom level in view state.
  3. Code that does some action when the navigation buttons are clicked: In order to get the required zoom in or out, or pane effect, we will store the current longitude, latitude and zoom level in view state, whenever user clicks a button, we will update one of the three properties. E.g. if user clicks on scroll left button, we will reduce the longititude by 0.2.

BingMapNav.ascx

This is a little control that helps in nevigation. This is nothing but 6 buttons for zoom in/out, and panning to left/right/top/bottom. These buttons would just fire an event and the master user control would do operations based on the click.

Deployment

VSTS 2010 makes deployment of a SharePoint object a breeze. All you have to do is right click the project in solution explorer and click "Deploy".

02_Deploy.jpg

No more painful way of authoring XML files and using 10 commands to install a simple web part. VSTS does it for you. Smile

But there is one thing that you will have to do, that is to specify the WCF settings in the web.config of your web app. In order to locate the web.config, you should go to IIS, select the web app you want to update and right click -> Explore. Once there, you will see web.config. Add the following section into the web.config under configuration->system.ServiceModel.

XML
<bindings>
   <basicHttpBinding>
     <binding name="BasicHttpBinding_IGeocodeService"
     closeTimeout="00:01:00" openTimeout="00:01:00"
     receiveTimeout="00:10:00" sendTimeout="00:01:00"
     allowCookies="false" bypassProxyOnLocal="false"
     hostNameComparisonMode="StrongWildcard"
     maxBufferSize="65536" maxBufferPoolSize="524288"
     maxReceivedMessageSize="65536" messageEncoding="Text"
     textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
       <readerQuotas maxDepth="32" maxStringContentLength="8192"
     maxArrayLength="16384" maxBytesPerRead="4096"
     maxNameTableCharCount="16384" />
       <security mode="None">
         <transport clientCredentialType="None" proxyCredentialType="None" realm="">
           <extendedProtectionPolicy policyEnforcement="Never" />
         </transport>
         <message clientCredentialType="UserName" algorithmSuite="Default" />
       </security>
     </binding>
     <binding name="BasicHttpBinding_IImageryService"
     closeTimeout="00:01:00" openTimeout="00:01:00"
     receiveTimeout="00:10:00" sendTimeout="00:01:00"
     allowCookies="false" bypassProxyOnLocal="false"
     hostNameComparisonMode="StrongWildcard" maxBufferSize="65536"
     maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
     messageEncoding="Text" textEncoding="utf-8"
     transferMode="Buffered" useDefaultWebProxy="true">
       <readerQuotas maxDepth="32" maxStringContentLength="8192"
     maxArrayLength="16384" maxBytesPerRead="4096"
     maxNameTableCharCount="16384" />
       <security mode="None">
         <transport clientCredentialType="None" proxyCredentialType="None" realm="">
           <extendedProtectionPolicy policyEnforcement="Never" />
         </transport>
         <message clientCredentialType="UserName" algorithmSuite="Default" />
       </security>
     </binding>
   </basicHttpBinding>
 </bindings>
 <client>
   <endpoint address=http://dev.virtualearth.net/webservices/v1/geocodeservice/
 GeocodeService.svc">http://dev.virtualearth.net/webservices/v1/
 geocodeservice/GeocodeService.svc binding="basicHttpBinding"
 bindingConfiguration="BasicHttpBinding_IGeocodeService"
 contract="GeocodeService.IGeocodeService"
 name="BasicHttpBinding_IGeocodeService" />
   <endpoint address=</a />"

Testing

Once you have the web part deployed, go to your SharePoint site's page where you want to add this web part. Once there, click on edit page and select your web part from the web part gallery.
Note: New web part will appear under "Custom" category. Once you have added this web part, just play with it by entering various addresses and using the navigation buttons.

Points of Interest

I took a while to figure out how to let my webpart konw how to read the WCF configuration. Finally, I ended up keeping it in web.config of the web app. Do let me know if you think there is a better place to keep it.

The panning logic is a little off. When you hit the pane left/right/top/bottom, I just update the co-ordinates by 0.2. I should have considered zoom level by offseting the co-ordinates, but I would leave that to you.

The last thing I want to point out is that this is a very primitive looking web part. It does not have drag and drop feature, nor can it change between street view and it cannot do dozens of other things I want it to do. You are more than welcome to extend it.

History

  • 17th May, 2010: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)