Friday, July 12, 2013

Integrating Facebook in ASP Website using C# SDK

If you like it or hate it, you can't get away with the fact that Facebook is present all over the web. Whether it's a complex web application or just a news blog, every site uses Facebook for driving traffic. Integrating your web app or website with Facebook is easy and free. Apart from driving traffic to your site it also makes your web site more social and tailored for the users. You can access user's data from Facebook to simplify or eliminate your own user registration process. If you have a asp.net website you can use Facebook C# SDK for integrating Facebook within your website/web application.

Creating a Facebook App
First of all we need to create an app through which the website will connect with users. 
  1. Visit https://developers.facebook.com/apps and click on 'Create New App'.
  2. Fill in the desired App Name and Namespace. Remember these must beunique.
  3. On the basic settings page look for 'Select how your app integrates with Facebook' section and choose 'Website with Facebook Login'.
  4. In the Site URL field, enter your site address. I am working locally, so I added http://localhost:8779/ (Don't forget to put a trailing '/').
Note: Facebook keeps changing the developer interface. So, may be when you're reading this post you have to go through a different set of steps while a creating a new app and configuring it.
Create a new Facebook App

Facebook App Settings

Installing Facebook C# SDK

Next step is to add Facebook C# SDK to your website. Search for 'facebook' in the NuGet Package Manager. Install the latest stable release. In my case it was 6.1.4.
Facebok C# SDK NuGet

Note: Make sure you have a recent version of NuGet if not, download it fromhere.

Getting Started with code
I have created a simple interface with a button, two labels and a listbox.
Facebook ASP App Design
Design

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="FacebookDemo.aspx.cs" Inherits="MyApp.FacebookDemo" %>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" Text="Log in with Facebook" OnClick="Button1_Click" />
        <br />
        <asp:Label ID="Label1" runat="server" Text="Your Email"></asp:Label><br />
        <br />
        <asp:Label ID="Label2" runat="server" Text="Your Friends"></asp:Label><br />
        <asp:ListBox ID="ListBox1" runat="server" Width="200px" Height="200px"></asp:ListBox>
    </div>
    </form>
</body>
</html>

User Authentication
On the click of the button, we allow users to connect with our app and grant the necessary permissions through Facebook's OAuth dialog. For this we create aFacebookClient and through that a login URL. We have to add a few parameters in the login url:
app id,
a url to which users will be redirected,
response type,
and finally the permissions we require from the users.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void Button1_Click(object sender, EventArgs e)
       {
   var loginUrl = fb.GetLoginUrl(new
               {
 
                   client_id = "your_app_id",
 
                   redirect_uri = "http://localhost:8779/FacebookDemo.aspx",
 
                   response_type = "code",
 
                   scope = "email" // Add other permissions as needed
 
               });
               Response.Redirect(loginUrl.AbsoluteUri);
 }

This will take the user to Facebook Login page (if already not logged in) and then to our app login dialog. A user can accept or cancel the dialog, in both cases the user will be redirected back to our page.
Facebook OAuth Dialog
OAuth Dialog

Receiving Access Token
Our very next step is to receive an access token so that we can make requests to Facebook Graph API on behalf of the user. When the user is redirected back to our website, an auth code is appended in the URL. We have to exchange that code with an access_token.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
protected void Page_Load(object sender, EventArgs e)
    {
  if (Request.QueryString["code"] != null)
            {
                string accessCode = Request.QueryString["code"].ToString();
 
                var fb = new FacebookClient();
 
                // throws OAuthException
                dynamic result = fb.Post("oauth/access_token", new
                {
 
                    client_id = "your_app_id",
 
                    client_secret = "your_app_secret",
 
                    redirect_uri = "http://localhost:8779/FacebookDemo.aspx",
 
                    code = accessCode
 
                });
 
                var accessToken = result.access_token;
              }
    }

First we extract the code from URL then we do a post request to Facebook and exchange the code for an access_token. Also, you can know the expire time for a user access token by querying response.expires which returns the number of seconds until the token expires.

Getting User Information
After getting the access token, our work is mostly simplified. Let us find user'sid,name and friend list. All these come under the basic info and we don't need ask for a permission. As we asked for the permission to access email id of the user we can easily extract it along with name and id. So here's the extended codind after the previous part.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
protected void Page_Load(object sender, EventArgs e)
        {
   if (Request.QueryString["code"] != null)
            {
                string accessCode = Request.QueryString["code"].ToString();
 
                var fb = new FacebookClient();
 
                // throws OAuthException
                dynamic result = fb.Post("oauth/access_token", new
                {
 
                    client_id = "your_app_id",
 
                    client_secret = "your_app_secret",
 
                    redirect_uri = "http://localhost:8779/FacebookDemo.aspx",
 
                    code = accessCode
 
                });
 
                var accessToken = result.access_token;
                var expires = result.expires;
 
                // Store the access token in the session
                Session["AccessToken"] = accessToken;
 
                // update the facebook client with the access token
                fb.AccessToken = accessToken;
     
                // Calling Graph API for user info
                dynamic me = fb.Get("me?fields=friends,name,email");
 
                string id = me.id; // You can store it in the database
                string name = me.name;
                string email = me.email;
 
                Label1.Text = name + "(" + email + ")";
 
                var friends = me.friends;
 
                foreach (var friend in (JsonArray)friends["data"])
                {
                    ListBox1.Items.Add((string)(((JsonObject)friend)["name"]));
                }
 
                Button1.Text = "Log Out"; //Changin the button text to Log Out
 
                FormsAuthentication.SetAuthCookie(email, false);
            }
 }

