WP7 Rest … The Easy Way

Over and over again, I see developers that have this great idea for an application that pulls cool data from a  great services BUT get tied up in the implementation of “Getting It Done”.  So I thought I would show you a quick and easy way to get REST data from a service, transfer the JSON data to a POCO list and Bind it to a listbox.  (In under 3 minutes)

On your Mark

Get Set

Go.

The first think you need to do is find some Data that is interesting to you.  For me, I LOVE coffee so I want to create an application that shows me all the coffee places that are near to me.  I can do this using Bing Search  http://msdn.microsoft.com/en-us/library/dd251014.aspx 

Specifically, I am going to use the PhoneBook Request part of the API that is like a Yellow Pages API.  It will give me all the business that designate themselves as “Coffee” places.

(Yes I know I am not using MVVM)

The first thing I do is Create a method called GetData() and call it from my MainPage() Constructor

  public MainPage()
        {
            InitializeComponent();
            GetData();
        }

        private void GetData()
        {
            string uri = "http://api.bing.net/json.aspx?AppId=YOUR_APP_ID&Version=2.0&Market=en-US&Query=Coffee&Sources=phonebook&latitude=33.8563&longitude=-118.1232";
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(uri));
            request.BeginGetResponse(new AsyncCallback(ReadCallback), request);

        }

In GetData() the first thing I do is make a call to the BING  API. 

The first part of the call shows that I want json returned and supplies my App_ID (Removed from post)  ( You can get your own Bing API key here http://msdn.microsoft.com/en-us/library/dd251020.aspx )

http://api.bing.net/json.aspx?AppId=YOUR_APP_ID

Next I set the version, Market, and what I am looking for

&Version=2.0&Market=en-US&Query=Coffee&

And finally, I tell it I am looking at the phonebook part of the API and where I want to search… In this example I am hardcoding the lat/long but you would of course use the Geo Location from the phone, but I wanted to keep this simple.

Sources=phonebook&latitude=33.8563&longitude=-118.1232";

Next, We then need to make the call to the service.  We will use a HttpWebRequest by passing it the URI we just created

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(uri));

And then making in the call and supplying it the CallBack method (Where the call returns to when it is finished)

request.BeginGetResponse(new AsyncCallback(ReadCallback), request);

Now here is the fun part. To work with the JSon data the is returned from this query, we need to create the class structure that represents the data…….. ugggggg what a pain right?   Nope Wrong, All we need to do is use http://json2csharp.com/    Just paste in either the JSon returned OR the URI String, and it will create the classes for you. So when I paste in my URI String above, it gives me the following.

(you can, of course, break up these classes into separate files but for now, I just pasted them at the bottom of the MainPage.xaml.cs file.)

 

public class Query
    {
        public string SearchTerms { get; set; }
    }

    public class Result
    {
        public string Title { get; set; }
        public string Url { get; set; }
        public string Business { get; set; }
        public string PhoneNumber { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string StateOrProvince { get; set; }
        public string CountryOrRegion { get; set; }
        public string PostalCode { get; set; }
        public double Latitude { get; set; }
        public double Longitude { get; set; }
        public string UniqueId { get; set; }
        public string DisplayUrl { get; set; }
    }


    public class Phonebook
    {
        public int Total { get; set; }
        public int Offset { get; set; }
        public string LocalSerpUrl { get; set; }
        public string Title { get; set; }
        public List<Restuarnt> Results { get; set; }
    }

    public class SearchResponse
    {
        public string Version { get; set; }
        public Query Query { get; set; }
        public Phonebook Phonebook { get; set; }
    }

    public class RootObject
    {
        public SearchResponse SearchResponse { get; set; }
    }

Now that you have the classes that hold the json that is returned, all you need to do is create the ReadCallback Method (Defined above)

private void ReadCallback(IAsyncResult asynchronousResult) 
        { 
            HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState; 
            HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult); 
            using (StreamReader streamReader1 = new StreamReader(response.GetResponseStream())) 
            { 
                string resultString = streamReader1.ReadToEnd(); 
                var ser = new DataContractJsonSerializer(typeof(RootObject));

                var stream = new MemoryStream(Encoding.Unicode.GetBytes(resultString));
                DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(RootObject));
                RootObject myBook = (RootObject)jsonSerializer.ReadObject(stream);
              
                

                Deployment.Current.Dispatcher.BeginInvoke(() => coffeeShops.ItemsSource = myBook.SearchResponse.Phonebook.Results); 
                
            } 
        }

You can see that we use a stream reader to read the results and then use a DataContractJsonSerializer to add the data to the RootObject (Root Object is one of the classes that were created for us that encapsulates all the others)

On the last line, I marshall the data to the UI thread using Dispatcher.BeginInvoke and bind it to a ListBox called coffeeShops.

That’s IT….

Now it took me 30 minutes to write this up, but it should take you only 3 minutes to implement.

Enjoy Smile

The Web Role was started in a wrong port

imageOne of the great things about Windows Phone is all of the samples that are out there.  And topping them all is the Windows Azure Toolkit for Windows Phone 7 .  The toolkit gives you everything you need to develop a Windows Phone application using Windows Azure. I will do a full post walkthrough of using the toolkit, but I thought I would post about one thing that seems to be tripping people up when they are trying to get things up and running.

If you start the project and get the error Sorry, an error occurred while processing your request, the web role was started in a wrong port, You might scratch your head.  If you peek at the url you will notice that it is running on port 444 instead of 443

image

The reason it is doing this is because if it does not find port 443 open, it will increment by one until it finds an open port. If you look in your compute emulator you will also see the wrong port. Which is the reason it says The web role was started in a wrong port.  Because it was :)

image

So now, to fix this you want to see what is running on port 443.  To do this open a cmd window and type in the following netstat –aon

This will bring up a list of what is running on each port.

image

You want to look for anything that has a :443 at the end of it and look at the last column.  This is the process ID for the process that is using that port.

Next, open up Task Manager and look for the process ids that you found. ( You may need to go to View –> Select Columns first to add the PID column)

 

image

My offending applications were:

  • SQL Reporting Services (Which I shut down in Services)
  • TweetDeck
  • Skype

That fixed it for me… hope that helps

Daniel

WP7 Isolated Storage Snapshots

 

When working with Isolated Storage on the phone you sometimes have difficulty “seeing” what is located in the IsoStore for your application.  Luckily we have a tool that will help you take snapshots of the Sandboxed Isolated Storage for your application.  It is a command line tool called ISETool.exe and it is located in:

(for 32 bit os) c:\Program Files\Microsoft SDKs\Windows Phone\v7.1\Tools\IsolatedStorageExplorerTool

(for 64 bit) c:\Program Files (x86)\Microsoft SDKs\Windows Phone\v7.1\Tools\IsolatedStorageExplorerTool

To run the tool, bring up a command line and change the directory to the location above.

 

image

Then run the ISTool.exe with the following parameters

◦ts – take snapshot  (rs for restore)
◦xd – emulator
◦guid – product GUID from WPAppManifest.xml
◦desktop dir – where to copy the isolated storage files

image

 

It will download the contents of your Isolated Storage for that application to the folder you specified

image

 

You can also restore to the phone or emulator by doing the reverse.

ISETool.exe rs xd 11111111-2222-3333-4444-555555555555 “C:\snapshots\IsolatedStore”

 

This can also be used for local databases as well as restoring your environment to a specific state.  Let me know if you have any questions.

 

Camera Picture by Capt Kodak flickr cc

Windows Phone Alerts and Reminders

Another great feature for Windows Phone Mango is the ability to set up reminders and alerts in your application (While it is not running).  You would be surprised how many applications want/need this. During our Windows Phone 7 Unleashed events this was a recurring topic. 

The great part is that it is really simple.

 

 

imageFor this application, we are creating a very basic interface.  A text box for the title, a text box for the reminder message and a button that says “remind me”.  In addition, there is a label to hold the parameter that is sent back from the reminder.

