{"id":444,"date":"2014-06-09T16:26:00","date_gmt":"2014-06-09T16:26:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/2014\/06\/09\/updating-the-mvc-facebook-api\/"},"modified":"2022-08-08T05:19:18","modified_gmt":"2022-08-08T12:19:18","slug":"updating-the-mvc-facebook-api","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/updating-the-mvc-facebook-api\/","title":{"rendered":"Updating the MVC Facebook API"},"content":{"rendered":"<p>Over the past several months Facebook made changes to their application development APIs that were incompatible with the MVC Facebook support.<\/p>\n<p>We have been working on updates while the Facebook API kept evolving, and on 4\/30\/2014 Facebook announced a <a href=\"https:\/\/developers.facebook.com\/blog\/post\/2014\/04\/30\/f8\/\">two-year stability guarantee<\/a>. This was a fantastic announcement because this ensured a similar stability for ASP.NET MVC developers developing Facebook applications. We&#8217;ve fixed the Facebook package and renamed it to <strong>Microsoft.AspNet.Facebook<\/strong>. This package is now available on NuGet.<\/p>\n<p><a href=\"https:\/\/aspnetwebstack.codeplex.com\/workitem\/list\/advanced?keyword=&amp;status=Closed&amp;type=All&amp;priority=All&amp;release=All&amp;assignedTo=All&amp;component=Facebook&amp;sortField=LastUpdatedDate&amp;sortDirection=Descending&amp;page=0&amp;reasonClosed=All\">Here<\/a>are the issues that we&rsquo;ve fixed.<\/p>\n<p>If you&rsquo;re new to the world of Facebook application development on MVC you can check out a Birthday application <a href=\"http:\/\/www.asp.net\/mvc\/tutorials\/mvc-4\/aspnet-mvc-facebook-birthday-app\">here<\/a>. Keep in mind this tutorial will be gradually updated so it may not be entirely accurate.<\/p>\n<h3>The important new stuff<\/h3>\n<p>The original Microsoft.AspNet.Mvc.Facebook package and corresponding API&rsquo;s at the time had no concept of optional or default permissions. This created friction with some of the updated prompt dialogs that Facebook released. To address this we&rsquo;ve made the Facebook&rsquo;s authorize filter more flexible by providing permission prompt hooks to control login dialog flow.<\/p>\n<p><em>FacebookAuthorizeFIlter<\/em> now exposes <em>OnPermissionPrompt<\/em> and an <em>OnDeniedPermissionPrompt<\/em> hooks.<strong> <\/strong>So what do these hooks do? Let&rsquo;s go over each in detail.<\/p>\n<h3>OnPermissionPrompt<\/h3>\n<p>Every time a prompt is about to be shown the <em>OnPermissionPrompt <\/em>is invoked and passed a <em>PermissionContext<\/em>. The hook enables you to modify the login flow by setting the context&#8217;s <em>Result <\/em>property just like you&rsquo;d do in an authorization filter.<\/p>\n<p>To utilize the <em>OnPermissionPrompt<\/em> you can create a <em>FacebookAuthorizeFilter<\/em>like so:<\/p>\n<pre class=\"code\"><span style=\"background: white;color: blue\">public class <\/span><span style=\"background: white;color: #2b91af\">CustomFacebookAuthorizeFilter <\/span><span style=\"background: white;color: black\">: <\/span><span style=\"background: white;color: #2b91af\">FacebookAuthorizeFilter <\/span><span style=\"background: white;color: black\">{ <\/span><span style=\"background: white;color: blue\">public <\/span><span style=\"background: white;color: black\">CustomFacebookAuthorizeFilter(<\/span><span style=\"background: white;color: #2b91af\">FacebookConfiguration <\/span><span style=\"background: white;color: black\">config) : <\/span><span style=\"background: white;color: blue\">base<\/span><span style=\"background: white;color: black\">(config) { } <\/span><span style=\"background: white;color: blue\">protected override void <\/span><span style=\"background: white;color: black\">OnPermissionPrompt(<\/span><span style=\"background: white;color: #2b91af\">PermissionContext <\/span><span style=\"background: white;color: black\">context) { <\/span><span style=\"background: white;color: green\">\/\/ This sets context.Result to ShowPrompt(context) (default behavior) <\/span><span style=\"background: white;color: blue\">base<\/span><span style=\"background: white;color: black\">.OnPermissionPrompt(context); } }<\/span><\/pre>\n<pre>&nbsp;<\/pre>\n<p>And then you can apply the filter the same way you&rsquo;d apply a <em>FacebookAuthorizeFilter<\/em>in the old world:<\/p>\n<pre class=\"code\"><span style=\"background: white;color: #2b91af\">GlobalFilters<\/span><span style=\"background: white;color: black\">.Filters.Add(<\/span><span style=\"background: white;color: blue\">new <\/span><span style=\"background: white;color: #2b91af\">CustomFacebookAuthorizeFilter<\/span><span style=\"background: white;color: black\">(yourFacebookConfiguration));<\/span><\/pre>\n<p>The default behavior of the <em>OnPermissionPrompt<\/em> hook is to set the <em>PermissionContext<\/em>&#8216;s result to a <em>ShowPromptActionResult<\/em> by calling into the <em>ShowPrompt<\/em> method. The source code of the <em>OnPermissionPrompt<\/em>method looks like this:<\/p>\n<pre class=\"code\"><span style=\"background: white;color: blue\">protected virtual void <\/span><span style=\"background: white;color: black\">OnPermissionPrompt(<\/span><span style=\"background: white;color: #2b91af\">PermissionContext <\/span><span style=\"background: white;color: black\">context) { context.Result = ShowPrompt(context); }<\/span><\/pre>\n<p>The <em>ShowPrompt <\/em>method returns an action result that shows the permission prompt to the user. We can do more though; if we really wanted to, we could redirect the user to a different action every time a prompt was about to be shown by overriding the default signature as shown:<\/p>\n<pre class=\"code\"><span style=\"background: white;color: blue\">protected override void <\/span><span style=\"background: white;color: black\">OnPermissionPrompt(<\/span><span style=\"background: white;color: #2b91af\">PermissionContext <\/span><span style=\"background: white;color: black\">context) { context.Result = <\/span><span style=\"background: white;color: blue\">new <\/span><span style=\"background: white;color: #2b91af\">RedirectToRouteResult<\/span><span style=\"background: white;color: black\">( <\/span><span style=\"background: white;color: blue\">new <\/span><span style=\"background: white;color: #2b91af\">RouteValueDictionary <\/span><span style=\"background: white;color: black\">{ { <\/span><span style=\"background: white;color: #a31515\">\"controller\"<\/span><span style=\"background: white;color: black\">, <\/span><span style=\"background: white;color: #a31515\">\"home\" <\/span><span style=\"background: white;color: black\">}, { <\/span><span style=\"background: white;color: #a31515\">\"action\"<\/span><span style=\"background: white;color: black\">, <\/span><span style=\"background: white;color: #a31515\">\"foo\" <\/span><span style=\"background: white;color: black\">} }); }<\/span><\/pre>\n<p>This would redirect us to the <em>Home<\/em> controller&rsquo;s action <em>Foo<\/em>instead of prompting the user for permissions.<\/p>\n<p>Lastly we could modify the <em>OnPermissionPrompt<\/em> method to ignore every prompt that&rsquo;s shown via setting the <em>PermissionContext<\/em>&#8216;s <em>Result<\/em>to be null:<\/p>\n<pre class=\"code\"><span style=\"background: white;color: blue\">protected override void <\/span><span style=\"background: white;color: black\">OnPermissionPrompt(<\/span><span style=\"background: white;color: #2b91af\">PermissionContext <\/span><span style=\"background: white;color: black\">context) { context.Result = <\/span><span style=\"background: white;color: blue\">null<\/span><span style=\"background: white;color: black\">; }<\/span><\/pre>\n<p>This would make it so we never prompt a user for permissions. This isn&rsquo;t ideal but it is possible.<\/p>\n<h4>OnDeniedPermissionPrompt<\/h4>\n<p>The <em>OnDeniedPermissionPrompt<\/em> is invoked when we detect that a user has revoked, declined, or skipped permissions. This occurs instead of the <em>OnPermissionPrompt<\/em> hook when there are denied permissions. Just like the <em>OnPermissionPrompt<\/em> we can utilize this hook by creating a <em>FacebookAuthorizeFilter<\/em>like so:<\/p>\n<pre class=\"code\"><span style=\"background: white;color: blue\">public class <\/span><span style=\"background: white;color: #2b91af\">CustomFacebookAuthorizeFilter <\/span><span style=\"background: white;color: black\">: <\/span><span style=\"background: white;color: #2b91af\">FacebookAuthorizeFilter <\/span><span style=\"background: white;color: black\">{ <\/span><span style=\"background: white;color: blue\">public <\/span><span style=\"background: white;color: black\">CustomFacebookAuthorizeFilter(<\/span><span style=\"background: white;color: #2b91af\">FacebookConfiguration <\/span><span style=\"background: white;color: black\">config) : <\/span><span style=\"background: white;color: blue\">base<\/span><span style=\"background: white;color: black\">(config) { } <\/span><span style=\"background: white;color: blue\">protected override void <\/span><span style=\"background: white;color: black\">OnDeniedPermissionPrompt(<\/span><span style=\"background: white;color: #2b91af\">PermissionContext <\/span><span style=\"background: white;color: black\">context) { <\/span><span style=\"background: white;color: green\">\/\/ Does nothing (default behavior to leave context.Result null) <\/span><span style=\"background: white;color: blue\">base<\/span><span style=\"background: white;color: black\">.OnDeniedPermissionPrompt(context); } }<\/span><\/pre>\n<p>And then just like the <em>OnPermissionPrompt<\/em> above you can apply the filter the same way you&rsquo;d apply a <em>FacebokAuthorizeFilter<\/em>in the old world:<\/p>\n<pre><span style=\"background: white;color: #2b91af\">GlobalFilters<\/span><span style=\"background: white;color: black\">.Filters.Add(<\/span><span style=\"background: white;color: blue\">new <\/span><span style=\"background: white;color: #2b91af\">CustomFacebookAuthorizeFilter<\/span><span style=\"background: white;color: black\">(yourFacebookConfiguration));<\/span><\/pre>\n<p>The default behavior of the <em>OnDeniedPermissionPrompt<\/em> hook is to leave the passed in <em>PermissionContext<\/em>&rsquo;s <em>Result <\/em>member null to ignore the &ldquo;denied&rdquo; permission prompt. The source code of the <em>OnDeniedPermissionPrompt<\/em>method looks like this:<\/p>\n<pre class=\"code\"><span style=\"background: white;color: blue\">protected virtual void <\/span><span style=\"background: white;color: black\">OnDeniedPermissionPrompt(<\/span><span style=\"background: white;color: #2b91af\">PermissionContext <\/span><span style=\"background: white;color: black\">context) { }<\/span><\/pre>\n<p>Here we&rsquo;re doing nothing so the <em>PermissionContext<\/em>&#8216;s <em>Result<\/em> member is null; this indicates that we do not want to show the permission prompt to the user. If we were to do the same thing as <em>OnPermissionPrompt<\/em> and set the <em>PermissionContext&#8217;<\/em>s <em>Result <\/em>to be a <em>ShowPromptActionResult <\/em>we&rsquo;d infinite loop in our login dialogs; the reason why is because every time the method is invoked there would still be denied permissions.<\/p>\n<p>Like the <em>OnPermissionPrompt <\/em>hook you can modify the login flow with the result that you return. For example, let&rsquo;s say we wanted to redirect to a &ldquo;skip&rdquo; handling page if we detect a user has skipped permissions:<\/p>\n<pre class=\"code\"><span style=\"background: white;color: blue\">protected override void <\/span><span style=\"background: white;color: black\">OnDeniedPermissionPrompt(<\/span><span style=\"background: white;color: #2b91af\">PermissionContext <\/span><span style=\"background: white;color: black\">context) { <\/span><span style=\"background: white;color: blue\">if <\/span><span style=\"background: white;color: black\">(context.SkippedPermissions.Any()) { context.Result = <\/span><span style=\"background: white;color: blue\">new <\/span><span style=\"background: white;color: #2b91af\">RedirectResult<\/span><span style=\"background: white;color: black\">(<\/span><span style=\"background: white;color: #a31515\">\"http:\/\/www.contoso.com\/SomeUrlToHandleSkips\"<\/span><span style=\"background: white;color: black\">); } }<\/span><\/pre>\n<h3>PermissionContext<\/h3>\n<p>In the previous sections I did not discuss the <em>PermissionContext<\/em> object that is passed into both the <em>OnPermissionPrompt<\/em> and <em>OnDeniedPermissionPrompt<\/em> hooks. This object exposes a significant amount of information that enable developers to modify the login flow. Let&rsquo;s examine what the <em>PermissionContext<\/em>has to offer:<\/p>\n<ul>\n<li><span style=\"background: white;color: #2b91af\">IEnumerable<\/span><span style=\"background: white;color: black\">&lt;<\/span><span style=\"background: white;color: blue\">string<\/span><span style=\"background: white;color: black\">&gt; DeclinedPermissions<\/span>\n<ul>\n<li>Permissions that were previously requested for but not granted for the lifetime of the application. This can happen by a user revoking, skipping or choosing not to allow permissions in the Facebook login dialog.<\/li>\n<\/ul>\n<\/li>\n<li><span style=\"background: white;color: #2b91af\">FacebookContext <\/span><span style=\"background: white;color: black\">FacebookContext<\/span>\n<ul>\n<li>Provides access to Facebook-specific information.<\/li>\n<\/ul>\n<\/li>\n<li><span style=\"background: white;color: #2b91af\">AuthorizationContext <\/span><span style=\"background: white;color: black\">FilterContext<\/span>\n<ul>\n<li>Provides access to filter information.<\/li>\n<\/ul>\n<\/li>\n<li><span style=\"background: white;color: #2b91af\">IEnumerable<\/span><span style=\"background: white;color: black\">&lt;<\/span><span style=\"background: white;color: blue\">string<\/span><span style=\"background: white;color: black\">&gt; MissingPermissions<\/span>\n<ul>\n<li>The entire list of missing permissions for the current page, including <em>DeclinedPermissions<\/em> and <em>SkippedPermissions<\/em>.<\/li>\n<\/ul>\n<\/li>\n<li><span style=\"background: white;color: #2b91af\">HashSet<\/span><span style=\"background: white;color: black\">&lt;<\/span><span style=\"background: white;color: blue\">string<\/span><span style=\"background: white;color: black\">&gt; RequiredPermissions<\/span>\n<ul>\n<li>The entire list of requested permissions for the current page. Includes permissions that were already prompted for.<\/li>\n<\/ul>\n<\/li>\n<li><span style=\"background: white;color: #2b91af\">IEnumerable<\/span><span style=\"background: white;color: black\">&lt;<\/span><span style=\"background: white;color: blue\">string<\/span><span style=\"background: white;color: black\">&gt; SkippedPermissions<\/span>\n<ul>\n<li>Permissions that were previously requested for but skipped. This can happen from a user hitting the &#8220;skip&#8221; button when requesting permissions.<\/li>\n<\/ul>\n<\/li>\n<li><span style=\"background: white;color: #2b91af\">ActionResult <\/span><span style=\"background: white;color: black\">Result<\/span>\n<ul>\n<li>The <em>ActionResult<\/em> that should be used to control the login flow. If value is null then we will continue onto the action that is intended to be invoked. Non-null values short-circuit the action.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>With all of the information the <em>PermissionContext <\/em>has to offer you should be able to fully control the login flow.<\/p>\n<h3>Hook flow chart<\/h3>\n<p>For reference sake I&rsquo;ve created a flow chart to indicate how Facebook&rsquo;s login dialog and our hooks interact.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2014\/06\/8130.clip_image001_thumb_1FD91F72.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2014\/06\/8130.clip_image001_thumb_1FD91F72.png\" alt=\"clip_image001\" width=\"683\" height=\"432\" border=\"0\" \/><\/a><\/p>\n<h3>Upgrading Existing Facebook Applications<\/h3>\n<p>To upgrade an existing Facebook application follow these steps:<\/p>\n<ol>\n<li>If your application does not currently run; migrate to the latest Facebook application platform.<\/li>\n<li>In the package manager console run: <em>Uninstall-Package Microsoft.AspNet.Mvc.Facebook<\/em><\/li>\n<li>Rename all Microsoft.AspNet.Mvc.Facebook namespaces to <strong>Microsoft.AspNet.Facebook<\/strong>.<\/li>\n<li>In the package manager console run: <em>Install-Package Microsoft.AspNet.Facebook<\/em><\/li>\n<\/ol>\n<h3>Conclusion<\/h3>\n<p>We&rsquo;d love to see people try out the new <strong>Microsoft.AspNet.Facebook<\/strong>package and let us know what you think. If you have any questions feel free to reach out below.<\/p>\n<p>To find or file issues do so <a href=\"https:\/\/aspnetwebstack.codeplex.com\/workitem\/list\/advanced?keyword=&amp;status=All&amp;type=All&amp;priority=All&amp;release=All&amp;assignedTo=All&amp;component=Facebook&amp;reasonClosed=All&amp;sortField=LastUpdatedDate&amp;sortDirection=Descending&amp;page=0\">here<\/a>.<\/p>\n<p><strong>Note:<\/strong> Facebook changed the way their &ldquo;user_friends&rdquo; permission works.&nbsp; It used to return all of a users friends and now only returns friends that also have your application.&nbsp; This will obviously be a limiter when using the existing Facebook template and the Birthday App tutorial.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Over the past several months Facebook made changes to their application development APIs that were incompatible with the MVC Facebook support. We have been working on updates while the Facebook API kept evolving, and on 4\/30\/2014 Facebook announced a two-year stability guarantee. This was a fantastic announcement because this ensured a similar stability for ASP.NET [&hellip;]<\/p>\n","protected":false},"author":420,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197],"tags":[4,7333,7470,7471,7472,7286],"class_list":["post-444","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","tag-net","tag-asp-net-mvc","tag-asp-net-mvc-facebook","tag-microsoft-aspnet-facebook","tag-microsoft-aspnet-mvc-facebook","tag-mvc"],"acf":[],"blog_post_summary":"<p>Over the past several months Facebook made changes to their application development APIs that were incompatible with the MVC Facebook support. We have been working on updates while the Facebook API kept evolving, and on 4\/30\/2014 Facebook announced a two-year stability guarantee. This was a fantastic announcement because this ensured a similar stability for ASP.NET [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/444","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/420"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=444"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/444\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=444"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=444"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=444"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}