Repairing the Windows Phone 7 behavior to show an image background for a search string
On the last day of 2011 ago I made DynamicBackgroundBehavior - a quite bizarre behavior which plays a supporting role in my latest Windows Phone application “What’s cooking”. It basically shows a picture from a search string as a background, using Bing Image search. Quite neat. Until Microsoft decided to change the Bing Search API a bit. Up until then, it had been a free unlimited ride – since about August you have to buy a package of searches (anything below 5000 searches per month is free). And some more stuff has been changed.
Microsoft provides a nice little C# client library that should solve all of this using an OData protocol. The sad thing is that for the life of it I could not get it to compile on Windows Phone. So I ended up analyzing the PHP (*shudder*) sample in this document – a Word document no less – to see what I needed to do (see page 27 and further).
From a coding perspective, the following details have been changed:
- The actual location of the API has been changed from http://api.bing.net/xml.aspx to https://api.datamarket.azure.com/Data.ashx/Bing/Search/v1/Image
- The schema of the MediaUrl element where the actual image in is returned moved from name space http://schemas.microsoft.com/LiveSearch/2008/04/XML/multimedia to name space http://schemas.microsoft.com/ado/2007/08/dataservices
- It uses an account key in stead of an App id.
- The App Id must be send base 64 encoded in the header of the request in stead of in the url as plain text.
Okay. My cheese moved a little. First things first. I need base64 encoded text. Samples of this are on the internet a dime a dozen, I took this one:
/// <summary> /// Converts string to base64 /// </summary> /// <param name="data"></param> /// <returns></returns> private string Base64Encode(string data) { try { var encData_byte = new byte[data.Length]; encData_byte = System.Text.Encoding.UTF8.GetBytes(data); return Convert.ToBase64String(encData_byte); } catch (Exception e) { throw new Exception("Error in Base64Encode" + e.Message); } }
Now the method that does the actual calling of the Bing Search API has changed a little, but not very much:
/// <summary> /// Start the image request using Bing Serach /// </summary> /// <param name="searchString"></param> protected void StartGetFirstImage(string searchString) { if (!string.IsNullOrWhiteSpace(searchString)) { var queryUri = string.Format( "https://api.datamarket.azure.com/Data.ashx/Bing/Search/v1/Image?Query=%27{0}%27&$top=1&$format=Atom", HttpUtility.UrlEncode(searchString)); var request = WebRequest.Create(queryUri) as HttpWebRequest; request.Headers["Authorization"] = "Basic " + Base64Encode(string.Format("{0}:{0}", BingSearchKey)); var response = Observable.FromAsyncPattern<WebResponse>( request.BeginGetResponse, request.EndGetResponse)(); response.Subscribe(WebClientOpenReadCompleted, WebClientOpenReadError); } }
Note the new url. It goes to a different location, the search term must be enclosed by %27 (i.e. the double quote “) and I have to specify a format (Atom). Really interesting is the thing I marked red, for a variety of reasons:
- Windows Phone’s Response.Headers collection does not sport the Add method. That stopped me a little, until I realized you could poke directly a new key in the collection by using [“Autorization”] =.
- Now the authentication is Basic, followed by a space, your account key, colon, your key again and that key:key sequence needs to base 64 encoded. Why this is implemented this way – no idea, but it gets your key across – and validated.
The final thing is that in the callback WebClientOpenReadCompleted I need to use “http://schemas.microsoft.com/ado/2007/08/dataservices” for a namespace,as I already stated.
And then my little Windows Phone behavior works again. The fixed version can be downloaded here. I will fix my #wp7nl library on codeplex ASAP.