The first thing you want to do once you build the UI is to click on the Remind Me button to create the click event for the button and add the following code to the event.

 private void OnRemindMeClick(object sender, RoutedEventArgs e)
        {
            Reminder r = new Reminder("reminder"); 
            r.Title = txtTitle.Text; 
            r.Content = txtContent.Text; 
            r.BeginTime = DateTime.Now.AddSeconds(10); 
            r.NavigationUri = new Uri("/MainPage.xaml?reminder=" + 
txtContent.Text ,UriKind.Relative); ScheduledActionService.Add(r); }

All we need to do is :

  • create an instance of the reminder
  • Set the title and content to the text boxes text property
  • set the begin time (in this instance I am doing it in 10 seconds from now)
  • Set the NavigationUri (this is where you will return when a user clicks on a message)
  • Add the reminder to the ScheduledActionService

Notice that we are passing the txtContent.Text back to the program when the user replies.  This can be userIDs, itemIDs, etc… .  Whatever makes sense for your program.

To capture the returning data, add this to an onNavigatedTo override.

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            string param = null;
            if (NavigationContext.QueryString.TryGetValue("reminder", out param))
                Param.Text = param;

            if (ScheduledActionService.Find("reminder") != null)
                ScheduledActionService.Remove("reminder");

        }

We collect the reminder parameter from the Querystring and set it equal to our Param.txt . Notice that we are also removing the reminder from the service.  In the way ours is constructed, if the user clicked on it a second time it would try to add “reminder” a second time which is not allowed.

There you go…. easy as pie Smile

 

(Clock picture from “H is for Home on Flickr” Creative Commons)

Background Agents in WP7

With the release of Windows Phone 7 Mango, you now have the ability to multitask (scheduled multitask) by using background agents.  Background agents allow you to do things when your application is not running. 

 

It is important to understand that the OS is responsible for determining when your background agent can run and is determined by a number of factors. It is also dependent on the type of Background Agent you use.

 

For both types of Agents you are constrained by the following :

Periodic Agents (PeriodicTask) are used when you want a “seimi” predictable action to fire.  But they are constrained to the following. For example, you can use Periodic Agents for collecting quick GPS coordinates or updating an RSS feed.

  • 30 Minute Intervals (this time may drift)
  • Run for 25 seconds
  • Might not run on Battery Saver mode
  • Agents per device (The number of apps using agents) can be as low as 6 on some devices

Resource-intensive Agents (resourceIntensiveTask) can be used for more intensive items like downloading larger files or coping database entries to a replication server. But you must keep in mind that they have some specific constraints as well.

 

  • Duration 10 Minutes
  • External Power Required (You need to plug it in)
  • Connection through WiFi or PC
  • Battery 90% or better
  • Screen Lock on
  • No active phone call

What this means is that it MAY never run.  The best case scenario is the user will have their phone connected to their WiFi when they plug it in at night.

But …. after all of that, it is pretty easy to use.  All you need to do is

  • Add a ScheduledAgentTasks project to your solution
  • Add a reference to the agent project in your phone application project
  • Add your code to the Invoke Method in the ScheduledAgentTasks project as shown below

 protected override void OnInvoke(ScheduledTask task)
        {
            //TODO: Add code to perform your task in background
            string toastMessage = "";

            // If your application uses both PeriodicTask and ResourceIntensiveTask
            // you can branch your application code here. Otherwise, you don't need to.
            if (task is PeriodicTask)
            {
                // Execute periodic task actions here.
                toastMessage = "Periodic task running.";
            }
            else
            {
                // Execute resource-intensive task actions here.
                toastMessage = "Resource-intensive task running.";
            }

            // Launch a toast to show that the agent is running.
            // The toast will not be shown if the foreground application is running.
            ShellToast toast = new ShellToast();
            toast.Title = "Background Agent Sample";
            toast.Content = toastMessage;
            toast.Show();

            // If debugging is enabled, launch the agent again in one minute.
#if DEBUG_AGENT
  ScheduledActionService.LaunchForTest(task.Name, TimeSpan.FromSeconds(60));
#endif

            // Call NotifyComplete to let the system know the agent is done working.
            NotifyComplete();
        }

 

