WP7 Contrib – Bing Service Wrapper Part I – Location

This being the first post about the Wrappers I thought that we should break the ice with the most commonly used service. Location. Out of all of the services this is the simplest to call but also we would suspect the most widely used. When you combine this service with the device location based WP7C bits then you can build your geo location aware app and have it plotting to a map and moving in real-time, or you could be helping your user to find the location of an address.

In the sample for using the location service we tackle both of these scenarios.

So, I am going to jump straight in here and assume that you have either looked at the sample in the Spikes folder of the WP7 Contrib (WP7C) or you have some experience of using the Rest API provided by the Bing Maps endpoint. If you have not done this then I would suggest opening up the sample and taking a quick look at the Location View Model, its pretty straight forwards so you should be back in 10.

First off if you have not already created a project then you need too. If you are using MVVM and some sort of DI library cool, if not no worries. There are two different options provided by the Location Service from the Bing REST API; you can either use the Geo Coordinate Location of the device and pass this to the service in order to give you back a current address; or you can enter a location to find out what Geo Coordinate Location is.

If you are not already using the WP7C components in you app (shame on you J) then you need to add a couple of references in order to get this up and running, these include:-

  • WP7Contrib.Services
    • BingMaps
    • BingMaps.Model
    • Location

These are the basic bits that you need to get your geo location app up and running. Once we have included those assemblies then we need to define the interfaces we want to use and the data objects that correspond to the location service calls.

First up we need to declare the private fields so let’s go ahead and do that

private readonly IBingMapService bingMapService;
private readonly ILocationService locationService;
private LocationRect boundingRectangle;
private GeoCoordinate currentDeviceGeoCoordinate;
private IDisposable currentLocationObserver;
private RelayCommand selectFindMyCurrentLocationCommand;
private RelayCommand selectFindGeoLocationFromAddressCommand;
private Address address;
private LocationData locationDataByPoint;

 

Next, we need to create a constructor for our VM. You will notice that not only am I using the ILocationService which is the WP7C’s Rx location component but we are also going to pass in a IBingMapService which is our wrapper that we will use to call the REST services. The other interfaces that I am using here are the navigation service and the logging component from WP7C.

public LocationViewModel(
INavigationService navigationService,
ILocationService locationService,
IBingMapService bingMapService,
ILog log)
: base(navigationService, log)
{
this.locationService = locationService;
this.bingMapService = bingMapService;
this.address = new Address {CountryRegion = "UK", PostalCode = "LE17 5ER"};
}

 

Currently, and this is consistent across all of our samples we are using Funq as our DI framework of choice, its light and simple which is why it’s great for WP7, we are not bound to Funq in anyway so if you want to use your Favourite DI then you can do so.

With our constructor defined we need to go ahead and do our register and resolve in the bootstrapper.

There is quite a bit of stuff happening in the bootstrapper, mainly because of the fact that we are taking advantage of the different components inside of the WP7C, now you don’t have to use these however if you need things like logging; want to store data; and if you have a design where you are not loading all the VM’s upfront take a look at the Last Message Replay. As this is the first in a series of posts we can deconstruct what is happening here in the future articles I will only reference this section.

The code below setups the Logging bits for us.

this.Container.Register<ILogManager>(c => new LoggingService("BingMaps"));
this.Container.Register<ILog>(c => this.Container.Resolve<ILogManager>());
<p>var logManager = this.Container.Resolve<ILogManager>();
logManager.Enable();

 

Here we setup the settings for the app and assign the key that we want to use for bing maps. The registered key in the code is registered to the WP7C so I would advise that you register, it does not take long and the key is generated instantly.

this.Container.Register<IStoreSettings>(c => new SettingsStore(this.Container.Resolve<ILog>()));
this.Container.Register<ISettings>(c => new Settings("Bing Key"));
var serialisationAssemblies = new List<Assembly> { this.GetType().Assembly };

 

Setup the cache provider and initialise it.

this.Container.Register<ICacheProvider>(c => new  IsolatedStorageCacheProvider("BingMaps", serialisationAssemblies,  c.Resolve<ILog>()));
var cache = this.Container.Resolve<ICacheProvider>();
System.Threading.ThreadPool.QueueUserWorkItem(state => cache.PreemptiveInitialise());

 

Setup the last replay messenger.

this.Container.Register<IMessenger>(c => new LastMessageReplayMessenger());

 

Setup the WP7C Navigation Service.

this.Container.Register<INavigationService>(

c => new ApplicationFrameNavigationService(((App)Application.Current).RootFrame));

 

Setup the WP7C Network service

this.Container.Register<INetworkService>(c => new NetworkMonitor(5000));

 

Setup the WP7C Storage service.

var assemblies = new List<Assembly> { this.GetType().Assembly, typeof(BaseModel).Assembly };
this.Container.Register<IStorageService>(c => new StorageService(assemblies, c.Resolve<ILog>()));

 

As we are using the Resource Client from WP7C we also need to add this setup code into our bootstrapper.

this.Container.Register<IEncodeProperties>(c => new UrlEncoder());
this.Container.Register<IHandleResourcesFactory>(c => new ResourceClientFactory(c.Resolve<ILog>()));

 

The final part is that we need to wire in the IBingMapService which needs to be resolved using some of the interfaces that we registered earlier.

this.Container.Register<IBingMapService>(c => new BingMapService(
c.Resolve<IHandleResourcesFactory>(),
c.Resolve<IEncodeProperties>(),
c.Resolve<ICacheProvider>(),
c.Resolve<ISettings>(),
c.Resolve<ILog>()));

 

Ok, so we nearly have, all of the underlying plumbing done what we need to do next is to setup the VM locator. If you need more details on this please refer to the sample code. Once you have the VM locator updated we can go ahead and bind our Data Context up to the VM using the service locator pattern in Xaml.

As I mentioned at the start of this article, the UI’s are more about form and function, so our intentions are purely to visualise all the different types of data coming back from the service. So, for this we went with simple UI controls to make sure that the data being returned from our request is correct.

Now, that we have the plumbing in place, and some simple UI that displays the responses, our next step is to make our requests out to the Bing Services. This code is going to live in the VM.

The first thing on our list to implement is that we need to make our app location aware, everything you need to do this is already baked in the WP7C, it just requires a simple bit of Rx to get it wired in. In order to do this we need to leverage the ILocation Service that we injected into the VM as this will find out what our current location is.

private GeoCoordinate currentDeviceGeoCoordinate;
private IDisposable currentLocationObserver;
private void ExecuteSelectFindMyCurrentLocationCommand()
{
try
{
this.currentLocationObserver =
this.locationService.Location()
.ObserveOnDispatcher()
.Subscribe(geoCoordinate =>
{
this.CurrentDeviceGeoCoordinate = geoCoordinate;
this.SearchForLocation(this.BuildLocationSearchForPoint());
});
}
catch (Exception exn)
{
MessageBox.Show(string.Format("Failed! Message - '{0}", exn.Message), "Location Search",                MessageBoxButton.OK);
}}

 

Notice in the subscribe how we are assigning a value to the VM’s Current Device Geo Coordinate Property which is bound up in the view; also note that we are then doing a Search for a geo location and passing into this method the result from the Build Location Search For Point. We decided that in order for us to wrap up all the services and provide a common API from which users can use the services we would adopt a factory style pattern. So, what’s going on in the Build method? Well here we are calling out to the factory and asking it to create what we need in order to query the Bing services for dealing with the request.

private ILocationSearchPointCriterion BuildLocationSearchForPoint()
{
return CriterionFactory.CreateLocationSearchForPoint(this.CurrentDeviceGeoCoordinate);
}

 

And that is all you need to add location awareness to your app, I hope that you agree with me that this is rather straight forwards. Next up we need to build out the search for location method, which is going to use the Bing wrapper service from the WP7C to search for a location. If you have looked over the code you will see that we have 2 overloaded methods, one which deals with Geo Location and the other which deals with addresses.

private void SearchForLocation(ILocationSearchPointCriterion criterion)
{
this.bingMapService.SearchForLocationUsingPoint(criterion)
.ObserveOnDispatcher()
.Subscribe(this.ProcessSearchLocationByPointResponse,
FailedSearch,
CompletedSearch);
}

 

And for completeness I have included the code for the address mechanism below.

 

private void SearchForLocation(ILocationSearchAddressCriterion criterion)
{
this.bingMapService.SearchForLocationUsingAddress(criterion)
.ObserveOnDispatcher()
.Subscribe(this.ProcessSearchLocationByAddressResponse,
FailedSearch,
CompletedSearch);
}

 

Note that there are a couple of differences between the overloads; first the interface type that we are passing into our method for locations we always need to use the ILocationSearchPointCriterion and for addresses we need to use the ILocationSearchAddressCriterion; and the other difference is that we use a different method to deal with the response that we get sent from the Bing Services.

private void ProcessSearchLocationByPointResponse(LocationSearchResult result)
{
if (result == null)
{
return;
}
if (result.Locations.Count != 0)
this.LocationDataByPoint = result.Locations[0];
}

In order to successfully process the data and then work on this data the WP7C provides you with the data transformation classes that you need and does all the map and wrap code so that you don’t have to. In the code above this is illustrated by our use of the LocationDataByPoint property which uses the Location Data class from the WP7C, we are using databinding in the view and wiring up to this property from the VM .

So, just to recap what we have covered are a couple of things here; first we made our app Geo Location aware by using the WP7C Rx location service; which was then wired up to the Bing Services Wrapper and we used this to provide an address of the device’s current location; and for completeness we provide a way for the user to enter details of an address and the app responds with a Geo Location that corresponds to the address.

Admittedly we are doing some simple tasks here however its super important that we put in the ground work so that you can gain a deep understanding of how the wrappers work. We would really like to hear your feedback, if you have built an app using the Bing services we would also be interested in talking to you about your sceanrios.

In the next post I will dig into using the Route Service.

Ollie has some deep dive blog posts planned which are based around the patterns that he is using along with some gems of information around using Rx with these more traditional patterns so watch out for those.

Enjoy!

 

 

 

 

 

 

Be Sociable, Share!

Tags: , , , ,

2 Responses to “WP7 Contrib – Bing Service Wrapper Part I – Location”

  1. [...] WP7 Contrib – Bing Service Wrapper Part I – Location (Rich) [...]

  2. [...] up we need to declare the private fields so let’s go ahead and do that view sourceprint? 01.private readonly IBingMapService bingMapService; 02.private readonly ILocationService [...]


Leave a Reply