Monday, July 8, 2013

A Sample Facebook App using Facebook C Sharp SDK

In previous tutorial of this series, we learnt the basics of Facebook C# SDK and how do we implement it in our asp.net website. Now let's move further and create something meaningful out of it. If you haven't tried Facebook C# SDK before, it's strongly recommended that to go through the previous tutorial.

Recap of the last article:
  • Creating and configuring Facebook App
  • Setting up Facebook C# SDK
  • Getting User Access Token
  • Obtaining User Email and Friend List
Continuing from where we left off i.e getting friend list, let's move further and obtain some more user information and more importantly get our hands dirty with POST actions available through Graph API.

To explain the various Graph API GET and POST actions, we will try to develop a real world app for better understandability.

I didn't put much pressure on my mind, and got an idea for a stupid, simple app that's already been developed by many on Facebook - Finding which sports star is the user. (Not too much realistic :P but will do for this tutorial)

Here's the design view for our app:



You can download the whole project to get the design code.

Working of the app

The idea is simple, we will obtain all the athletes liked by the user and guess what, then we would RANDOMLY choose a sports person. Now when we have the name of the sports person from the list, we would display his picture. User would have options to share it as a text status, or a photo with description. They could also tag their friends in the photo before sharing.
Additionally, the user can share our page on his timeline. Also, he can share his experience or doubts on our Facebook Page i.e give feedback.
The status label at the end will help you being notified of what's going on and moreover it would display the result of various POST actions.

Getting Access Token, Name, Friends and Favorite Athletes

