Introduction
If you’ve discovered this blog post via search engine most likely you want to build a StackOverflow desktop client. Someone once said ‘talk is cheap, show me the code’ so you can go straight to http://stackoverflowclient.codeplex.com/ and download the code sample that logs you into StackOverflow site and shows you all the latest posts in a WPF application.
StackOverflow client as we know it is a popular site for asking programming related questions. One of the great things about this site is that it has a reputation system in which you get upvoted for the right answers and downvoted for the wrong answers. What this means is that people with higher reputation are most likely very smart people like Jon Skeet and Marc Gravell. However if you have low reputation this could also mean that you do not have time to visit the site more often and answer more questions. This is exactly why you would need a desktop client for SO. Without boring you with further introductory information lets get straight to the code.
Design
There are many ways in which you can build a client for SO
- Monitor the RSS feeds and show desktop popups (Easiest but not very useful)
- Log into the site using WebClient class and maintain the sessions (Harder way and can be easily detected and blocked unless done right)
- Put a Web Browser control on your form and simulate navigation on it, read and parse the html to extract information (Medium difficulty and can easily break with css/markup changes but they are not very frequent.)
I chose the 3rd way of building the client.
So essential ingredients for writing a client in WPF/C# for SO using the 3rd methods are as follows:
A question on StackOverflow can be represented by a class with following definition
class Question
{
public Uri Url { get; set; }
public string Title { get; set; }
public bool Interesting { get; set; }
public int Votes { get; set; }
public int Answers { get; set; }
public int Views { get; set; }
}
All the information in this class can be easily populated by parsing the home page of the SO site.
The bool interesting property tells if you’ve marked the tag as interesting on your SO profile which highlights the questions for you so you can easily find questions that have the same tags in which you’re interested.
So for parsing the html of the page you will need a component in your code called StackOverflowParser.
I’ll cut the implementation details here and just tell you what services each component provides.
So the Parser currently has two methods
public IEnumerable GetQuestions(string html){}
public bool IsLoggedIn(string html){}
Both the methods take html of a page and return you some information based on the parsed html (using HtmlAgilityPack).
To determine that you’re logged in the IsLoggedIn just checks for a link to logout page in the html “/users/logout”. This link would only appear on a page if you’re logged in.
To get the questions from the home page, the GetQuestions method finds all the divs with id “question-summary”. These divs contain all the questions and information related to them that can be parsed into Question object.
Now that the basic parsing component is ready we need a component that uses this parser and navigates on the site to particular pages that have the relevant html on them.
For this you need a StackOverflowNavigator component. This component currently has following methods:
public void BeginNavigateToHome(Action callback){}
public void BeginGetActiveQuestions(Action> callback){}
public void EnsureLoggedIn(Action action){}
And following events
public event EventHandler RequestLogin = delegate { };
public event EventHandler LoggedIn = delegate { };
BeginNavigateToHome asynchronously navigates the WebBrowser control (which is passed in the constructor) to the Home Page and then executes the action that you’ve passed as callback.
BeginGetActiveQuestions similarly navigates to the home page, parses out the questions and raises the callback that you’ve passed. This method also ensures that you’re logged in using EnsureLoggedIn method because ‘bool interesting’ property of Questions can only be populated if you’re logged in hence it checks if you’re not logged in then it raises the ReqestLogin event. The form on receiving this event should open up a window with the same WebBrowser control on it and make it visible because the navigator will have navigated the page to the login page of SO site.
When the user enters his login/password SO redirect the person to the home page. The navigator constantly monitors the Web Browser control and on each navigation it checks where the user is now logged in and as soon as the user is logged in it raises the LoggedIn event. This is when you can hide the window because user is now logged in and soon your call back of activequestions will be raised because thats one of the pending tasks the navigator had to do.
As soon as you get the callback with questions you can then iterate over the questions and show popups on desktop to notify the user about new questions.
You will obviously need to keep last set of questions to make sure that you don’t show the popups repeatedly.
The code sample on codeplex simply shows the active questions on WPF window in a ListBox control. Since Overroot is going to pursue some other ideas as our upcoming products you are free to take this project from here and build a complete SO client on it.
If you want to contribute to this project contact hasan#overroot$com (Replace # with @ and $ with .)
If you have any trouble understanding the code just leave a comment on this post or send me an email.
Happy coding!