Created
          February 2, 2012 22:39 
        
      - 
      
- 
        Save madd0/1726246 to your computer and use it in GitHub Desktop. 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | // -------------------------------- | |
| // <copyright file="FacebookOAuthClient.cs" company="Thuzi LLC (www.thuzi.com)"> | |
| // Microsoft Public License (Ms-PL) | |
| // </copyright> | |
| // <author>Nathan Totten (ntotten.com), Jim Zimmerman (jimzimmerman.com) and Prabir Shrestha (prabir.me)</author> | |
| // <license>Released under the terms of the Microsoft Public License (Ms-PL)</license> | |
| // <website>http://facebooksdk.codeplex.com</website> | |
| // --------------------------------- | |
| namespace Facebook | |
| { | |
| using System; | |
| using System.Collections.Generic; | |
| using System.ComponentModel; | |
| using System.IO; | |
| using System.Net; | |
| using FluentHttp; | |
| /// <summary> | |
| /// Represents the Facebook OAuth Client. | |
| /// </summary> | |
| public class FacebookOAuthClient | |
| { | |
| /// <summary> | |
| /// The Facebook AppId. | |
| /// </summary> | |
| private string _appId; | |
| /// <summary> | |
| /// The Facebook AppSecret. | |
| /// </summary> | |
| private string _appSecret; | |
| /// <summary> | |
| /// Initializes a new instance of the <see cref="FacebookOAuthClient"/> class. | |
| /// </summary> | |
| public FacebookOAuthClient() | |
| { | |
| } | |
| /// <summary> | |
| /// Initializes a new instance of the <see cref="FacebookOAuthClient"/> class. | |
| /// </summary> | |
| /// <param name="facebookApplication"> | |
| /// The Facebook application. | |
| /// </param> | |
| public FacebookOAuthClient(IFacebookApplication facebookApplication) | |
| { | |
| if (facebookApplication != null) | |
| { | |
| _appId = facebookApplication.AppId; | |
| _appSecret = facebookApplication.AppSecret; | |
| } | |
| } | |
| /// <summary> | |
| /// Event handler for application access token completion. | |
| /// </summary> | |
| public event EventHandler<FacebookApiEventArgs> GetApplicationAccessTokenCompleted; | |
| /// <summary> | |
| /// Event handler for application access token completion. | |
| /// </summary> | |
| public event EventHandler<FacebookApiEventArgs> ExchangeCodeForAccessTokenCompleted; | |
| /// <summary> | |
| /// Gets or sets the app id. | |
| /// </summary> | |
| public virtual string AppId { get { return _appId; } set { _appId = value; } } | |
| /// <summary> | |
| /// Gets or sets the app secret. | |
| /// </summary> | |
| public virtual string AppSecret { get { return _appSecret; } set { _appSecret = value; } } | |
| /// <summary> | |
| /// Gets or sets the redirect uri. | |
| /// </summary> | |
| public virtual Uri RedirectUri { get; set; } | |
| /// <summary> | |
| /// Gets the aliases to Facebook domains. | |
| /// </summary> | |
| protected virtual Dictionary<string, Uri> DomainMaps | |
| { | |
| get | |
| { | |
| // return IsBeta ? FacebookUtils.DomainMapsBeta : FacebookUtils.DomainMaps; | |
| return FacebookUtils.DomainMaps; | |
| } | |
| } | |
| #region Login url helpers | |
| /// <summary> | |
| /// Gets the login url. | |
| /// </summary> | |
| /// <returns> | |
| /// Returns the Facebook login url. | |
| /// </returns> | |
| public virtual Uri GetLoginUrl() | |
| { | |
| return GetLoginUrl(null); | |
| } | |
| /// <summary> | |
| /// Gets the login url. | |
| /// </summary> | |
| /// <param name="parameters"> | |
| /// The parameters. | |
| /// </param> | |
| /// <returns> | |
| /// Returns the Facebook login url. | |
| /// </returns> | |
| /// <remarks> | |
| /// http://developers.facebook.com/docs/reference/dialogs/oauth | |
| /// Parameters that can be used: | |
| /// client_id : Your application's identifier. This is called client_id instead of app_id for this particular method to be compliant with the OAuth 2.0 specification. Required, but automatically specified by most SDKs. | |
| /// redirect_uri : The URL to redirect to after the user clicks a button on the dialog. Required, but automatically specified by most SDKs. | |
| /// scope : Optional. A comma-delimited list of permissions. | |
| /// state : Optional. An opaque string used to maintain application state between the request and callback. When Facebook redirects the user back to your redirect_uri, this value will be included unchanged in the response. | |
| /// response_type : Optional, default is token. The requested response: an access token (token), an authorization code (code), or both (code token). | |
| /// display : The display mode in which to render the dialog. The default is page on the www subdomain and wap on the m subdomain. This is automatically specified by most SDKs. (For WP7 builds it is set to touch.) | |
| /// </remarks> | |
| public virtual Uri GetLoginUrl(IDictionary<string, object> parameters) | |
| { | |
| var defaultParameters = new Dictionary<string, object>(); | |
| defaultParameters["client_id"] = AppId; | |
| defaultParameters["redirect_uri"] = RedirectUri ?? new Uri("http://www.facebook.com/connect/login_success.html"); | |
| #if WINDOWS_PHONE | |
| defaultParameters["display"] = "touch"; | |
| #endif | |
| var mergedParameters = FacebookUtils.Merge(defaultParameters, parameters); | |
| // check if client_id and redirect_uri is not null or empty. | |
| if (mergedParameters["client_id"] == null || string.IsNullOrEmpty(mergedParameters["client_id"].ToString())) | |
| { | |
| throw new ArgumentException("client_id required."); | |
| } | |
| if (mergedParameters["redirect_uri"] == null || string.IsNullOrEmpty(mergedParameters["redirect_uri"].ToString())) | |
| { | |
| throw new ArgumentException("redirect_uri required."); | |
| } | |
| // seems like if we don't do this and rather pass the original uri object, | |
| // it seems to have http://localhost:80/csharpsamples instead of | |
| // http://localhost/csharpsamples | |
| // notice the port number, that shouldn't be there. | |
| // this seems to happen for iis hosted apps. | |
| mergedParameters["redirect_uri"] = mergedParameters["redirect_uri"].ToString(); | |
| var url = "http://www.facebook.com/dialog/oauth/?" + FacebookUtils.ToJsonQueryString(mergedParameters); | |
| // In order to be compliant with the OAuth spec Facebook have made changes to their auth APIs. | |
| // As part of this update, they will be deprecating 'code_and_token' and need developers | |
| // to use 'code%20token'. Everything is identical, just replace '_and_' with encoded | |
| // <space> '%20'. | |
| // url = url.Replace("response_type=code+token", "response_type=code%20token"); | |
| return new Uri(url); | |
| } | |
| /// <summary> | |
| /// Gets the login url. | |
| /// </summary> | |
| /// <param name="appId"> | |
| /// The app id. | |
| /// </param> | |
| /// <param name="redirectUri"> | |
| /// The redirect Uri. | |
| /// </param> | |
| /// <returns> | |
| /// The url to navigate. | |
| /// </returns> | |
| public static Uri GetLoginUrl(string appId, Uri redirectUri) | |
| { | |
| return GetLoginUrl(appId, redirectUri, null, null); | |
| } | |
| /// <summary> | |
| /// Gets the login url. | |
| /// </summary> | |
| /// <param name="appId"> | |
| /// The app id. | |
| /// </param> | |
| /// <param name="redirectUri"> | |
| /// The redirect Uri. | |
| /// </param> | |
| /// <param name="extendedPermissions"> | |
| /// The extended permissions (scope). | |
| /// </param> | |
| /// <returns> | |
| /// The url to navigate. | |
| /// </returns> | |
| public static Uri GetLoginUrl(string appId, Uri redirectUri, string[] extendedPermissions) | |
| { | |
| return GetLoginUrl(appId, redirectUri, extendedPermissions, null); | |
| } | |
| /// <summary> | |
| /// Gets the login url. | |
| /// </summary> | |
| /// <param name="appId"> | |
| /// The app id. | |
| /// </param> | |
| /// <param name="redirectUri"> | |
| /// The redirect Uri. | |
| /// </param> | |
| /// <param name="extendedPermissions"> | |
| /// The extended permissions (scope). | |
| /// </param> | |
| /// <param name="loginParameters"> | |
| /// The login parameters. | |
| /// </param> | |
| /// <returns> | |
| /// The url to navigate. | |
| /// </returns> | |
| public static Uri GetLoginUrl(string appId, Uri redirectUri, string[] extendedPermissions, IDictionary<string, object> loginParameters) | |
| { | |
| if (string.IsNullOrEmpty(appId)) | |
| throw new ArgumentNullException("appId"); | |
| var oauth = new FacebookOAuthClient { AppId = appId, RedirectUri = redirectUri }; | |
| var defaultLoginParameters = new Dictionary<string, object> | |
| { | |
| { "response_type", "code" }, // make it "code" by default for security reasons. | |
| #if WINDOWS_PHONE | |
| { "display", "touch" } | |
| #else | |
| { "display", "popup" } | |
| #endif | |
| }; | |
| if (extendedPermissions != null && extendedPermissions.Length > 0) | |
| { | |
| defaultLoginParameters["scope"] = string.Join(",", extendedPermissions); | |
| } | |
| var mergedLoginParameters = FacebookUtils.Merge(defaultLoginParameters, loginParameters); | |
| var loginUrl = oauth.GetLoginUrl(mergedLoginParameters); | |
| return loginUrl; | |
| } | |
| #endregion | |
| #region Application Access Token | |
| #if !(SILVERLIGHT || WINRT) | |
| /// <summary> | |
| /// Gets the application access token. | |
| /// </summary> | |
| /// <returns> | |
| /// The application access token. | |
| /// </returns> | |
| public virtual object GetApplicationAccessToken() | |
| { | |
| return GetApplicationAccessToken(null); | |
| } | |
| /// <summary> | |
| /// Gets the application access token. | |
| /// </summary> | |
| /// <param name="parameters"> | |
| /// The parameters. | |
| /// </param> | |
| /// <returns> | |
| /// The application access token. | |
| /// </returns> | |
| public virtual object GetApplicationAccessToken(IDictionary<string, object> parameters) | |
| { | |
| string name, path; | |
| var pars = BuildApplicationAccessTokenParameters(parameters, out name, out path); | |
| return BuildApplicationAccessTokenResult(OAuthRequest(name, path, pars)); | |
| } | |
| #endif | |
| /// <summary> | |
| /// Gets the application access token asynchronously. | |
| /// </summary> | |
| /// <param name="parameters"> | |
| /// The parameters. | |
| /// </param> | |
| /// <param name="userToken"> | |
| /// The user token. | |
| /// </param> | |
| public virtual void GetApplicationAccessTokenAsync(IDictionary<string, object> parameters, object userToken) | |
| { | |
| string name, path; | |
| var pars = BuildApplicationAccessTokenParameters(parameters, out name, out path); | |
| OAuthRequestAsync( | |
| name, path, pars, userToken, | |
| json => BuildApplicationAccessTokenResult(json).ToString(), | |
| (o, e) => | |
| { | |
| if (GetApplicationAccessTokenCompleted != null) | |
| { | |
| GetApplicationAccessTokenCompleted(this, e); | |
| } | |
| }); | |
| } | |
| /// <summary> | |
| /// Gets the application access token asynchronously. | |
| /// </summary> | |
| /// <param name="userToken"> | |
| /// The user token. | |
| /// </param> | |
| public virtual void GetApplicationAccessTokenAsync(object userToken) | |
| { | |
| GetApplicationAccessTokenAsync(null, userToken); | |
| } | |
| /// <summary> | |
| /// Gets the application access token asynchronously. | |
| /// </summary> | |
| public virtual void GetApplicationAccessTokenAsync() | |
| { | |
| GetApplicationAccessTokenAsync(null, null); | |
| } | |
| private IDictionary<string, object> BuildApplicationAccessTokenParameters(IDictionary<string, object> parameters, out string name, out string path) | |
| { | |
| name = FacebookUtils.DOMAIN_MAP_GRAPH; | |
| path = "/oauth/access_token"; | |
| var defaultParameters = new Dictionary<string, object> | |
| { | |
| { "client_id", AppId }, | |
| { "client_secret", AppSecret }, | |
| { "grant_type", "client_credentials" } | |
| }; | |
| var mergedParameters = FacebookUtils.Merge(defaultParameters, parameters); | |
| if (mergedParameters["client_id"] == null || string.IsNullOrEmpty(mergedParameters["client_id"].ToString())) | |
| throw new ArgumentException("client_id required"); | |
| if (mergedParameters["client_secret"] == null || string.IsNullOrEmpty(mergedParameters["client_secret"].ToString())) | |
| throw new ArgumentException("client_secret required"); | |
| if (mergedParameters["grant_type"] == null || string.IsNullOrEmpty(mergedParameters["grant_type"].ToString())) | |
| throw new ArgumentException("grant_type required"); | |
| return mergedParameters; | |
| } | |
| private object BuildApplicationAccessTokenResult(string responseString) | |
| { | |
| var returnParameter = new JsonObject(); | |
| FacebookUtils.ParseQueryParametersToDictionary("?" + responseString, returnParameter); | |
| return returnParameter; | |
| } | |
| #endregion | |
| #region ExchangeCodeForAccessToken | |
| #if !(SILVERLIGHT || WINRT) | |
| /// <summary> | |
| /// Exchange code for access token. | |
| /// </summary> | |
| /// <param name="code"> | |
| /// The code. | |
| /// </param> | |
| /// <param name="parameters"> | |
| /// The parameters. | |
| /// </param> | |
| /// <returns> | |
| /// The json result. | |
| /// </returns> | |
| public virtual object ExchangeCodeForAccessToken(string code, IDictionary<string, object> parameters) | |
| { | |
| string name, path; | |
| var defaultParameters = new Dictionary<string, object> { { "code", code } }; | |
| var mergedParameters = FacebookUtils.Merge(defaultParameters, parameters); | |
| mergedParameters = BuildExchangeCodeForAccessTokenParameters(mergedParameters, out name, out path); | |
| return BuildExchangeCodeForAccessTokenResult(OAuthRequest(name, path, mergedParameters)); | |
| } | |
| /// <summary> | |
| /// Exchange code for access token. | |
| /// </summary> | |
| /// <param name="code"> | |
| /// The code. | |
| /// </param> | |
| /// <returns> | |
| /// The json result. | |
| /// </returns> | |
| public virtual object ExchangeCodeForAccessToken(string code) | |
| { | |
| return ExchangeCodeForAccessToken(code, null); | |
| } | |
| #endif | |
| /// <summary> | |
| /// Exchange code for access token asynchronously. | |
| /// </summary> | |
| /// <param name="code"> | |
| /// The code. | |
| /// </param> | |
| /// <param name="parameters"> | |
| /// The parameters. | |
| /// </param> | |
| /// <param name="userToken"> | |
| /// The user token. | |
| /// </param> | |
| public virtual void ExchangeCodeForAccessTokenAsync(string code, IDictionary<string, object> parameters, object userToken, string urlScheme = null) | |
| { | |
| string name, path; | |
| var defaultParameters = new Dictionary<string, object> { { "code", code } }; | |
| var mergedParameters = FacebookUtils.Merge(defaultParameters, parameters); | |
| mergedParameters = BuildExchangeCodeForAccessTokenParameters(mergedParameters, out name, out path, urlScheme); | |
| OAuthRequestAsync( | |
| name, path, mergedParameters, userToken, | |
| json => BuildExchangeCodeForAccessTokenResult(json).ToString(), | |
| (o, e) => | |
| { | |
| if (ExchangeCodeForAccessTokenCompleted != null) | |
| ExchangeCodeForAccessTokenCompleted(this, e); | |
| }); | |
| } | |
| /// <summary> | |
| /// Exchange code for access token asynchronously. | |
| /// </summary> | |
| /// <param name="code"> | |
| /// The code. | |
| /// </param> | |
| /// <param name="parameters"> | |
| /// The parameters. | |
| /// </param> | |
| public virtual void ExchangeCodeForAccessTokenAsync(string code, IDictionary<string, object> parameters) | |
| { | |
| ExchangeCodeForAccessTokenAsync(code, parameters, null, null); | |
| } | |
| /// <summary> | |
| /// Exchange code for access token asynchronously. | |
| /// </summary> | |
| /// <param name="code"> | |
| /// The code. | |
| /// </param> | |
| public virtual void ExchangeCodeForAccessTokenAsync(string code, string urlScheme = null) | |
| { | |
| ExchangeCodeForAccessTokenAsync(code, null, null, urlScheme); | |
| } | |
| private IDictionary<string, object> BuildExchangeCodeForAccessTokenParameters(IDictionary<string, object> parameters, out string name, out string path, string urlScheme = null) | |
| { | |
| name = FacebookUtils.DOMAIN_MAP_GRAPH; | |
| path = "oauth/access_token"; | |
| var defaultUrl = new UriBuilder("http://www.facebook.com/connect/login_success.html"); | |
| if (urlScheme != null) | |
| { | |
| defaultUrl.Scheme = urlScheme; | |
| defaultUrl.Port = -1; | |
| } | |
| var pars = new Dictionary<string, object>(); | |
| pars["client_id"] = AppId; | |
| pars["client_secret"] = AppSecret; | |
| pars["redirect_uri"] = RedirectUri ?? defaultUrl.Uri; | |
| pars["code"] = null; | |
| var mergedParameters = FacebookUtils.Merge(pars, parameters); | |
| if (mergedParameters["client_id"] == null || string.IsNullOrEmpty(mergedParameters["client_id"].ToString())) | |
| throw new Exception("ClientID required."); | |
| if (mergedParameters["client_secret"] == null || string.IsNullOrEmpty(mergedParameters["client_secret"].ToString())) | |
| throw new Exception("ClientSecret required"); | |
| if (mergedParameters["redirect_uri"] != null && | |
| !string.IsNullOrEmpty(mergedParameters["redirect_uri"].ToString())) | |
| { | |
| // seems like if we don't do this and rather pass the original uri object, | |
| // it seems to have http://localhost:80/csharpsamples instead of | |
| // http://localhost/csharpsamples | |
| // notice the port number, that shouldn't be there. | |
| // this seems to happen for iis hosted apps. | |
| mergedParameters["redirect_uri"] = mergedParameters["redirect_uri"].ToString(); | |
| } | |
| if (mergedParameters["code"] == null || string.IsNullOrEmpty(mergedParameters["code"].ToString())) | |
| throw new Exception("code required"); | |
| return mergedParameters; | |
| } | |
| private object BuildExchangeCodeForAccessTokenResult(string json) | |
| { | |
| var returnParameter = new JsonObject(); | |
| FacebookUtils.ParseQueryParametersToDictionary("?" + json, returnParameter); | |
| // access_token=string&expires=long or access_token=string | |
| // Convert to JsonObject to support dynamic and be consistent with the rest of the library. | |
| var jsonObject = new JsonObject(); | |
| if (returnParameter.ContainsKey("access_token")) | |
| { | |
| jsonObject["access_token"] = returnParameter["access_token"]; | |
| } | |
| // check if expires exist coz for offline_access it is not present. | |
| if (returnParameter.ContainsKey("expires")) | |
| { | |
| jsonObject.Add("expires", Convert.ToInt64(returnParameter["expires"])); | |
| } | |
| return jsonObject; | |
| } | |
| #endregion | |
| #if !(SILVERLIGHT || WINRT) | |
| internal protected virtual string OAuthRequest(string name, string path, IDictionary<string, object> parameters) | |
| { | |
| if (string.IsNullOrEmpty(name)) | |
| throw new ArgumentNullException("name"); | |
| parameters = parameters ?? new Dictionary<string, object>(); | |
| path = FacebookUtils.ParseQueryParametersToDictionary(path, parameters); | |
| if (!string.IsNullOrEmpty(path) && path.StartsWith("/", StringComparison.OrdinalIgnoreCase)) | |
| path = path.Substring(1, path.Length - 1); | |
| var requestUrl = GetUrl(name, path, parameters); | |
| var httpWebRequest = CreateHttpWebRequest(requestUrl); | |
| httpWebRequest.Method = "GET"; | |
| var httpHelper = new HttpHelper(httpWebRequest); | |
| Stream responseStream; | |
| try | |
| { | |
| responseStream = httpHelper.OpenRead(); | |
| } | |
| catch (WebExceptionWrapper ex) | |
| { | |
| if (ex.GetResponse() == null) | |
| throw; | |
| responseStream = httpHelper.OpenRead(); | |
| } | |
| Exception exception; | |
| string responseString = ProcessResponse(httpHelper, responseStream, out exception); | |
| if (exception == null) | |
| return responseString; | |
| throw exception; | |
| } | |
| #endif | |
| internal protected virtual void OAuthRequestAsync(string name, string path, IDictionary<string, object> parameters, object userToken, Func<string, string> processResponseString, Action<object, FacebookApiEventArgs> onDownloadComplete) | |
| { | |
| if (string.IsNullOrEmpty(name)) | |
| throw new ArgumentNullException("name"); | |
| if (onDownloadComplete == null) | |
| throw new ArgumentNullException("onDownloadComplete"); | |
| parameters = parameters ?? new Dictionary<string, object>(); | |
| path = FacebookUtils.ParseQueryParametersToDictionary(path, parameters); | |
| if (!string.IsNullOrEmpty(path) && path.StartsWith("/", StringComparison.OrdinalIgnoreCase)) | |
| path = path.Substring(1, path.Length - 1); | |
| var requestUrl = GetUrl(name, path, parameters); | |
| var httpWebRequest = CreateHttpWebRequest(requestUrl); | |
| httpWebRequest.Method = "GET"; | |
| #if TPL | |
| if (HttpWebRequestWrapperCreated != null) | |
| HttpWebRequestWrapperCreated(this, new HttpWebRequestCreatedEventArgs(userToken, httpWebRequest)); | |
| #endif | |
| var httpHelper = new HttpHelper(httpWebRequest); | |
| httpHelper.OpenReadCompleted += | |
| (o, e) => | |
| { | |
| FacebookApiEventArgs args = null; | |
| if (e.Error == null) | |
| { | |
| Exception ex; | |
| string responseString = ProcessResponse(httpHelper, e.Result, out ex); | |
| args = new FacebookApiEventArgs(ex, e.Cancelled, userToken, processResponseString(responseString), false, false); | |
| } | |
| else | |
| { | |
| if (e.Error is WebExceptionWrapper) | |
| { | |
| var webEx = (WebExceptionWrapper)e.Error; | |
| if (webEx.GetResponse() == null) | |
| { | |
| args = new FacebookApiEventArgs(webEx, false, userToken, null, false, false); | |
| } | |
| else | |
| { | |
| httpHelper.OpenReadAsync(); | |
| return; | |
| } | |
| } | |
| } | |
| onDownloadComplete(this, args); | |
| }; | |
| httpHelper.OpenReadAsync(); | |
| } | |
| #if TPL | |
| /// <summary> | |
| /// Event handler when http web request wrapper is created for async api only. | |
| /// (used internally by TPL for cancellation support) | |
| /// </summary> | |
| private event EventHandler<HttpWebRequestCreatedEventArgs> HttpWebRequestWrapperCreated; | |
| /// <summary> | |
| /// Exchange code for access token asynchronously. | |
| /// </summary> | |
| /// <param name="code"> | |
| /// The code. | |
| /// </param> | |
| /// <param name="parameters"> | |
| /// The parameters. | |
| /// </param> | |
| /// <param name="cancellationToken"> | |
| /// The cancellation token. | |
| /// </param> | |
| /// <returns> | |
| /// The json result. | |
| /// </returns> | |
| public virtual System.Threading.Tasks.Task<object> ExchangeCodeForAccessTokenTaskAsync(string code, IDictionary<string, object> parameters, System.Threading.CancellationToken cancellationToken) | |
| { | |
| var tcs = new System.Threading.Tasks.TaskCompletionSource<object>(); | |
| if (cancellationToken.IsCancellationRequested) | |
| { | |
| tcs.TrySetCanceled(); | |
| } | |
| else | |
| { | |
| HttpWebRequestWrapper httpWebRequest = null; | |
| EventHandler<HttpWebRequestCreatedEventArgs> httpWebRequestCreatedHandler = null; | |
| httpWebRequestCreatedHandler += (o, e) => | |
| { | |
| if (e.UserState != tcs) | |
| return; | |
| httpWebRequest = e.HttpWebRequest; | |
| }; | |
| var ctr = cancellationToken.Register(() => { if (httpWebRequest != null) httpWebRequest.Abort(); }); | |
| EventHandler<FacebookApiEventArgs> handler = null; | |
| handler = (sender, e) => FacebookUtils.TransferCompletionToTask(tcs, e, e.GetResultData, | |
| () => | |
| { | |
| if (ctr != null) ctr.Dispose(); | |
| ExchangeCodeForAccessTokenCompleted -= handler; | |
| HttpWebRequestWrapperCreated -= httpWebRequestCreatedHandler; | |
| }); | |
| ExchangeCodeForAccessTokenCompleted += handler; | |
| HttpWebRequestWrapperCreated += httpWebRequestCreatedHandler; | |
| try | |
| { | |
| ExchangeCodeForAccessTokenAsync(code, parameters, tcs); | |
| if (cancellationToken.IsCancellationRequested && httpWebRequest != null) httpWebRequest.Abort(); | |
| } | |
| catch | |
| { | |
| ExchangeCodeForAccessTokenCompleted -= handler; | |
| HttpWebRequestWrapperCreated -= httpWebRequestCreatedHandler; | |
| throw; | |
| } | |
| } | |
| return tcs.Task; | |
| } | |
| /// <summary> | |
| /// Exchange code for access token asynchronously. | |
| /// </summary> | |
| /// <param name="code"> | |
| /// The code. | |
| /// </param> | |
| /// <param name="parameters"> | |
| /// The parameters. | |
| /// </param> | |
| /// <returns> | |
| /// The json result. | |
| /// </returns> | |
| public virtual System.Threading.Tasks.Task<object> ExchangeCodeForAccessTokenTaskAsync(string code, IDictionary<string, object> parameters) | |
| { | |
| return ExchangeCodeForAccessTokenTaskAsync(code, parameters, System.Threading.CancellationToken.None); | |
| } | |
| /// <summary> | |
| /// Exchange code for access token asynchronously. | |
| /// </summary> | |
| /// <param name="code"> | |
| /// The code. | |
| /// </param> | |
| /// <returns> | |
| /// The json result. | |
| /// </returns> | |
| public virtual System.Threading.Tasks.Task<object> ExchangeCodeForAccessTokenTaskAsync(string code) | |
| { | |
| return ExchangeCodeForAccessTokenTaskAsync(code, null); | |
| } | |
| /// <summary> | |
| /// Gets the application access token asynchronously. | |
| /// </summary> | |
| /// <param name="parameters"> | |
| /// The parameters. | |
| /// </param> | |
| /// <param name="cancellationToken"> | |
| /// The cancellation token. | |
| /// </param> | |
| /// <returns> | |
| /// The application access token. | |
| /// </returns> | |
| public virtual System.Threading.Tasks.Task<object> GetApplicationAccessTokenTaskAsync(IDictionary<string, object> parameters, System.Threading.CancellationToken cancellationToken) | |
| { | |
| var tcs = new System.Threading.Tasks.TaskCompletionSource<object>(); | |
| if (cancellationToken.IsCancellationRequested) | |
| { | |
| tcs.TrySetCanceled(); | |
| } | |
| else | |
| { | |
| HttpWebRequestWrapper httpWebRequest = null; | |
| EventHandler<HttpWebRequestCreatedEventArgs> httpWebRequestCreatedHandler = null; | |
| httpWebRequestCreatedHandler += (o, e) => | |
| { | |
| if (e.UserState != tcs) | |
| return; | |
| httpWebRequest = e.HttpWebRequest; | |
| }; | |
| var ctr = cancellationToken.Register(() => { if (httpWebRequest != null) httpWebRequest.Abort(); }); | |
| EventHandler<FacebookApiEventArgs> handler = null; | |
| handler = (sender, e) => FacebookUtils.TransferCompletionToTask(tcs, e, e.GetResultData, | |
| () => | |
| { | |
| if (ctr != null) ctr.Dispose(); | |
| GetApplicationAccessTokenCompleted -= handler; | |
| HttpWebRequestWrapperCreated -= httpWebRequestCreatedHandler; | |
| }); | |
| GetApplicationAccessTokenCompleted += handler; | |
| HttpWebRequestWrapperCreated += httpWebRequestCreatedHandler; | |
| try | |
| { | |
| GetApplicationAccessTokenAsync(parameters, tcs); | |
| if (cancellationToken.IsCancellationRequested && httpWebRequest != null) httpWebRequest.Abort(); | |
| } | |
| catch | |
| { | |
| GetApplicationAccessTokenCompleted -= handler; | |
| HttpWebRequestWrapperCreated -= httpWebRequestCreatedHandler; | |
| throw; | |
| } | |
| } | |
| return tcs.Task; | |
| } | |
| /// <summary> | |
| /// Gets the application access token asynchronously. | |
| /// </summary> | |
| /// <returns> | |
| /// The application access token. | |
| /// </returns> | |
| public virtual System.Threading.Tasks.Task<object> GetApplicationAccessTokenTaskAsync() | |
| { | |
| return GetApplicationAccessTokenTaskAsync(null, System.Threading.CancellationToken.None); | |
| } | |
| #endif | |
| private string ProcessResponse(HttpHelper httpHelper, Stream responseStream, out Exception exception) | |
| { | |
| exception = null; | |
| try | |
| { | |
| string responseString; | |
| using (var stream = responseStream) | |
| { | |
| using (var reader = new StreamReader(stream)) | |
| { | |
| responseString = reader.ReadToEnd(); | |
| } | |
| } | |
| if (httpHelper.InnerException == null) | |
| return responseString; | |
| object jsonObject; | |
| exception = ExceptionFactory.GetGraphException(responseString, out jsonObject) ?? httpHelper.InnerException; | |
| return null; | |
| } | |
| catch (Exception ex) | |
| { | |
| exception = ex; | |
| return null; | |
| } | |
| } | |
| /// <summary> | |
| /// Build the URL for given domain alias, path and parameters. | |
| /// </summary> | |
| /// <param name="name"> | |
| /// The name of the domain (from the domain maps). | |
| /// </param> | |
| /// <param name="path"> | |
| /// Optional path (without a leading slash) | |
| /// </param> | |
| /// <param name="parameters"> | |
| /// Optional query parameters | |
| /// </param> | |
| /// <returns> | |
| /// The string of the url for the given parameters. | |
| /// </returns> | |
| internal protected virtual Uri GetUrl(string name, string path, IDictionary<string, object> parameters) | |
| { | |
| if (string.IsNullOrEmpty(name)) | |
| throw new ArgumentNullException("name"); | |
| return FacebookUtils.GetUrl(DomainMaps, name, path, parameters); | |
| } | |
| /// <summary> | |
| /// Creates the http web request. | |
| /// </summary> | |
| /// <param name="url">The url of the http web request.</param> | |
| /// <returns>The http helper.</returns> | |
| [EditorBrowsable(EditorBrowsableState.Never)] | |
| protected virtual HttpWebRequestWrapper CreateHttpWebRequest(Uri url) | |
| { | |
| if (url == null) | |
| throw new ArgumentNullException("url"); | |
| return new HttpWebRequestWrapper((HttpWebRequest)WebRequest.Create(url)); | |
| } | |
| #region Parse OAuth Result | |
| /// <summary> | |
| /// Parse the uri to <see cref="FacebookOAuthResult"/>. | |
| /// </summary> | |
| /// <param name="uriString"> | |
| /// The url to parse. | |
| /// </param> | |
| /// <returns> | |
| /// Returns an instance of <see cref="FacebookOAuthResult"/>. | |
| /// </returns> | |
| public virtual FacebookOAuthResult ParseResult(string uriString) | |
| { | |
| return FacebookOAuthResult.Parse(uriString); | |
| } | |
| /// <summary> | |
| /// Parse the uri to <see cref="FacebookOAuthResult"/>. | |
| /// </summary> | |
| /// <param name="uri"> | |
| /// The url to parse. | |
| /// </param> | |
| /// <returns> | |
| /// Returns an instance of <see cref="FacebookOAuthResult"/>. | |
| /// </returns> | |
| public virtual FacebookOAuthResult ParseResult(Uri uri) | |
| { | |
| return FacebookOAuthResult.Parse(uri); | |
| } | |
| /// <summary> | |
| /// Try parsing the uri to <see cref="FacebookOAuthResult"/>. | |
| /// </summary> | |
| /// <param name="uriString"> | |
| /// The url to parse. | |
| /// </param> | |
| /// <param name="result"> | |
| /// An instance of <see cref="FacebookOAuthResult"/>. | |
| /// </param> | |
| /// <returns> | |
| /// Returns true if parsing was successful otherwise false. | |
| /// </returns> | |
| public virtual bool TryParseResult(string uriString, out FacebookOAuthResult result) | |
| { | |
| return FacebookOAuthResult.TryParse(uriString, out result); | |
| } | |
| /// <summary> | |
| /// Try parsing the uri to <see cref="FacebookOAuthResult"/>. | |
| /// </summary> | |
| /// <param name="uri"> | |
| /// The url to parse. | |
| /// </param> | |
| /// <param name="result"> | |
| /// An instance of <see cref="FacebookOAuthResult"/>. | |
| /// </param> | |
| /// <returns> | |
| /// Returns true if parsing was successful otherwise false. | |
| /// </returns> | |
| public virtual bool TryParseResult(Uri uri, out FacebookOAuthResult result) | |
| { | |
| return FacebookOAuthResult.TryParse(uri, out result); | |
| } | |
| #endregion | |
| } | |
| } | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment