Archive

Posts Tagged ‘google finance API’

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

October 21, 2010 10 comments

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.