Facebook C# SDK ASP .NET
OAuthException - #100
At this moment (i.e the code is still present in the url), if you reload the page you will experience an OAuthException - #100 "This authorization code has been used.".
What's happening is, we are again exchanging the code for an access token on the page load. Facebook could return us the already generated access token but it doesn't. Rather it perceives a call to generate a new access token. You can track this Facebook bug here.
So what we could do and actually we should do is check if the user is already signed in i.e look for the session variable we stored when the user signed in. So, here's a better a page_load method.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
protected void Page_Load(object sender, EventArgs e)
        {  
            // Check if already Signed In
            if (Session["AccessToken"] != null)
            {
                Label4.Text = Session["AccessToken"].ToString();
 
                // Retrieve user information from database if stored or else create a new FacebookClient with this accesstoken and extract data again.
                var fb = new FacebookClient(Session["AccessToken"].ToString());
 
                dynamic me = fb.Get("me?fields=friends,name,email");
 
                string email = me.email;
                Label1.Text = email;              
 
                var friends = me.friends;
 
                foreach (var friend in (JsonArray)friends["data"])
                {
                    System.Diagnostics.Debug.WriteLine((string)(((JsonObject)friend)["name"]));
                    ListBox1.Items.Add((string)(((JsonObject)friend)["name"]));
                }
 
                Button1.Text = "Log Out";
 
            }
             
            // Check if redirected from facebook
            else if (Request.QueryString["code"] != null)
            {
                ...
            }
 }

User Cancels Login Dialog
What if the user clicks on 'Cancel' rather than 'Go To App'. The user will still be returned to our site but instead of code there would be 3 other parameters in the url namely error, error_reason, error_description. Taking this to account, here's a modified page_load event.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
protected void Page_Load(object sender, EventArgs e)
        {  
            // Check if already Signed In
            if (Session["AccessToken"] != null)
            {
                ...
            }
    
            // Check if redirected from facebook
            else if (Request.QueryString["code"] != null)
            {
               ...
            }
 
            else if (Request.QueryString["error"] != null)
            {
                string error = Request.QueryString["error"];
                string errorReason = Request.QueryString["error_reason"];
                string errorDescription = Request.QueryString["error_description"];
            }
 
            else
            {
                // User not connected
            }
        }

Here's the output received when the user clicks on 'Cancel':YOUR_REDIRECT_URI?error_reason=user_denied&error=access_denied&error_description=The+user+denied+your+request.

Logout
You may also want to allow the users to logout and hide all the social details. In this sample app, as you have noted earlier the text for Login Button changes toLog Out when the user logs in. So, through the button's text we can know if the user wants to Log In or Out.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
protected void Button1_Click(object sender, EventArgs e)
        {
            if (Button1.Text == "Log Out")
                logout();
            else
            {
                var fb = new FacebookClient();
 
                var loginUrl = fb.GetLoginUrl(new
                {
 
                    client_id = "your_app_id",
 
                    redirect_uri = "http://localhost:8779/FacebookDemo.aspx",
 
                    response_type = "code",
 
                    scope = "email" // Add other permissions as needed
 
                });
                Response.Redirect(loginUrl.AbsoluteUri);
            }
        }
 
        private void logout()
        {
            var fb = new FacebookClient();
 
            var logoutUrl = fb.GetLogoutUrl(new
            {
                access_token = Session["AccessToken"],
 
                next = "http://localhost:8779/FacebookDemo.aspx"
 
            });
    
            // User Logged out, remove access token from session
            Session.Remove("AccessToken");
 
            Response.Redirect(logoutUrl.AbsoluteUri);
        }

Avoiding OAuthException
An OAuthException may occur if you try to use a expired access token. Access token may expire in the following cases:
> The token expires after expires time (2 months is the default for server-side auhentication flow & 2 hours    for client-side auhentication flow.).
> The user changes his password.
> The user de-authorizes your app.
> The user logs out of Facebook.

So, you must surround the piece of code which makes the use of access token with a try catch block.
1
2
3
4
5
6
7
8
9
10
try
{
    dynamic me = fb.Get("me?fields=email");
 
    Label1.Text = email;
}
catch (FacebookOAuthException ex)
{
    // Access Token expired, Ask the user to Login again
}

These were just sample examples on how to work with the sdk. It's up to you, how you incorporate these pieces of code in a real world web application and make the most out of Facebook.

Let your friends know that you are developing a Facebook App by sharing this article :P

UPDATE
Must read the second part, A Sample Facebook App using Facebook C Sharp SDK.