Click here to Skip to main content
Click here to Skip to main content

FriendTracker - A Winforms application that interacts with Facebook

, 3 Jul 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
How to interact with Facebook using Facebook SDK for .NET version 6.x

Download FriendTracker.zip

Introduction  

OK, I have to admit it: I'm a control freak! When somebody unfriends me on Facebook, I want to know who it is. Don't tell me that none of you have ever wondered that as well?

Previously I had an Excel sheet with all my friends, and every now and then, I would check it against my friend list on Facebook. That is - needless to say - a big job that can take quite some time.

Several times, I had thought of writing an application that could do the job for me, but I didn't really think that I could be bother spending my time doing that. It would definitely take longer than updating the Excel ark once or twice, but an application can be run as often as you like, so in the end, it could be worth it,  time-wise.

The other day, I happened to stumble over the Facebook SDK for .NET, and I thought: "Well, maybe it's time to see if I can crack that nut once and for all". And so I set out on my journey towards building the ultimate Facebook application for Windows (Dramatic, right?). 

Before you start 

First of all, before you start on your application, you need to do a few things on Facebook to get access to the Facebook API. 

Start by going to https://developers.facebook.com/apps. Click the "Create New App" button: 

 

Fill in the appropriate information and create the app. Afterwards, you can see that it's created like this:

Make a note of the App ID/API Key and the App Secret, because you're going to need them for your application. Also note the Sandbox Mode which should say "On". That means that your new application is only visible to the users you want it to be visible to. When your development is all done and the application is ready, you should switch off the Sandbox Mode. 

To learn more about the Sandbox Mode and Application Roles, you can visit: 

https://developers.facebook.com/docs/ApplicationSecurity/ 

Creating your .NET project 

First of all: Make sure that you have NuGet installed. If you haven't, you can get it from:

http://nuget.org/ 

Then create a new .NET Winforms application in the language of your choice (I use C#). Right-click the application's project node in the Solution Explorer and select "Manage NuGet Packages...". Click "Online" and enter "Facebook" in the search box. Install the "Facebook SDK for .NET" by Outercurve Foundation. IMPORTANT: The version number should be higher than 6.0. 

 

 

Important Code 

I'm not going to go into detail with all the code, just the parts that have to do with Facebook. As for the rest, you can see the code in the downloadable project files.

Before we can do anything with Facebook, we need to authenticate ourselves to get an Access Token. While we're developing the application, we can create a temporary Access Token using the tool:

https://developers.facebook.com/tools/access_token/ 

Using a developer access token is useful in certain cases, because it will allow you to access the Facebook API without having to go through the normal user authentication. But that access token is going to expire every once in a while, and we will need to create a new one and update out application with that.

When the application is done, we get the access token by authenticating a valid Facebook user, so I might as well skip the temporary developer access token and explain how to authenticate the user.

Before we do that, we need to make sure that we have the Facebook information we need. I created two Application Settings for the App Id and the App Secret and wrapped them in a read-only property:  

        public string ApplicationId
        {
            get { return Properties.Settings.Default.ApplicationID; }
        }
        public string AppSecret
        { 
            get { return Properties.Settings.Default.ApplicationSecret; }
        }   

We also need to specify what permissions we require of Facebook. I decided not to put that in the settings file. There is a certain logic to it that you put the App Id and the App Secret in a settings file, because you may need to create a new app declaration on Facebook against which your Winforms client should work. Having the settings in the settings file will allow you to modify them without rebuilding your exe. 

But if we put the permissions in the settings file, anybody could modify them and thus maybe get your application to behave strangely or not at all. It could also be that you develop a new version of your application that requires more permissions, and if you deploy the exe without updating the settings file (like you would normally do if you didn't know better), the app wouldn't work properly. 

I didn't want that of course. So for the permissions, I put them in a string constant in the code. That way, the correct permissions are always available to the application: 

         private const string ExtendedPermissionsNeeded = "email,offline_access"; 

The "email" permission allows us to access the user's email address, which the application will need for the email sending functionality (see further down). 

The "offline_access" is really an old permission that should now be depreciated. But it was necessary earlier, so I have chosen to include it anyway, just in case. 

For more information on permissions, please see:

https://developers.facebook.com/docs/reference/login/extended-permissions/ 

https://developers.facebook.com/docs/reference/login/email-permissions/ 

 

Authenticating the user and getting user information 

Now were ready to authenticate our application user to Facebook. To do that, we need to generate a Login Url: 

        private string GenerateLoginUrl()
        {
            dynamic parameters = new ExpandoObject();

            parameters.client_id = ApplicationId;
            parameters.redirect_uri = "https://www.facebook.com/connect/login_success.html";
            parameters.response_type = "token";
            parameters.display = "popup";

            if (!string.IsNullOrWhiteSpace(ExtendedPermissionsNeeded))
                parameters.scope = ExtendedPermissionsNeeded;

            var fb = new FacebookClient();

            Uri loginUri = fb.GetLoginUrl(parameters);

            return loginUri.AbsoluteUri;
        }  

That code is more or less self-explanatory. We declare the parameters needed and use the FacebookClient object located in the SDK to generate the login url. When that is done, we add a WebBrowser control (I call it loginWebBrowser) to the application and navigate it to the login url: 

         loginWebBrowser.Navigate(loginUrl); 

Then we handle the WebBrowser Navigated event to check if the authentication went well: 

        private void LoginWebBrowserNavigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            if (loginWebBrowser.Visible)
            {
                var fb = new FacebookClient();

                FacebookOAuthResult oauthResult;
                if (fb.TryParseOAuthCallbackUrl(e.Url, out oauthResult))
                {
                    if (oauthResult.IsSuccess)
                    {
                        _accessToken = oauthResult.AccessToken;
                        _authorized = true;
                    }
                    else
                    {
                        _accessToken = "";
                        _authorized = false;
                    }

                    if (_authorized)
                    {
                        fb = new FacebookClient(_accessToken);

                        dynamic result = fb.Get("me");
                        _currentName = result.name;
                        _currentEmail = result.email;
                        userNameLabel.Text = string.Format("Facebook User: {0}", _currentName);

                        //Do what need being done now that we are logged in!
                    }
                    else
                    {
                        MessageBox.Show("Couldn't log into Facebook!", "Login unsuccessful", MessageBoxButtons.OK,
                                        MessageBoxIcon.Error);
                    }
                }
            }
        } 

 As you see, we use the FacebookClient object's TryParseOAuthCallbackUrl method to parse the callback url to see if the login was successful, and also retrieve the current valid access token for further use.

As a bonus, we use another FacebookClient object (this time created with the access token in the constructor) to retrieve the name and email of the user that is logged in. Note that if we had not specified the "email" extended permission, we would have gotten most of the user information, but NOT the email address. The fields available to you can be seen in this list: 

https://developers.facebook.com/docs/reference/fql/standard_user_info/notes 

Please note: The above url neglects to mention the thing about "email" permission. It claims that you can get the email address just by specifying the acces token. That is NOT true! 

Getting the friend list 

To access the user's friend list is easy as pie. The following code does the trick:

                Dictionary<string, string> userFriends = new Dictionary<string, string>();

                var client = new FacebookClient(_accessToken);

                dynamic myInfo = client.Get(@"\me\friends");

                foreach (dynamic friend in myInfo.data)
                {
                    userFriends.Add(friend.id, friend.name);
                } 

I am doing that in a BackgroundWorker thread so that it doesn't lock up the UI while it's working. 

Once I have the friend list, I simply compare it to the result from the previous run, which I have stored in an Xml file, and after that I update the Xml file to reflect the current list. 

PLEASE NOTE! VERY IMPORTANT! In some cases, you will notice that the friend list retrieved by the API is not complete! For instance, I have 152 friends on Facebook, but the above API only returns 149. I had to Google to find the explanation for that; It turns out that a Facebook user can deny ALL requests from ALL applications. It is called "turning off the platform", but is rarely done, because it also entails that you cannot use Facebook login at third party pages - which most users want because it's easy and convenient.

The problem is that those friends do not show up in the friend list. It is no bug, and there is absolutely nothing you can do about it. That means that in reality, this application can only track people who do NOT deny application requests. 

Logging out when the deed is done 

After we have read the friend list, we can either remain logged in or we can log out of Facebook. If we choose to remain logged in, we will completely bypass the authentication process the next time and go directly to the hot stuff (as long as the access token does not expire). 

If we choose to log out, we can log in with another account if we so please - and track the friends of that account. 

To log out, we need to find the logout url in the same manner as we found the login url: 

        private string GenerateLogoutUrl()
        {
            dynamic parameters = new ExpandoObject();

            parameters.next = HttpUtility.UrlEncode(_loginUrl, Encoding.UTF8);
            parameters.access_token = _accessToken;

            var fb = new FacebookClient(_accessToken);

            Uri logoutUri = fb.GetLogoutUrl(parameters);
            return logoutUri.AbsoluteUri;
        } 

Again, we use the FacebookClient object to generate the url. According to the documentation I found, specifying a url in the "next" parameter should cause a redirect to that url when the logout was done. In the above case, it should redirect to the login form when the logout was done. 

But as I explain in my tip Facebook SDK for .NET - How to log your application out, that doesn't work at all. My WebBrowser only redirects to the Facebook timeline of the user that is logged in, and that user is NOT logged out at all. 

In the above tip, I explain more about how to work around that problem. In short, I test to see if there is a hidden logout form in the current web page (which there is in the timeline), and if there is, I invoke a JavaScript to do the logout. Once that is done, I manually redirect to the login page again: 

        private void LoginWebBrowserNavigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            if (_loggingOut)
            {
                if (loginWebBrowser.Document != null)
                {
                    HtmlElement logoutForm = loginWebBrowser.Document.GetElementById("logout_form");
                    if (logoutForm != null)
                    {
                        loginWebBrowser.Document.InvokeScript("execScript",
                                      new Object[] { "document.getElementById('logout_form').submit();", "JavaScript" });
                    }
                }
         
                if (e.Url.AbsoluteUri.StartsWith(@"https://www.facebook.com/index.php")
                 || e.Url.AbsoluteUri.StartsWith(@"http://www.facebook.com/index.php"))
                {
                    loginWebBrowser.Navigate(_loginUrl);
                }
            }
        } 

That's all there is to it! Easy peasy if you know how to. I had to Google a lot and read a lot of articles to be able to piece it all together, so I hope that this can be of a small help to you. 

Using the FriendTracker application  

OK, now the application is done and ready for use. So how do you use it?

Step 1 - .NET Framework 

Make sure that the machine that shoul run the program has got .NET Framework 4.5 installed. If not, you can get it from here: 

http://msdn.microsoft.com/en-us/library/5a4x27ek(v=vs.110).aspx 

 

Step 2 - Deployment: 

Copy the contents of the "bin\Release" folder to a folder on the machine where you want to use it. It should be five files in total: 

Facebook.dll

Facebook.xml

FriendTracker.exe

FriendTracker.exe.config

FriendTracker.pdb 

 

Step 3 - Update the settings in the config file: 

ApplicationID: This is the App Id you got when you registered the application on the Facebook developer site (see above) 

ApplicationSecret: This is the App Secret you got when you registered the application on the Facebook developer site (see above)

SendEmail: A boolean value. If set to "True", the application will send an email to a given email address whenever an update of the friend list has occurred (new friends added or old friends removed). It requires that the other email settings are set up correctly. If set to "False", no email is ever sent.

SMTPServer: The SMTP server with which you want to send the email. Can be empty if SendEmail="False".

SMTPPort: The port your SMTP server sends emails on. An integer value. Leave at 80 if you're not sure.

SMTPUser: If your SMTP Server requires authentication, you can enter the user name here. Please note: If authentication is used, BOTH user name and password MUST be filled in, otherwise it won't work. Can be empty if SendEmail="False".

SMTPPassword: If your SMTP Server requires authentication, you can enter the user password here. Please note: If authentication is used, BOTH user name and password MUST be filled in, otherwise it won't work. Can be empty if SendEmail="False".

SMTPUseSecurity: If your SMTP Server requires the use of SSL, you can set this property to "True". Otherwise just leave it at "False".

FromEmailAddress: The email address that appears to be the sender of the email. Can either be a specific address or the string "[CURRENT_EMAIL]" (without quotes). If it is "[CURRENT_EMAIL]", the email address retrieved from the currently logged in user will be used. The FROM email address can NOT be empty.

TomEmailAddress: The email address to whom the email will be sent. Can either be a specific address or the string "[CURRENT_EMAIL]" (without quotes). If it is "[CURRENT_EMAIL]", the email address retrieved from the currently logged in user will be used. The TO email address can NOT be empty.

LogOutAfterUpdate: If this is set to "True", the application will log out the current user from Facebook once the update of the friend list has taken place. This is mostly for automation purposes.

CloseAfterUpdate: If this is set to "True", the application will close down once the update of the friend list has taken place. This is mostly for automation purposes. 

 

Step 4 - Use the application: 

The simplest way to use the application is to simply run it manually by double-clicking the FriendTracker.exe file. That will open the application and present you with the Facebook login. Once you have logged in, you should see the list of your friends in the listview (it takes a very short time to retrieve them, but should not take more than a few seconds). 

New friends are placed in the top group, old friends in the group after that and removed friends in the last group. 

If new friends have been added or old friends removed, and all the email settings are correctly specifed, you should receive and email to the selected address with the changes. 

You could, if you so desire automate the run of the application, either by adding it to the Windows startup sequence so that it is run when Windows starts, of by using the scheduler to run it at scheduled times. 

No matter how you do, you need to remember that you might need to log in. Always the first time you run the application. If you don't log out, you should be logged in on every subsequent run unless the access token needs to be renewed. 

How to deal with friends that are not in the list due to their security settings: 

As I wrote above, the friend list you get from Facebook might not be complete if some of you friends have turned off their platform. If you can live with that, it's ok. If not, then you can add them manually to your list once you are logged in. Just click the "File" menu and choose "Add friend manually" or simply press the "Insert" button on your keyboard. 

A manually added friend will be shown with a person icon. Friends retrieved from Facebook are shown with a Facebook icon. 

You can just as easily remove manually added friends, by selecting one or more, and select "Remove friend manually" from the "File" menu or simply pressing the "Delete" button on the keyboard. You needn't worry, you will be asked to confirm the delete before it actually happens. 

Please note: If you delete a person that is NOT manually added, the person will be deleted, but restored from Facebook the next time the program is run. 

Deleting friends - manually or automatically added - in the FriendTracker program will NOT delete them from Facebook. 

Possible Improvements 

  • Possibility to change the settings from within the program!
  • Other Facebook features, for instance, it could be interesting to have the program post a message to your timeline when it has updated the friend list, saying "Peter Peterson has recently added 12 new friends" or something like that. It could also be interesting to add a feature so that you can actually remove friends from Facebook by removing them from the FriendTracker list. 
 
I will leave that up to you, the reader, as a homework excercise. 

History 

Version 1.00 - Initial release

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Johnny J.
Software Developer (Senior)
Sweden Sweden
Born in Copenhagen, Denmark
Have been living in Paris, France and L.A., The United States
Now live in Stockholm, Sweden
 
Started programming when I got my first VIC 20, and a few months later on Commodore 64. Those were the days!
 
Studied programming at the Copenhagen Engineering Academy
 
Professional console, winforms and webforms programming in Comal, x86 Assembler, Fortran, Pascal, Delphi, Visual Basic 3 through 6, Classic ASP, C# and VB.NET
 
I now work as Senior .NET developer building Airline Booking Systems, and have a number of projects in various states of progress to work on in the spare time...
 
PS: The cat on my profile is one of my three cats, Ramses. He's all white, odd-eyed, deaf and definitely the coolest cat there is!

Comments and Discussions

 
QuestionApp Secret PinmemberMember 1035577313-May-14 6:51 
AnswerRe: App Secret PinprofessionalJohnny J.13-May-14 20:07 
QuestionAhem! PinprofessionalBassam Abdul-Baki3-Jul-13 4:36 
AnswerRe: Ahem! PinprofessionalJohnny J.3-Jul-13 4:57 
GeneralRe: Ahem! PinprofessionalBassam Abdul-Baki3-Jul-13 5:05 
GeneralRe: Ahem! PinprofessionalBassam Abdul-Baki3-Jul-13 5:07 
GeneralRe: Ahem! PinprofessionalJohnny J.3-Jul-13 5:37 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141030.1 | Last Updated 3 Jul 2013
Article Copyright 2013 by Johnny J.
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid