Facebook C# SDK - What’s new in v5.3

Most of you by now might have got the hands on Visual Studio 11 Developer Preview and have been playing around with the new async/await features of .net 4.5. If you have been following me on twitter @prabirshrestha, you might have noticed that I had posted a sample library called “Facebook.Extensions.Task” in github earlier this year for those who wanted to play with the Async CTP. The good news is that starting with v5.3, async/await is now a first class citizen.

Some you might feel reluctant to update to a developer preview of .net 4.5 to use these new features. Well, you guys are not out of luck. Since Task Parallel Library is supported in .net 4.0 you guys can start playing with it now.

You can checkout the sample called “CS-WinForms-AsyncAwait.sln” which demonstrates the usage of async in Graph Api, Legacy Rest Api, Fql, Fql multi-query and even progress and cancellation support.

Moving to Asynchronous methods with Async/Await

Here is the hello world of Facebook. First using the synchronous method.

private void GraphApiExample()
{
    try
    {
        var fb = new FacebookClient();
        dynamic result = fb.Get("4");
        string name = result.name;
        Console.WriteLine(name);
    }
    catch (FacebookApiException ex)
    {
        Console.WriteLine(ex.Message);
    }
}

And here is the async equivalent method.

async private void GraphApiAsyncExample()
{
    try
    {
        var fb = new FacebookClient();
        dynamic result = await fb.GetTaskAsync("4");
        string name = result.name;
        Console.WriteLine(name);
    }
    catch (FacebookApiException ex)
    {
        Console.WriteLine(ex.Message);
    }
}

Only 3 simple changes required to convert synchronous method to asynchronous methods.

  1. add “async” keyword in the method.
  2. change fb.Get() to fb.GetTaskAsync()
  3. add await before fb.GetTaskAsync() methods.

The best part is that your workflow for async methods will now remain same as in synchronous methods with no callbacks. Handling exceptions just got easier for async methods.

(There are tons of new interesting stuffs you can do with async. In the upcoming days and weeks, I will be blogging more on this. In the mean time you can see all the features in “CS-WinForms-AsyncAwait.sln” sample.

Multiple async calls on the same FacebookClient instance

One of the common complains we have received from the folks who use Async methods was that they need to create a new instance of FacebookClient for each different async method calls. Though this is by design, we have improved it for XTaskAsync methods. Now you can call TaskAsync methods on the same instance of FacebookClient. (In order to maintain backward compatibility, XAsync() methods will still require new instance while XTaskAsync() won’t.)

This is now possible staring from v5.3

async private void GraphApiAsyncExample()
{
    var fb = new FacebookClient();
    dynamic result1 = await fb.GetTaskAsync("4");
    dynamic result2 = await fb.GetTaskAsync("5");
}

CancellationToken support

With the introduction of CancellationToken in .net 4.0 with Task Parallel Library, we now have a unified way to cancel a Task in .net.

You will need to add an extract catch block to handle OperationCancelledException. Here is a sample code showing how to cancel a Facebook request.

CancellationTokenSource _cts;

async private void btnUpload_Click(object sender, EventArgs e)
{    
    try
    {
        _cts = new CancellationTokenSource();

        var fb = new FacebookClient();
        dynamic parameters = new ExpandoObject();
        // code emited for brevity.
        dynamic result = await fb.PostTaskAsync("me/videos", parameters, _cts.Token);
    }
    catch(FacebookApiException ex)
    {
        MessageBox.Show(ex.Message);
    }
    catch(OperationCanceledException ex)
    {
        MessageBox.Show("Upload Cancelled");
    }
}

private void btnCancel_Click(object sender, EventArgs e)
{
    if (_cts != null)
        _cts.Cancel();
}

Note: Unlike XAsync() event based async methods, you shouldn’t call CancelAsync method to cancel the XTaskAsync methods, but rather use the CancellationToken.

Since XTaskAsync methods can execute on the same instance of FacebookClient you can either use the same cancellation token or different cancellation token depending on your requirements.

Upload Progress Reporting

If you are using .net 4.0 you will need to continue using UploadProgressChanged event handler as described in http://blog.prabir.me/post/Facebook-CSharp-SDK-Upload-Progress.aspx

But if you are using .net 4.5 you can use the new methods that were introduced to simplify the asynchrony in .net 4.5 using IProgress<T>.

Here is the sample showing the usage of both cancellation and upload progress reporting.

CancellationTokenSource _cts;

async private void CancellationAndProgressSupport()
{    
    try
    {
        _cts = new CancellationTokenSource();

        var fb = new FacebookClient();
        dynamic parameters = new ExpandoObject();
        // code emited for brevity.

        var uploadProgress = new Progress<FacebookUploadProgressChangedEventArgs>();
        uploadProgress.ProgressChanged += (o, args) => progressBar1.Value = args.ProgressPercentage;

        dynamic result = await fb.PostTaskAsync("me/videos", parameters, null, _cts.Token, uploadProgress);
    }
    catch(FacebookApiException ex)
    {
        MessageBox.Show(ex.Message);
    }
    catch(OperationCanceledException ex)
    {
        MessageBox.Show("Upload Cancelled");
    }
}

private void btnCancel_Click(object sender, EventArgs e)
{
    if (_cts != null)
        _cts.Cancel();
}

There are new overload methods for BatchTaskAsync and PostTaskAsync that includes IProgress<FacebookUploadProgressChangedEventArgs> as a parameter.

What about my investments in event based XAsync() methods?

No worries. We have no plans to remove them and will remain there although XTaskAsync() methods would be the recommended way to go. (Internally XTaskAsync methods actually makes use of XAsync methods. This also means that any patch applied to .net 3.5 will also be propagated to .net 4.5 builds. In the near future I will blog about how to convert your old event based apis to use the new Task Parallel Library features.)

If you are still using the FacebookApp class which was marked [Obsolete], make sure to change it to FacebookClient/FacebookWebClient as we are now removing it from .net 4.5 builds although it will still be available for .net 3.5 and .net 4.0 builds.

Asynchrony with ASP.NET MVC4

Internally since Facebook.Web.Mvc.dll in .net 4.5 build does not use any new features of MVC4, it still references MVC3. A binding redirect in web.config is enough to tell Facebook.Web.Mvc.dll to use MVC4.

With ASP.NET MVC 4, you can now execute asynchronous methods easily inside of MVC Actions.

[AsyncTimeout(2500)]
[HandleError(ExceptionType = typeof(TaskCanceledException), View = "TimedOut")]
[FacebookAuthorize(Permissions = ExtendedPermissions, LoginUrl = "/Account/LogOn?ReturnUrl=~/")]
async public Task<ActionResult> Index()
{
    dynamic result = await _fb.GetTaskAsync("me");
    ViewBag.me = result;

    return View();
}

Attributes will continue using the synchronous methods, while you can call the asynchronous versions inside the Action. You can also add a default time out using AsyncTimeout action filter which is part of ASP.NET MVC. Incase the action times out, you can handle the error using HandleError action filter which is again a part of ASP.NET MVC.

FQL using Graph Api

Facebook recently supported issuing FQL queries using the Graph Api. Starting from v5.3 the Facebook C# SDK will be using the Graph Api instead of Legacy Rest Api to perform fql queries.

Here is how you would execute the query method in Graph Api without using Query helper methods.

var fb = new FacebookClient("access_token");
dynamic parameters = new ExpandoObject();
parameters.q = "SELECT name, uid FROM user WHERE uid = me()";
dynamic result = fb.Get("fql", parameters);
Console.WriteLine(result);

You would then get a result which looks similar to this:

{"data":[{"name":"Prabir Shrestha","uid":123456}]}

There are two stuffs to notice from using the legacy rest api.

  1. The result is wrapped in “data”
  2. uid is of type long instead of string

But if you execute the FQL methods using the Query() method as below.

var fb = new FacebookClient("access_token");
dynamic result = fb.Query("SELECT name, uid FROM user WHERE uid = me()");
Console.WriteLine(result);

It will remove “data” and return the value of data in order to maintain compatibility with previous versions of the sdk. The result will now look as follows:

[{"name":"Prabir Shrestha","uid":123456}]

If you use Query() methods make sure you handle the type of the ids correctly. It is same for multi-query – “data” is automatically removed. Make sure to handle this breaking change when updating to v5.3.

Removed dependency from CodeContracts

Though code contracts is an awesome tool, we have decided to remove it due to lack of early support for new releases of Visual Studio/ .net Framework.

Channel.html

There will be a new nuget package called “Facebook.channel” which will contain the channel file for Facebook Javascript SDK. (Facebook.xd_receiver will no longer be maintained.) You can read more about the channel file at https://developers.facebook.com/docs/reference/javascript/. In short, channel file address some issues with cross domain communication in certain browsers. Since this is a beta release it is not yet available from nuget.org. You will need to manually add it from “Build\NuGet\Facebook.channel\Content\fbchannel.ashx.pp”

You can then initialize the Facebook Javascript SDK using the following code.

<div id="fb-root"></div>
<div class="fb-login-button" data-show-faces="true" data-width="200" data-max-rows="1" perms="user_about_me"></div>
<script type="text/javascript">
    window.fbAsyncInit = function () {
        FB.init({ appId: '@Facebook.FacebookApplication.Current.AppId', channelURL: '@Request.Url.Scheme://@Request.Url.Authority@Url.Content("~/fbchannel.ashx")', cookie: true, xfbml: true, oauth: true });
        FB.Event.subscribe('auth.login', function (response) { window.location.reload(); });
        FB.Event.subscribe('auth.logout', function (response) { window.location.reload(); });
    };

    (function(d){
        var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
        js = d.createElement('script'); js.id = id; js.async = true;
        js.src = "//connect.facebook.net/en_US/all.js";
        d.getElementsByTagName('head')[0].appendChild(js);
    }(document));
</script>

The above code is taken from Facebook.JavascriptMvcWebsite nuget package. It loads the Facebook Javascript SDK asynchronously and also uses the new HTML 5 Facebook login button instead of XFBML. (https://developers.facebook.com/docs/reference/plugins/login/). The Javascript SDK is also initialized with the channelURL.

New OpenGraph Samples

We have also added a new Sample called “CS-AspNetMvc3-JsSdk-OpenGraph.sln” demonstrating the use of Open Graph based on the PHP sample https://developers.facebook.com/blog/post/564/ with slight modifications.

New OAuth 2.0 sample with FormsAuthentication

Another new sample called “CS-AspNetMvc3-WithoutJsSdk.sln” has been added which demonstrates the use of OAuth 2.0 with ASP.NET Forms Authentication. The sample also includes prevention of Cross Site Request Forgery (CSRF) attacks and Open Redirection Attack during login.

(Since .net 4.5 is in Developer Preview status, we will not be distributing the compiled binaries. You will need to grab the source code and build it manually.)

Though this release updates the minor version number there are tons of new cool features. Make sure to read the CHANGES.txt before updating.

If you want to catch up with the latest updates make sure to like us on our official Facebook Page - https://www.facebook.com/csharpsdk or follow us on twitter at @csharpsdk

blog comments powered by Disqus