Prabir's Blog

open source geek and lover of all tech  

Recently I had released the first public version of the nuget button. It was a great start but still lacked some cool features that I wanted. So with this v0.2 release, it will address some of those lacking features.

Make sure to change the javascript url to the new version.

<script type="text/javascript">
    (function () {
        var nb = document.createElement('script'); nb.type = 'text/javascript'; nb.async = true;
        nb.src = 'http://s.prabir.me/nuget-button/0.2.1/nuget-button.min.js';
        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(nb, s);
    })();
</script>

Clickable links

Many of us have been pleased by the ease nuget has brought to the .net world on package management. But for me, there has also been one more + nuget has brought into my life. It has also allowed me to easily find the source code of the project. (Next time you install a package, make sure to check out its source code too. You are gonna a learn a lot just looking at others source code).

image

Starting from v0.2, you can now click the package name and go the the official nuget page of the package. Here is the sample effect when you hover over the package name.

Install-Package SimpleJson

<pre class="nuget-button">Install-Package Facebook</pre>

The code is exactly same as in v0.1 thus maintaining backward compatibility. The nuget button is smart enough and generates a link to http://nuget.org/List/Packages/SimpleJson

But what if I don’t host my packages in nuget.org?

The easiest workaround would be to disable the link feature in nuget button.

<pre class="nuget-button" data-nugetbutton-link="false">Install-Package SimpleJson</pre>

Add a new data- property called data-nugetbutton-link and set it to false.

Great! But I want custom links.

No problem. That’s been thought of already.

A bit of history first(As of this writing nuget doesn’t yet support pre-releases (beta release) packages, though it has been planned for v1.6.) We release Facebook C# SDK quite often, but to maintain the stability of the code, we mark some of the release as beta release and don’t publish it in nuget.org as there are lots of live facebook apps using it. But due to the popularity of nuget, the first question we get on every release is how do I get this pre-release package from nuget? My answer was, it’s not in nuget as its not a stable release and we don’t want users to just start pulling beta releases and using it in their production and nuget doesn’t support pre-release packages. Overtime I was tired of answering the same reason again and again and I simply set up a pulic nuget server that others could add. But the problem is you get different url which is not hosted in nuget.org. So here is how to get over that problem.

<pre data-nugetbutton-link="http://nuget.prabir.me"  class="nuget-button">Install-Package Facebook</pre>

Notice that it is the same data-nugetbutton-link that we used before, but this time its set to a url instead of false. This allows you to point to your own custom nuget servers or a github page.

Custom size

This one is especially for those who writes blog like me. You would most likely want to match the theme of nuget button with your own blog theme. I don’t have plans to allow customizable color - black nuget button is supposed to be a brand ;), but you can definitely set the size of the nuget button using em value for font-size – pure html again.

<div style="float:left; font-size:0.5em"><pre class="nuget-button">Install-Package FluentHttp.Core</pre></div><div style="clear: left"></div>

The above code not only sets the size, but also takes only the required length for your package.

Here are some live example of the nuget button v0.2.

Full width (default)

Install-Package FluentHttp.Core

Auto width

Install-Package FluentHttp.Core
 

Auto width with smaller size

Install-Package FluentHttp.Core
 

For more live samples and new features make sure to check out http://s.prabir.me/nuget-button/0.2.1/nuget-button.htm

When I was going through Scott Hansleman’s blog posts, I had realized that he makes extensive use the the nuget style Install-Package buttons like the one shown below.

image

I was a bit jealous and wanted to see for myself if I could have those nuget install-package buttons too. As of now I have around 18 unique nuget packages (most popular ones being Facebook C# SDK, SimpleJson and FluentHttp) hosted at nuget.org so I thought it was lame to do a print screen, a bit of editing and then pasting the image. So, I needed to come up with a new solution, a replacement to using images.

In the mean time, I seriously needed to make more people aware of nuget’s awesomeness. In Facebook C# SDK, we ship two files from the codeplex download tab – binary/assembly files (also available through nuget) and source code. But at the end of the day, the number of assembly files downloaded from codeplex always seems to be the higher than that of the source code and almost double than from nuget. (most probably VS2008 users.). So I decided that I ‘m going to start putting the Install-Package button in my blog on almost every blog post I do about Facebook C# SDK.

So my answer to both the above problems – a Javascript based solution that works with minimal amount of code the way you want too in any of your existing sites, just like Facebook’s like button, Google’s +1 button or Github’s “Fork me on Github” ribbons.

Enough of the history crap, show me the code

First of all you will need to add the following code just before the end of the body tag. nuget-button.min.js is download asynchronously using the below code.

<script type="text/javascript">
    (function () {
        var nb = document.createElement('script'); nb.type = 'text/javascript'; nb.async = true;
        nb.src = 'http://s.prabir.me/nuget-button/0.1/nuget-button.min.js';
        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(nb, s);
    })();
</script>

Then use “pre” tag and assign a class called “nuget-button” to it where ever you want the nuget Install-Package button to be rendered.

<pre class="nuget-button">Install-Package Facebook</pre>

You can see a live working example at http://s.prabir.me/nuget-button/0.1/nuget-button.htm

The best part about nuget-button is that you could now copy/paste the code and execute directly in the nuget package manager. No worries about Javascript being disabled coz pre is a standard html tag and will still get rendered.

Some of you may be wondering why its named “nuget-button” when there is nothing to do with behavior of a button like clicking. For vNEXT I plan to add anchor tag for the name of the project, so when you click, it will open http://nuget.org/List/Packages/Facebook. It is just the beginning and since all the code for nuget-button is open source, make sure to fork it or send suggestions/patches at https://github.com/prabirshrestha/nuget-button.

Here is a live sample showing nuget-button working in my blog.

Install-Package Facebook

And before I forget, nuget button is super lightweight (less than 3kb) with no dependencies on any javascript framework and yes it work on IE6 too.

This blog post is gonna be all about codes and how you can use FacebookClient class to make synchronous requests to the Facebook server. But first …

The basics

To access most of the protected resource in Facebook, you require access token. You can read more about it on how to get the access token in this post.

Install-Package Facebook

Graph Api (GET)

var fb = new FacebookClient();

var result = (IDictionary<string,object>)fb.Get("4");

var id = (string)result["id"];
var name = (string)result["name"];
var firstName = (string)result["first_name"];
var lastName = (string)result["last_name"];
var link = (string)result["link"];
var username = (string)result["username"];
var gender = (string)result["gender"];
var male = (string)result["locale"];

Passing Parameters

var fb = new FacebookClient();

var parameters = new Dictionary<string, object>();
parameters["fields"] = "id,name";

var result = (IDictionary<string, object>)fb.Get("4", parameters);
var id = (string)result["id"];
var name = (string)result["name"];

Note:

  • Cast to IDictionary<string, object> if it is a json object,
  • Cast to IList<object> if it is is a json array,
  • Cast to string, long, double or boolean accordingly depending on the json primitive types, or
  • use dynamic without explicitly casting. (supported only in frameworks where dynamic keyword is supported.)

Using dynamic

var fb = new FacebookClient();

dynamic result = fb.Get("4");

var id = result.id;
var name = result.name;
var firstName = result.first_name;
var lastName = result.last_name;
var link = result.link;
var username = result.username;
var gender = result.gender;
var male = result.locale;

Passing parameters the dynamic way.

(Use ExpandoObject instead of IDictionary<string, object>)

var fb = new FacebookClient();

dynamic parameters = new ExpandoObject();
parameters.fields = "id,name";

dynamic result = fb.Get("4", parameters);
var id = result.id;
var name = result.name;

Graph Api (POST)

var fb = new FacebookClient("access_token");

dynamic parameters = new ExpandoObject();
parameters.message = "Hello World!"

dynamic result = fb.Post("me/feed", parameters);
var id = result.id;

Graph Api (DELETE)

var fb = new FacebookClient("access_token");

dynamic result = fb.Delete(id);

Legacy REST API

Unlike graph api, you need to only pass parameters and make sure you set the “method” in the parameter.

var fb = new FacebookClient();

dynamic parameters = new ExpandoObject();
parameters.method = "users.getInfo";
parameters.uids = "4";
parameters.fields = new[] { "name", "first_name", "last_name" };

dynamic result = fb.Get(parameters);

FQL

var fb = new FacebookClient();

string query = string.Format("SELECT name FROM user WHERE uid='{0}'", 4);
dynamic result = fb.Query(query);

FQL-MultiQuery

var fb = new FacebookClient();

string query0 = string.Format("SELECT first_name FROM user WHERE uid='{0}'", "4");
string query1 = string.Format("SELECT last_name FROM user WHERE uid='{0}'", "4"); ;

dynamic result = fb.Query(query0, query1);
var result0 = result[0].fql_result_set;
var result1 = result[0].fql_result_set;

Batch Requests

Well … this one requires a whole new blog post. So here it goes

Getting user profile picture

Lot of devs have been asking how to retrieve the user profile picture. You don’t need to use FacebookClient to retrieve the picture. Just get the user id and generate the url for the picture.

string profilePictureUrl = string.Format("https://graph.facebook.com/{0}/picture", user_id);

Using Access Token

Most of the above samples were shown without using the access token, but most of the api requests requires using the access token. You can set the access token in the following ways.

var fb = new FacebookClient("access_token");

or you could also use the AccessToken property.

var fb = new FacebookClient();
fb.AccessToken = "access_token";

Using Application Access Token

There are times when you need to use the application access token instead of the user access token.

var oauthClient = new FacebookOAuthClient
                        {
                            AppId = "app_id",
                            AppSecret = "app_secret"
                        };
						
dynamic result = oauthClient.GetApplicationAccessToken();
string appAccessToken = result.access_token;

or you could also use the application access token as

string appAccessToken = string.Concat(appId, "|", appSecret);

or use the overload constructor of FacebookClient. The below code also sets the app access token automatically for you using the above method.

var fb = new FacebookClient("app_id", "app_secret");

OAuth 2.0 -  exchange code for access token

FacebookClient supports parsing only json responses. Due to this reason “oauth/access_token” token will not work when using FacebookClient.Get(“oauth/access_token”). Instead you will need to use a method in FacebookOAuthClient.

var oauthClient = new FacebookOAuthClient
                        {
                            AppId = "app_id",
                            AppSecret = "app_secret",
                            RedirectUri = new Uri("http://redirecturi.com")
                        };
						
dynamic result = oauthClient.ExchangeCodeForAccessToken("code");
var accessToken = result.access_token;

Handling Exceptions

If you want to create apps that are error free, make sure to catch exceptions that are thrown when you make requests to the facebook server.

try
{
    var fb = new FacebookClient();
    dynamic result = fb.Get("4");
    var name = result.name;
}
catch (FacebookApiException ex)
{
}
catch (Exception ex)
{
}

You could also catch more generic FacebookApiException and take actions accordingly.

try
{
    var fb = new FacebookClient();
    dynamic result = fb.Get("4");
    var name = result.name;
}
catch (FacebookApiLimitException ex)
{
}
catch (FacebookOAuthException ex)
{
}
catch (FacebookApiException ex)
{
}
catch (Exception ex)
{
}

v5.2 is out and its all about support for the new Javascript SDK with OAuth 2.0 enabled and the best part of it is that you require no server side changes to your existing code. Just update Facebook C# SDK to v5.2 and set oauth:true in your Javascript and it works out of the box.

Before you start typing “Update-Package FacebookWeb” here are some internals that you should be aware of.

1. Support for Javascript SDK with OAuth 2.0 enabled

First of all make sure you have enabled oauth during FB.init. You can read more on this at https://developers.facebook.com/blog/post/525/ (If you would like to continue using the Javascript SDK without oauth support, it is fine too as v5.2 still supports the old cookie format.)

FB.init({
   appId : YOUR_APP_ID,
   // other parameters,
   oauth : true
});

First difference internally is to understand the new cookie format used. The old Javascript SDK or the new Javascript SDK with oauth disabled, sets the cookie name as “fbs_<app_id>” while the new Javascript SDK uses “fbsr_<app_id>” when the user authorizes your app. Internally Facebook C# SDK checks for the new “fbsr_<app_id>” cookie first, if found it creates the session from the specified cookie else reverts back to the old “fbs_<app_id>” cookie. This way your existing code still works with oauth disabled, so no fear when updating your existing codes to v5.2.

Here is a big difference with the old and the new cookie. The new cookie doesn’t contain the access token but rather contains only code, which you can then exchange for access token. But Facebook C# SDK makes your life easier. Whenever you call the AccessToken property in the FacebookSession, the SDK is smart enough to retrieve the access token automatically for you if it hasn’t been set yet.

Here is a sample code on how it exchanges code the access token. Notice that it use FacebookApplication.Current to get the app_id and app_secret, so make sure to set the correct FacebookApplication either programmatically or using web.config file.

var oauthClient = new FacebookOAuthClient(FacebookApplication.Current);

var parameters = new Dictionary<string ,object>();
parameters["redirect_uri"] = null;

dynamic result = oauthClient.ExchangeCodeForAccessToken(code, parameters);

Make sure you set the redirect_uri as null in parameters and not oauthClient.RedirectUri = null; This is to maintain backward compatibility as redirect_uri is set to “http://www.facebook.com/connect/login_success.html” if oauthClient.RedirectUri is null.

FacebookSession is cached per request for optimal performance. This means it will call ExchangeCodeForAccessToken only once for the particular request as you can see the traffic in fiddler for the sample “CS-AspNetMvc3-JsSdk”.

image

This allows you to continue using your existing code without any changes even when oauth 2.0 is enabled in the new Javascript SDK.

[FacebookAuthorize]
public ActionResult Index()
{
    var fb = new FacebookWebClient();
    dynamic me = fb.Get("me");
    ViewBag.me = me;
    return View();
}

2. New Samples

All the samples have been rewritten with detailed comments and instructions. This will help you get started. You can now click “build.cmd” from the source code to build the dll files and then run the sample solution files. (Please do not use build.cmd to build dll files and use it in production, the recommend way is still to use rake. build.cmd is meant for samples only without installing ruby and rake.)

Even though you may be a web developer or silverlight or windows phone 7 developer make sure to check out “CS-WinForms.sln” samples. It includes samples showing graph api, legacy rest api, fql, fql muti-query and batch requests in both synchronous and asynchronous way.

There are a bunch of new changes in v5.2. Make sure to read CHANGES.txt for more details before updating.

(This feature requires Facebook C# SDK v5.1 at minimum.)

Recently Facebook supported uploading videos using graph api and multiple file uploads in a single batch request which have been both supported in the Facebook C# SDK. Though these are great features that enables us (the developers) to write cool apps using these api, you will soon notice the lack of user experience you can provide. Let us say you want to upload 10 photos each totaling up to 20mb (and assuming you don’t have the best internet speed) it would take quite some time for the upload to finish. Wouldn’t it be great if you could provide a sort of progress bar to the user? What if the user got an urgent phone call and need to go somewhere else and cancel the photo upload? Well starting from v5.1 these scenarios have been answered.

So first make sure you are at least on v5.1 if you aren’t.

(You can see this full working sample in the source code  Samples\CS-WinForms.sln or Samples\CSWinFormsUploadProgressAndCancel.sln file prior to v5.2)

Here is an existing code that you would use prior to v5.1

var mediaObject = new FacebookMediaObject
                                  {
                                      ContentType = "image/jpeg",
                                      FileName = Path.GetFileName(_filename)
                                  }
                                  .SetValue(File.ReadAllBytes(_filename));

var fb = new FacebookClient(_accessToken);
fb.PostCompleted += fb_PostCompleted;
fb.PostAsync("/me/photos", new Dictionary<string, object> { { "source", mediaObject } });

The above code uses a simple graph api photo upload as you would. (As for uploading 10 photos in a single batch request that I mentioned above is for your you to try it out Smile and get familiar with the new upload progress and cancellation apis).

Nothing fancy here. It just creates the media object and sets the value from the file and do a post to “/me/photos”.

To support the upload progress, you will need to add and event handler called UploadProgressChanged which will be called every time the progress changes. v5.1 also introduces a new event argument called FacebookUploadProgressChangedEventArgs. It contains useful information such as the progress percentage, number of bytes sent and total bytes to send.

 

fb.UploadProgressChanged += fb_UploadProgressChanged;

public void fb_UploadProgressChanged(object sender, FacebookUploadProgressChangedEventArgs e)
{
    progressBar1.BeginInvoke(
        new MethodInvoker(() =>
                              {
                                  var totalBytesToSend = e.TotalBytesToSend;
                                  var bytesSent = e.BytesSent;
                                  var state = e.UserState;
                                  progressBar1.Value = e.ProgressPercentage;
                              }));

}

progressBar1 is a standard WinForms control. Notice that I use BeginInvoke when I need to update the gui.

So now what about cancellation?

fb.CancelAsync() and that is it. Simple as it can be.

If want to add cancellation you might want to update your existing PostCompleted method. Make sure to check e.Cancelled first before anything else. You can then extract more information about the cancellation by checking the e.Error.

public void fb_PostCompleted(object sender, FacebookApiEventArgs e)
{
    if (e.Cancelled)
    {
        var cancellationError = e.Error;
        MessageBox.Show("Upload cancelled");
    }
    else if (e.Error == null)
    {
        // upload successful.
        MessageBox.Show(e.GetResultData().ToString());
    }
    else
    {
        // upload failed
        MessageBox.Show(e.Error.Message);
    }
}

Known issues on cancellation:

If you are using cancellation and call the CancelAsync() method, there are times when the request is completed and facebook has already sent you the response but you still get e.Cancelled as true. Since in .NET we can’t get the response on the HttpWebRequest which has been aborted, the Facebook C# SDK has no idea about whether the request was completed or not if the request was cancelled as the HttpWebResponse is always returned as null. Therefore, the SDK set the e.Cancelled as true.