The one caveat is that it can sometimes be difficult to debug in an emulator.  If you have a developer phone you will have a much easier time debugging it on the device.  If you have any questions, let me know.

Windows Phone testing for sensors

If you are planning on using the new sensors that are in the Windows Phone code named Mango (Gyroscope, Compass, etc…), you need to add some code to your application to test and see if they are available.  You can use the Microsoft.Devices.Sensors namespace to find this out.

 

bool IsGyroSupported = Microsoft.Devices.Sensors.Gyroscope.IsSupported;

bool IsAccelerometerSupported = Microsoft.Devices.Sensors.Accelerometer.IsSupported;

bool IsCompassSupported = Microsoft.Devices.Sensors.Compass.IsSupported;

bool IsMotionSupported = Microsoft.Devices.Sensors.Motion.IsSupported;
 
The Motion Sensor is the API that combines all the other sensors and adds some math to
make it easier to build your application using sensors.

Get Network Info on Windows Phone

When you are developing your application, you keep in mind that you may not always have a network connection. You should prepare for this simi-connected environment.  To do this, you should use the Microsoft.Phone.Net.NetworkingInformation namespace. With this you can do things like, check to see if the network is available, determine the type of network the phone is using (CDMA, GSM), or find the MO (Mobile Operator)

bool IsConnected =
Microsoft.Phone.Net.NetworkInformation.DeviceNetworkInformation.IsNetworkAvailable;
  
string MobileOperator = 
Microsoft.Phone.Net.NetworkInformation.DeviceNetworkInformation.CellularMobileOperator;
 
bool IsCellularDataEnabled = 
Microsoft.Phone.Net.NetworkInformation. DeviceNetworkInformation.IsCellularDataEnabled;
          
bool IsCellularDataRoamingEnabled = 
Microsoft.Phone.Net.NetworkInformation DeviceNetworkInformation.IsCellularDataRoamingEnabled;
 
bool IsWifiEnabled =
Microsoft.Phone.Net.NetworkInformation. DeviceNetworkInformation.IsWiFiEnabled;

 

The NetworkInterfaceType is another good one to put to determine what type of speeds you are going to get.

WP7 Getting Unique Device and User

In order for you to get the device unique ID and WL (Windows Live) Anonymous ID you need to first declare a couple of things in your WMAppManifest.xml file.  If you attempt to retrieve this information without these capabilities,  it will throw a UnauthorizedAccessException.  Remember, like all capabilities, the user will be alerted that you require this information before they download your application.  So use this only if you need it.

    <Capabilities>
      ...
      <Capability Name="ID_CAP_IDENTITY_DEVICE"/>
      <Capability Name="ID_CAP_IDENTITY_USER"/>
      ...
    </Capabilities>

Now you can access the the desired properties.  First add a using statement

 

using Microsoft.Phone.info;

 

Then access the properties.

 

public static byte[] GetDeviceUniqueID()  
        {  
            byte[] result = null;  
            object uniqueId;  
            if (DeviceExtendedProperties.TryGetValue("DeviceUniqueId", out uniqueId))  
                result = (byte[])uniqueId;  
  
            return result;  
        }  

public static string GetWindowsLiveAnonymousID()
        {
            string result = string.Empty;
            object anid;
            if (UserExtendedProperties.TryGetValue("ANID", out anid))
            {
                if (anid != null && anid.ToString().Length >= (ANIDLength + ANIDOffset))
                {
                    result = anid.ToString().Substring(ANIDOffset, ANIDLength);
                }
            }

            return result;
        }

Getting WP7 Device Info

As you are writing your WP7 applications you may come across the need to get information about the device your application is running on like the Firmware version, Manufacturer or the Memory the phone has loaded.  You can find all of this information in Microsoft.Phone.Info.DeviceStatus.

 

 1:  PowerSource =  Microsoft.Phone.Info.DeviceStatus.PowerSource.ToString();
 2: 
 3:  FirmwareVersion = Microsoft.Phone.Info.DeviceStatus.DeviceFirmwareVersion;
 4: 
 5:  HardwareVersion =  Microsoft.Phone.Info.DeviceStatus.DeviceHardwareVersion;
 6: 
 7:  Manufacturer =  Microsoft.Phone.Info.DeviceStatus.DeviceManufacturer;
 8: 
 9:  Name = Microsoft.Phone.Info.DeviceStatus.DeviceName;
 10: 
 11:   TotalMemory = (Microsoft.Phone.Info.DeviceStatus.DeviceTotalMemory / 

           1048576).ToString() + "MB";
 12: 
 13:  HasKeyboard = Microsoft.Phone.Info.DeviceStatus.IsKeyboardPresent;

 

 

Use this class to find the information you are looking for.  Hope that helps.

WP7 Saving To Isolated Storage

In the next few posts, we will be working with Isolated Storage on the phone.  In this post, we are going IO1to cover the basics of saving to, and reading from storage.  As we move forward we will modify this application with more complexity and best practices.

If you have every used the System.IO namespace in your .Net projects, you will find working with the storage on the phone very simple. It is just an extension of that namespace called System.IO.IsolatedStorage.

 

The first thing we want to do is to create a simple application that allows us to save some data.  We create a PhoneApplicatiton and add some TextBoxes and TextBlocks as shown on the left.

As you can see, we want to capture three simple points of data,  First Name, Last Name, and Age.

 

If we go to the code behind file, we first need to add the using statements for IsolatedStorage.

using System.IO;
using System.IO.IsolatedStorage;

 

Next,  lets look at the code that lies under the Set button. As you can see, we first create the storage for the application and then define a streamwriter that we will use to write our data to storage

private void btnSet_Click(object sender, RoutedEventArgs e)
{
    //get the storage for your app
    IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();
    //define a StreamWriter
    StreamWriter writeFile;

 

Since we will be writing to this file many times, we need to determine if this is the first time that someone has used the application. If it is, we create a folder and a file, if it is not, we just open the file and append it.

 

if (!store.DirectoryExists("SaveFolder"))
{
    //Create a directory folder
    store.CreateDirectory("SaveFolder");

    //Create a new file and use a StreamWriter to the store a new file in the directory we just created
     writeFile = new StreamWriter(new IsolatedStorageFileStream("SaveFolder\\SavedFile.txt", FileMode.CreateNew, store));
}
else
{
    //Create a new file and use a StreamWriter to the store a new file in the directory we just created
     writeFile = new StreamWriter(new IsolatedStorageFileStream("SaveFolder\\SavedFile.txt", FileMode.Append, store));
}

 

Now we gather the data needed, add a comma to seperate the data, and save the data to the file we created in the last step.

StringWriter str = new StringWriter();
            str.Write(txtFirstName.Text);
            str.Write(",");
            str.Write(txtLastName.Text);
            str.Write(",");
            str.Write(txtAge.Text);

            writeFile.WriteLine(str.ToString());
            writeFile.Close();

            txtFirstName.Text = string.Empty;
            txtLastName.Text = string.Empty;
            txtAge.Text = string.Empty;
                

        }

 

Now that we have the data saved to file. We can retrieve the data using a StreamReader. This is the code under the GET button.

 

//Get the Store we created earlier
IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication();

//use a StreamReader to open and read the file           
StreamReader readFile = null;
try
{
    readFile = new StreamReader(new IsolatedStorageFileStream("SaveFolder\\SavedFile.txt", FileMode.Open, store));
    string fileText = readFile.ReadToEnd();

    //The control txtRead will display the text entered in the file
    txtReturn.Text = fileText;
    readFile.Close();
}

catch
{        
    //For now, a simple catch to make sure they created it first
    //we will modify this later
    txtReturn.Text = "Need to create directory and the file first.";
}

 

This will read the file and place it in the TextBlock as shown below.

IO2 

 

Download the files for this post

In our next post on IsolatedStorage,  we will modify this section to read, search, and delete specific records.

Happy Coding

Daniel Egan – The Sociable Geek