Home > General Software Development > How to build a Google Finance client app with Windows Phone 7

How to build a Google Finance client app with Windows Phone 7

October 21st 2010 | Ben Yoder

<< Update: the zip file of this application is now available for download

How to build a Google Finance client app with Windows Phone 7

1. Getting Started

Google Finance enables users to view and manage stock portfolios. Google provides an HTTP API that allows clients to interface with the application. With the release of the new Windows Phone 7 operating system, creating a portfolio viewer application is a great way to learn a new set of tools.
Download the Windows Phone development tools—they integrate nicely into an already installed version of Visual Studio 2010. Alternatively you can use an Express Edition of 2010.
Once you’re up and running open VS 2010 and select File->New Project, then select a new Windows Phone List Application:

You should see a split screen designer for MainPage.xaml. This is the opening list page of the application. On the side with the XAML code, update the TitlePanel section to give your application a new name.

Hit F5 to run your application. Your emulator should come up and look something like this:

2. Authentication
Now that you’ve seen your application run in the emulator you must authenticate to the Google Finance API. I used HttpWebRequest to handle all the calls. Using the WebClient class could also work and might be simpler, but I prefer the control that HttpWebRequest provides.
The following code illustrates sending a HTTP POST to the Google client login service and reading the response. For simplicity, I put all my code in the MainViewModel.cs file.

        public void LoadItems()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://www.google.com/accounts/ClientLogin");
            request.ContentType = "application/x-www-form-urlencoded";
            request.Method = "POST";

            request.BeginGetRequestStream(new AsyncCallback(GetRequest), request);
        }

        private void GetRequest(IAsyncResult asyncResult)
        {

            string postData = "accountType=HOSTED_OR_GOOGLE";
            postData += "&Email=yourusername@gmail.com";
            postData += "&Passwd=yourpassword";
            postData += "&service=finance";
            postData += "&source=test-test-.01";
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);

            HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
            Stream newStream = request.EndGetRequestStream(asyncResult);
            newStream.Write(byteArray, 0, byteArray.Length);
            newStream.Close();

            request.BeginGetResponse(new AsyncCallback(GetResponse), request);
        }

        private void GetResponse(IAsyncResult asyncResult)
        {
            string responseFromServer = ReadResponse(asyncResult);
        }

        private string ReadResponse(IAsyncResult result)
        {
            HttpWebRequest request = (HttpWebRequest)result.AsyncState;
            WebResponse response = request.EndGetResponse(result);
            Console.WriteLine(((HttpWebResponse)response).StatusDescription);
            Stream dataStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            string responseFromServer = reader.ReadToEnd();
            reader.Close();
            dataStream.Close();
            response.Close();
            return responseFromServer;
        }

To see what the response is, paste this code into your project and call the LoadItems method from the OnNavigatedTo event in MainPage.xaml.cs.

            // Set the data context of the listbox control to the sample data
            if (DataContext == null)
                App.ViewModel.LoadItems();
                DataContext = App.ViewModel;

The Auth section is the only one we care about, so I parsed it out and assigned it to a private variable. All subsequent requests for portfolio and stock data will require it.

        private void GetResponse(IAsyncResult asyncResult)
        {
            string responseFromServer = ReadResponse(asyncResult);
            AuthenticationToken = responseFromServer.Substring(responseFromServer.IndexOf("Auth=") + 5);
        }

3. Getting Data
Now that we can authenticate to the Google Finance service, we can start retrieving stock information. First, set up your Google Finance account with some test portfolios if none currently exist. The call to retrieve your portfolio feed is significantly simpler than the authentication call—it’s a simple GET request with the Authorization header set to the previously returned Authentication Token.

        private void GetPortfolios()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://finance.google.com/finance/feeds/default/portfolios");
            request.Method = "GET";
            request.Headers["Authorization"] = "GoogleLogin auth=" + AuthenticationToken;
            request.BeginGetResponse(new AsyncCallback(GetPortfolioResponse), request);
        }