Here's the page_load, login, logout and GetUserData method.

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            // Check if already Signed In
            if (Session["AccessToken"] != null)
            {
                // Retrieve user information from database if stored or else create a new FacebookClient with this accesstoken and extract data again.
                GetUserData(Session["AccessToken"].ToString());

            }
            // Check if redirected from facebook
            else 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 = "app_id",

                    client_secret = "app_secret",

                    redirect_uri = "redirect_uri",

                    code = accessCode

                });

                Status.Text = "Logged in. Your session expires in " + result.expires + "ms";

                // Store the access token in the session
                Session["AccessToken"] = result.access_token;

                GetUserData(result.access_token);
            }

            else if (Request.QueryString["error"] != null)
            {
                // Notify the user as you like
                string error = Request.QueryString["error"];
                string errorResponse = Request.QueryString["error_reason"];
                string errorDescription = Request.QueryString["error_description"];

                Status.Text = errorDescription;
            }

            else
            {
                // User not connected, ask them to sign in again
                Status.Text = "Not Signed In";
            }
        }
    }

    protected void Login_Click(object sender, EventArgs e)
    {
        if (Login.Text == "Log Out")
            logout();
        else
        {
            var fb = new FacebookClient();

            var loginUrl = fb.GetLoginUrl(new
            {

                client_id = "app_id",

                redirect_uri = "redirect_uri",

                response_type = "code",

                scope = "email,user_likes,publish_stream" // 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 = "redirect_uri"

        });

        Session.Remove("AccessToken");

        Response.Redirect(logoutUrl.AbsoluteUri);
    }

    private void GetUserData(string accessToken)
    {
        var fb = new FacebookClient(accessToken);

        dynamic me = fb.Get("me?fields=friends,name,email,favorite_athletes");

        string id = me.id; // Store in database
        string email = me.email; // Store in database
        string FBName = me.name; // Store in database            

        NameText.Visible = true;
        NameText.Text = FBName;

        ViewState["FBName"] = FBName; // Storing User's Name in ViewState

        var friends = me.friends;

        foreach (var friend in (JsonArray)friends["data"])
        {
            ListItem item = new ListItem((string)(((JsonObject)friend)["name"]), (string)(((JsonObject)friend)["id"]));
            FriendList.Items.Add(item);
        }

        var athletes = me.favorite_athletes;

        foreach (var athlete in (JsonArray)athletes)
        {
            SportsPersonList.Items.Add((string)(((JsonObject)athlete)["name"]));
        }

        Login.Text = "Log Out";
    }


Status - Connected
Update
1 Corrigendum: The expiration time of access token is in seconds and not milliseconds.
2 You can now see a video walk-through of the app at the end of the post.

On Page_Load we would detect the status of the user - connected, not connected or redirected from Facebook. On GetUserData method we access user's name and friends for populating our CheckBox List. Importantly list of favorite athelets of the user is extracted and displayed in a ListBox. For a detailed explanation on this step, please refer to the previous tutorial.

Selecting an Athlete

When 'Click to Find' is clicked. we would randomly select a sportsperson from the list of favorite athletes of the user.  An image of the selected sports person would be displayed on the Image component on our web page. For simplicity I have included all the images in my project, you might consider making API calls in your real world app.

    protected void Find_Click(object sender, EventArgs e)
    {
        if (Session["AccessToken"] != null)
        {
            Random rnd = new Random();
            int rnum = rnd.Next(SportsPersonList.Items.Count);

            string SportsPerson = SportsPersonList.Items[rnum].ToString();

            ViewState["SportsPerson"] = SportsPerson;

            FinalName.Text = SportsPerson;

            FinalImage.ImageUrl = "Images/" + SportsPerson + ".jpg";

        }
        else
            Status.Text = "You need to login";
    }
Messi? I don't mind :P

Now when a user has interacted with your app, you would be interested in publishing his activity on his timeline so that it could attract more users or just create an awareness for your app. You could post a simple text update, an image or an open graph action.
In this example, it's not done automatically rather there are buttons for each of these actions. In your real world application you might be interested in doing this behind scenes.

Update Status (Publishing a simple text update)

The 'Update Status' button when clicked will publish a text message to the user's timeline. It's easy, we just need to do a simple POST request to '/me/feed'.

When successfully posted, Facebook returns the post id of the newly published status which you might want to store in database for tracking/analytics.
Note: 'via your_app_name' is placed next to the post date to depict that it's published through an app.

Share Photo

SDK's FacebookMediaObject makes it very easy to post photos to user's profile. The Graph API path for posting photos is 'me/photos'

    protected void SharePhoto_Click(object sender, EventArgs e)
    {
        var fb = new FacebookClient(Session["AccessToken"].ToString());

        string sportsperson = ViewState["SportsPerson"].ToString();

        var parameters = new Dictionary<string, object>();
        parameters["name"] = "If " + ViewState["FBName"] + " was a sports person, he would have been " + sportsperson;
        parameters["TestPic"] = new FacebookMediaObject
        {
            ContentType = "image/jpeg",
            FileName = sportsperson + ".jpg"

        }.SetValue(File.ReadAllBytes(Server.MapPath("~\\Images\\" + sportsperson + ".jpg")));

        dynamic res = fb.Post("me/Photos", parameters);

        Status.Text = "Photo Uploaded. Photo ID: " + res.id;
    }


This will create a new album with the same name as of the app (if it didn't existed already) and the photo will be added in that album. You can also add a photo to a particular album by specifying the album id in the following endpoint: 'Album_ID/Photos'.

Note: the parameter 'name' will contain the description for the photo. The second parameter i.e 'pic' can be anything you like. It is used as the name in the multipart/form-data when you upload the file.

Once posted, Facebook will return the photo_id as response which is displayed in the status label.


Tag & Share

Users can also tag their friends before publishing the photo. Users can select their friends to be tagged from the Checkbox List on the left.
I am NOT able to develop a sophisticated tagging system where users would click on the friends faces to tag them. So for this example x and y cordinates are generated through code and are NOT in the control of the user.
Select friends from Checked ListBox
    protected void TagShare_Click(object sender, EventArgs e)
    {
        List<ListItem> checkedItems = new List<ListItem>();

        foreach (ListItem item in FriendList.Items)
        {
            if (item.Selected)
            {
                checkedItems.Add(item);
            }
        }

        var fb = new FacebookClient(Session["AccessToken"].ToString());

        int x = 10, y = 10;
        UserTags[] tags = new UserTags[checkedItems.Count];

        for (int i = 0; i < checkedItems.Count; i++)
        {
            ListItem item = checkedItems[i];

            UserTags tag = new UserTags();
            tag.tag_uid = long.Parse(item.Value);
            tag.x = x;
            tag.y = y;

            tags[i] = tag;

            x += 10;
            y += 10;
        }

        string sportsperson = ViewState["SportsPerson"].ToString();

        var parameters = new Dictionary<string, object>();
        parameters["name"] = "If " + ViewState["FBName"] + " was a sports person, he would have been " + sportsperson;
        parameters["tags"] = tags;
        parameters["TestPic"] = new FacebookMediaObject
        {
            ContentType = "image/jpeg",
            FileName = sportsperson + ".jpg"

        }.SetValue(File.ReadAllBytes(Server.MapPath("~\\Images\\" + sportsperson + ".jpg")));

        dynamic res = fb.Post("me/Photos", parameters);

        Status.Text = "Photo Uploaded. Photo ID: " + res.id;
    }

Photo with friends tagged

Share Page

You can make users share a link with custom thumbnail, name and description.

    protected void SharePage_Click(object sender, EventArgs e)
    {
        var fb = new FacebookClient(Session["AccessToken"].ToString());

        var parameters = new Dictionary<string, object>();
        parameters["link"] = "http://www.thepcwizard.in/";
        parameters["picture"] = "http://1.bp.blogspot.com/-jHdAux6CGwc/UDPP71sDSdI/AAAAAAAABRA/cbQtJWwx95k/s1600/new-fb-thepcwizard-cover.jpg";
        parameters["name"] = "ThePCWizard";
        parameters["caption"] = ViewState["SportsPerson"].ToString() + " just read a tutorial on ThePCWizard";
        parameters["description"] = ViewState["SportsPerson"].ToString() + " read the tutorial \"A sample facebook app using Facebook C Sharp SDK\" on thepcwizard.in";

        dynamic res = fb.Post("/me/feed", parameters);

        Status.Text = "Thank you for sharing. Post ID: " + res.id;
    }
You can either accept values for these parameters from user or generate it automatically or skip them altogether. In the last case Facebook will automatically extract the required  information from the link.

        protected void SharePage_Click(object sender, EventArgs e)
        {
            var fb = new FacebookClient(Session["AccessToken"].ToString());

            var parameters = new Dictionary<string, object>();
            parameters["link"] = "http://www.facebook.com/thepcwizardblog";

            dynamic res = fb.Post("/me/feed", parameters);

            Status.Text = "Thank you for sharing. Post ID: " + res.id;

        }

Give Feedback

You might also want to allow users to share their experiences/feedback on you company's Facebook page. This can be done by using page_id instead of 'me' in the graph api call.



    protected void GiveFeedback_Click(object sender, EventArgs e)
    {
        var fb = new FacebookClient(Session["AccessToken"].ToString());

        var parameters = new Dictionary<string, object>();
        parameters["message"] = FeedbackText.Text;

        dynamic res = fb.Post("/page_id/feed", parameters);

        Status.Text = "Thanks for your feedback. Post ID: " + res.id;
    }
 
Note:
1. Don't try to replace the page_id with user profile_id because as of 6th Feb, 2013 you can't post on friends timeline using Graph API.
2. This will NOT work on a page you admin. You will receive an '(OAuthException - #283) (#283) Requires extended permission: manage_pages'. For debugging purpose, you could use a different account or even better create a Test User for your app.


I hope this article takes you a step forward with Facebook C# SDK. You can download the whole project from here if you have any doubts. You can always ask your queries/share your feedback in the comment section below.

Don't forget to like ThePCWizard on facebook for latest tech trolls and geeky discussion. Also subscribe to the RSS feeds and YouTube channel for latest programming tutorials and tech news.

8 comments:

  1. Good example.
    Thank you for this post

    ReplyDelete
  2. Thank you for this post. Si visitas ARGENTINA tenes una asado gratis!! :D

    ReplyDelete
  3. how can i get messages and send messages

    ReplyDelete
  4. i get error ;( friend function ...

    ReplyDelete
  5. How to share a post with Public, Friends or Only Me ?

    ReplyDelete
  6. Nice Article Thank you,by the way how do i send private message to my friends?through that message i actually want to send Link of my app so when my friend open the message and click on link he/she will redirect to my app page..can you please suggest how do i do this?Thank you in advance.

    ReplyDelete
  7. it is not retrieving friends in me can you help

    ReplyDelete
  8. Your Both Articles Were Good!!!!
    But Facebook Don`t Allow On A Fly To Give Us Permission To Extract User`s Friend List..
    You Should Have Explain that Tpp

    ReplyDelete