private void GetPortfolioResponse(IAsyncResult asyncResult)
       {
    ……
    }

The resulting response is an XML doc detailing your portfolio feed. Now, let’s bind it to the list displayed in the MainPage. LINQ to XML provides a simple way to parse the response and create the list of items to bind to.

        private void GetPortfolioResponse(IAsyncResult asyncResult)
        {
                string response = ReadResponse(asyncResult);
                XElement portfolio = XElement.Parse(response);

                XName qualifiedName = XName.Get("entry", "http://www.w3.org/2005/Atom");
                XName qualifiedTitle = XName.Get("title", "http://www.w3.org/2005/Atom");
                XName portfolioData = XName.Get("portfolioData", "http://schemas.google.com/finance/2007");

                var portfolios = from p in portfolio.Descendants(qualifiedName)
                                 select new ItemViewModel
                                    {
                                        LineOne = p.Element(qualifiedTitle).Value,
                                        LineTwo = "1 Week Return: " + p.Element(portfolioData).Attribute("return1w").Value
                                    };

                foreach (var d in portfolios)
                {
                    Items.Add(d);
                }

                NotifyPropertyChanged("Items");
        }

The ItemViewModel class is a default for the solution. Change it, or its property names, if you want them to be more descriptive. Update the GetResponse method to call GetPortfolios:

        private void GetResponse(IAsyncResult asyncResult)
        {
            string responseFromServer = ReadResponse(asyncResult);
            AuthenticationToken = responseFromServer.Substring(responseFromServer.IndexOf("Auth=") + 5);
            GetPortfolios();
        }

Then run the solution again. At this point you should get a security exception. This is because the HttpWebRequest kicks off a series of asynchronous calls which use separate threads. The NotifyPropertyChanged() call then tries to update the UI via event handlers, which isn’t allowed in Silverlight. To force the thread context, wrap the body of GetPortfolioResponse with:

            System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
            …
            });

This invokes the update on the UI thread which does not throw System.UnauthorizedAccessException: Invalid cross-thread access error.
An additional gotcha about parsing the response from Google is that the XML has a specified namespace, so doing something like portfolio.Descendents(“entry”) won’t work. You have to use the fully qualified name which you can do by using XName.Get with the elements specified namespace.
The solution should be runnable at this point. Hit F5 to debug. Your emulator should now look something like this (depending on your Google Finance portfolios):

If you click on an item you will automatically navigate to a detail page which will just display the portfolio name right now. In future posts, I’ll detail binding this page with specific stocks and making the app look great. If you have any questions or interesting alternative solutions please post them in the comments below.

 

 

Ben Yoder is a Senior .NET developer at Thycotic Software, an agile software services and product development company based in Washington DC. Secret Server is our flagship password management software product.

  1. October 21, 2010 at 8:31 pm

    Nice work Mate !!!

    Thank you for sharing this… !!!

    Very Helpful for Newbies !!!

    Regards

    KRK

  2. Senthil
    November 29, 2010 at 2:47 am

    Thanks a lot for sharing this. I was looking for how to post back on UI thread. This was very helpful!

  3. tkc
    January 10, 2011 at 3:34 pm

    Possible to post the source code here?

  4. manikanta
    January 20, 2011 at 9:02 am

    first of all very sweet of you for your work .then how to read text/json format in windows phone 7 can u explain me with simple example

  5. WP7Geek
    March 26, 2011 at 7:45 pm

    Can you plzzzzzzzzzzz share the code?

    • WP7Geek
      March 26, 2011 at 7:46 pm

      Any similar apps for Google doc client?

    • Ben
      October 5, 2011 at 4:16 pm

      See the update at the top of the post for a link to the source code.

  6. Tarzan
    May 9, 2011 at 8:01 pm

    Is there a zip file avaiable of the completed app?

  7. May 20, 2011 at 12:45 am

    Thanks for taking the time to put this example code into a well formed blog post. Got me up and running with a functional app using http GET / POST within 20 minutes!

  1. October 26, 2010 at 12:55 pm

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

%d bloggers like this: