FacebookApplication.VerifyAuthentication(_httpContext, GenerateLocalCallbackUri()) return null on Facebook

元气小坏坏 提交于 2019-11-29 07:13:06

We ran into this same issue on Monday, 3/27/2017, when Facebook discontinued support for their Graph API v2.2.

We are also using DotNetOpenAuth, which was originally installed via Nuget. The source code is available at the link below:

https://github.com/DotNetOpenAuth/DotNetOpenAuth

Specifically, we discovered that our code was utilizing the 4.3 branch which contains the source code for the DotNetOpenAuth.AspNet.DLL. Upon inspecting the source, we discovered the problem is with this snippet of code from DotNetOpenAuth.AspNet\Clients\OAuth2\FacebookClient.cs, located within the QueryAccessToken method:

using (WebClient client = new WebClient()) {
     string data = client.DownloadString(builder.Uri);
     if (string.IsNullOrEmpty(data)) {
          return null;
     }

     var parsedQueryString = HttpUtility.ParseQueryString(data);
     return parsedQueryString["access_token"];
}

The issue, specifically, is the ParseQueryString call. Starting with v2.3 of the API, the data is no longer returned as an HTML query string, but in standard JSON format.

To fix this, we created our own custom class inheriting OAuth2Client and imported most of the same code from FacebookClient.cs. We then replaced the above code snippet with code that parses the JSON response to extract the access_token, and returns that instead. You can see an example of how to do this in the same FacebookClient class, within the GetUserData method:

FacebookGraphData graphData;
var request =
    WebRequest.Create(
        "https://graph.facebook.com/me?access_token=" +
             MessagingUtilities.EscapeUriDataStringRfc3986(accessToken));
using (var response = request.GetResponse()) {
     using (var responseStream = response.GetResponseStream()) {
        graphData = JsonHelper.Deserialize<FacebookGraphData>(responseStream);
     }
}

The only other change was to register our custom class in place of the FacebookClient class so the OAuth callback uses it to handle the post from Facebook's API. Once we did this, everything worked smoothly again.

I have used the code shared by @Vishal and got the same working.

The main thing that we have to focus is to override the QueryAccessToken method to use json response.

protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
    {
        var uri = BuildUri(TokenEndpoint, new NameValueCollection
            {
                { "code", authorizationCode },
                { "client_id", _appId },
                { "client_secret", _appSecret },
                { "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) },
            });

        var webRequest = (HttpWebRequest)WebRequest.Create(uri);
        string accessToken = null;            
        HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();

        // handle response from FB 
        // this will not be a url with params like the first request to get the 'code'
        Encoding rEncoding = Encoding.GetEncoding(response.CharacterSet);

        using (StreamReader sr = new StreamReader(response.GetResponseStream(), rEncoding))
        {
            var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            var jsonObject = serializer.DeserializeObject(sr.ReadToEnd());
            var jConvert = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(jsonObject));

            Dictionary<string, object> desirializedJsonObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(jConvert.ToString());
            accessToken = desirializedJsonObject["access_token"].ToString();
        }
        return accessToken;
    }

Steps to achieve this: Step 1. What you have to do is add one file named FacebookClientOverride.cs(other than FacebookClient.cs)

Here is the code snippet of the whole file.

 using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using DotNetOpenAuth.AspNet.Clients;
using Newtonsoft.Json;

public class FacebookClient : OAuth2Client
{
    #region Constants and Fields

    /// <summary>
    /// The authorization endpoint.
    /// </summary>
    private const string AuthorizationEndpoint = "https://www.facebook.com/dialog/oauth";

    /// <summary>
    /// The token endpoint.
    /// </summary>
    private const string TokenEndpoint = "https://graph.facebook.com/oauth/access_token";

    /// <summary>
    /// The user info endpoint.
    /// </summary>
    private const string UserInfoEndpoint = "https://graph.facebook.com/me";

    /// <summary>
    /// The app id.
    /// </summary>
    private readonly string _appId;

    /// <summary>
    /// The app secret.
    /// </summary>
    private readonly string _appSecret;

    /// <summary>
    /// The requested scopes.
    /// </summary>
    private readonly string[] _requestedScopes;

    #endregion

    /// <summary>
    /// Creates a new Facebook OAuth2 client, requesting the default "email" scope.
    /// </summary>
    /// <param name="appId">The Facebook App Id</param>
    /// <param name="appSecret">The Facebook App Secret</param>
    public FacebookClient(string appId, string appSecret)
        : this(appId, appSecret, new[] { "email" }) { }

    /// <summary>
    /// Creates a new Facebook OAuth2 client.
    /// </summary>
    /// <param name="appId">The Facebook App Id</param>
    /// <param name="appSecret">The Facebook App Secret</param>
    /// <param name="requestedScopes">One or more requested scopes, passed without the base URI.</param>
    public FacebookClient(string appId, string appSecret, params string[] requestedScopes)
        : base("facebook")
    {
        if (string.IsNullOrWhiteSpace(appId))
            throw new ArgumentNullException("appId");

        if (string.IsNullOrWhiteSpace(appSecret))
            throw new ArgumentNullException("appSecret");

        if (requestedScopes == null)
            throw new ArgumentNullException("requestedScopes");

        if (requestedScopes.Length == 0)
            throw new ArgumentException("One or more scopes must be requested.", "requestedScopes");

        _appId = appId;
        _appSecret = appSecret;
        _requestedScopes = requestedScopes;
    }

    protected override Uri GetServiceLoginUrl(Uri returnUrl)
    {
        var state = string.IsNullOrEmpty(returnUrl.Query) ? string.Empty : returnUrl.Query.Substring(1);

        return BuildUri(AuthorizationEndpoint, new NameValueCollection
                {
                    { "client_id", _appId },
                    { "scope", string.Join(" ", _requestedScopes) },
                    { "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) },
                    { "state", state },
                });
    }

    protected override IDictionary<string, string> GetUserData(string accessToken)
    {
        var uri = BuildUri(UserInfoEndpoint, new NameValueCollection { { "access_token", accessToken } });

        var webRequest = (HttpWebRequest)WebRequest.Create(uri);

        using (var webResponse = webRequest.GetResponse())
        using (var stream = webResponse.GetResponseStream())
        {
            if (stream == null)
                return null;

            using (var textReader = new StreamReader(stream))
            {
                var json = textReader.ReadToEnd();
                var extraData = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
                var data = extraData.ToDictionary(x => x.Key, x => x.Value.ToString());

                data.Add("picture", string.Format("https://graph.facebook.com/{0}/picture", data["id"]));

                return data;
            }
        }
    }

    protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
    {
        var uri = BuildUri(TokenEndpoint, new NameValueCollection
                {
                    { "code", authorizationCode },
                    { "client_id", _appId },
                    { "client_secret", _appSecret },
                    { "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) },
                });

        var webRequest = (HttpWebRequest)WebRequest.Create(uri);
        string accessToken = null;
        HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();

        // handle response from FB 
        // this will not be a url with params like the first request to get the 'code'
        Encoding rEncoding = Encoding.GetEncoding(response.CharacterSet);

        using (StreamReader sr = new StreamReader(response.GetResponseStream(), rEncoding))
        {
            var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            var jsonObject = serializer.DeserializeObject(sr.ReadToEnd());
            var jConvert = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(jsonObject));

            Dictionary<string, object> desirializedJsonObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(jConvert.ToString());
            accessToken = desirializedJsonObject["access_token"].ToString();
        }
        return accessToken;
    }

    private static Uri BuildUri(string baseUri, NameValueCollection queryParameters)
    {
        var keyValuePairs = queryParameters.AllKeys.Select(k => HttpUtility.UrlEncode(k) + "=" + HttpUtility.UrlEncode(queryParameters[k]));
        var qs = String.Join("&", keyValuePairs);

        var builder = new UriBuilder(baseUri) { Query = qs };
        return builder.Uri;
    }

    /// <summary>
    /// Facebook works best when return data be packed into a "state" parameter.
    /// This should be called before verifying the request, so that the url is rewritten to support this.
    /// </summary>
    public static void RewriteRequest()
    {
        var ctx = HttpContext.Current;

        var stateString = HttpUtility.UrlDecode(ctx.Request.QueryString["state"]);
        if (stateString == null || !stateString.Contains("__provider__=facebook"))
            return;

        var q = HttpUtility.ParseQueryString(stateString);
        q.Add(ctx.Request.QueryString);
        q.Remove("state");

        ctx.RewritePath(ctx.Request.Path + "?" + q);
    }
}

Step 2. Add one reference to System.Web.Extensions

Step 3. In the FacebookProviderAuthorizer.cs (Nopcommerce project) look for the FacebookClient Property private FacebookClient _facebookApplication;

This should refer to your new file just added.

Step 4. Now put a break point in the method named VerifyAuthentication in the file FacebookProviderAuthorizer.cs .

The authResult.IsSuccessful must be true now as it successfully parsed the token.

Thanks all. Please like if the soluutions worked for you.

Building onto Steve's post, I created a "FriendlyFacebookClient" to use in-place of FacebookClient, copied over some of the internal methods, and replaced QueryAccessToken with the following:

  protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
        {
            UriBuilder builder = new UriBuilder("https://graph.facebook.com/oauth/access_token");
            AppendQueryArgs(builder, (IEnumerable<KeyValuePair<string, string>>)new Dictionary<string, string>()
              {
                { "client_id", this.appId},
                { "redirect_uri", FriendlyFacebookClient.NormalizeHexEncoding(returnUrl.AbsoluteUri)},
                { "client_secret",  this.appSecret },
                { "code",  authorizationCode },
                { "scope", "email" }
              });

            using (WebClient webClient = new WebClient())
            {
                var response = webClient.DownloadString(builder.Uri);
                var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(response);
                return data["access_token"];
            }
        }

According to Previous Answer I got my solution. In MVC4 everyone write down their AppID and SecurityCode. Due to change of facebook GRAPH API those previous links are broken. Consequently everyone need to change the RegisterFacebookClient class. But this class is a sealed class in the .Net library, so anyone can't extend or overwrite it. As a result we need to use a wrapper class. I am writing this answer because all the previous answer suppliers have missed one thing, for which I have suffered a lot. Because they did not mentioned the system of class warping system in the AuthConfig Class. So it takes too much to solve this problem. Therefore I am going step by step as below. Let us consider my Wrapper class is FacebookClientV2Dot3 therefore my class will be

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using DotNetOpenAuth.AspNet.Clients;
using Newtonsoft.Json;

public class FacebookClientV2Dot3 : OAuth2Client
{
    #region Constants and Fields

    /// <summary>
    /// The authorization endpoint.
    /// </summary>
    private const string AuthorizationEndpoint = "https://www.facebook.com/dialog/oauth";

    /// <summary>
    /// The token endpoint.
    /// </summary>
    private const string TokenEndpoint = "https://graph.facebook.com/oauth/access_token";

    /// <summary>
    /// The user info endpoint.
    /// </summary>
    private const string UserInfoEndpoint = "https://graph.facebook.com/me";

    /// <summary>
    /// The app id.
    /// </summary>
    private readonly string _appId;

    /// <summary>
    /// The app secret.
    /// </summary>
    private readonly string _appSecret;

    /// <summary>
    /// The requested scopes.
    /// </summary>
    private readonly string[] _requestedScopes;

    #endregion

    /// <summary>
    /// Creates a new Facebook OAuth2 client, requesting the default "email" scope.
    /// </summary>
    /// <param name="appId">The Facebook App Id</param>
    /// <param name="appSecret">The Facebook App Secret</param>
    public FacebookClient(string appId, string appSecret)
        : this(appId, appSecret, new[] { "email" }) { }

    /// <summary>
    /// Creates a new Facebook OAuth2 client.
    /// </summary>
    /// <param name="appId">The Facebook App Id</param>
    /// <param name="appSecret">The Facebook App Secret</param>
    /// <param name="requestedScopes">One or more requested scopes, passed without the base URI.</param>
    public FacebookClient(string appId, string appSecret, params string[] requestedScopes)
        : base("facebook")
    {
        if (string.IsNullOrWhiteSpace(appId))
            throw new ArgumentNullException("appId");

        if (string.IsNullOrWhiteSpace(appSecret))
            throw new ArgumentNullException("appSecret");

        if (requestedScopes == null)
            throw new ArgumentNullException("requestedScopes");

        if (requestedScopes.Length == 0)
            throw new ArgumentException("One or more scopes must be requested.", "requestedScopes");

        _appId = appId;
        _appSecret = appSecret;
        _requestedScopes = requestedScopes;
    }

    protected override Uri GetServiceLoginUrl(Uri returnUrl)
    {
        var state = string.IsNullOrEmpty(returnUrl.Query) ? string.Empty : returnUrl.Query.Substring(1);

        return BuildUri(AuthorizationEndpoint, new NameValueCollection
                {
                    { "client_id", _appId },
                    { "scope", string.Join(" ", _requestedScopes) },
                    { "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) },
                    { "state", state },
                });
    }

    protected override IDictionary<string, string> GetUserData(string accessToken)
    {
        var uri = BuildUri(UserInfoEndpoint, new NameValueCollection { { "access_token", accessToken } });

        var webRequest = (HttpWebRequest)WebRequest.Create(uri);

        using (var webResponse = webRequest.GetResponse())
        using (var stream = webResponse.GetResponseStream())
        {
            if (stream == null)
                return null;

            using (var textReader = new StreamReader(stream))
            {
                var json = textReader.ReadToEnd();
                var extraData = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
                var data = extraData.ToDictionary(x => x.Key, x => x.Value.ToString());

                data.Add("picture", string.Format("https://graph.facebook.com/{0}/picture", data["id"]));

                return data;
            }
        }
    }

    protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
    {
        var uri = BuildUri(TokenEndpoint, new NameValueCollection
                {
                    { "code", authorizationCode },
                    { "client_id", _appId },
                    { "client_secret", _appSecret },
                    { "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) },
                });

        var webRequest = (HttpWebRequest)WebRequest.Create(uri);
        string accessToken = null;
        HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();

        // handle response from FB 
        // this will not be a url with params like the first request to get the 'code'
        Encoding rEncoding = Encoding.GetEncoding(response.CharacterSet);

        using (StreamReader sr = new StreamReader(response.GetResponseStream(), rEncoding))
        {
            var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            var jsonObject = serializer.DeserializeObject(sr.ReadToEnd());
            var jConvert = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(jsonObject));

            Dictionary<string, object> desirializedJsonObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(jConvert.ToString());
            accessToken = desirializedJsonObject["access_token"].ToString();
        }
        return accessToken;
    }

    private static Uri BuildUri(string baseUri, NameValueCollection queryParameters)
    {
        var keyValuePairs = queryParameters.AllKeys.Select(k => HttpUtility.UrlEncode(k) + "=" + HttpUtility.UrlEncode(queryParameters[k]));
        var qs = String.Join("&", keyValuePairs);

        var builder = new UriBuilder(baseUri) { Query = qs };
        return builder.Uri;
    }

    /// <summary>
    /// Facebook works best when return data be packed into a "state" parameter.
    /// This should be called before verifying the request, so that the url is rewritten to support this.
    /// </summary>
    public static void RewriteRequest()
    {
        var ctx = HttpContext.Current;

        var stateString = HttpUtility.UrlDecode(ctx.Request.QueryString["state"]);
        if (stateString == null || !stateString.Contains("__provider__=facebook"))
            return;

        var q = HttpUtility.ParseQueryString(stateString);
        q.Add(ctx.Request.QueryString);
        q.Remove("state");

        ctx.RewritePath(ctx.Request.Path + "?" + q);
    }
}

Look here you I have replaces all the API links by newer version links.

Now you need to modify your

AuthConfig

Just use a wrapper class instead of RegisterFacebookClient. Completely block those portion of code. And add this...

OAuthWebSecurity.RegisterClient(new FacebookClientV2Dot3("AppID", "HassedPassword"));

Then all success. You facebook login will be back in previous state.

However you can face a new issue regarding this new API rather than previous API, the problem is that IP Whitelisting. Like this image. Hope you will need nothing but this. Happy coding.

As suggested by @SteveTerry We need to update QueryAccessToken function in FacebookClient class. unfortunately "FacebookClient" is sealed class so we cannot inherit and override. So whichever way you choose is up to you. Here is what end result should look like:

Old code of this function was:

protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) {
// Note: Facebook doesn't like us to url-encode the redirect_uri value
var builder = new UriBuilder(TokenEndpoint);
builder.AppendQueryArgs(
    new Dictionary<string, string> {
        { "client_id", this.appId },
        { "redirect_uri", NormalizeHexEncoding(returnUrl.AbsoluteUri) },
        { "client_secret", this.appSecret },
        { "code", authorizationCode },
        { "scope", "email" },
    });

using (webclient client = new webclient()) {
    string data = client.downloadstring(builder.uri);
    if (string.isnullorempty(data)) {
        return null;
    }

    var parsedquerystring = httputility.parsequerystring(data);
    return parsedquerystring["access_token"];
}

}

And to support new version of fb api it should be like this:

/// <summary>
/// Contains access_token of a Facebook user.
/// </summary>
[DataContract]
[EditorBrowsable(EditorBrowsableState.Never)]
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Facebook", Justification = "Brand name")]
public class FacebookAccessTokenData
{
    #region Public Properties

    /// <summary>
    /// 
    /// </summary>
    [DataMember(Name = "access_token")]
    public string AccessToken { get; set; }

    /// <summary>
    /// 
    /// </summary>
    [DataMember(Name = "token_type")]
    public string TokenType { get; set; }

    /// <summary>
    /// 
    /// </summary>
    [DataMember(Name = "expires_in")]
    public string ExpiresIn { get; set; }

    #endregion
}


/// <summary>
/// Obtains an access token given an authorization code and callback URL.
/// </summary>
/// <param name="returnUrl">
/// The return url.
/// </param>
/// <param name="authorizationCode">
/// The authorization code.
/// </param>
/// <returns>
/// The access token.
/// </returns>
protected override string QueryAccessToken(Uri returnUrl, string authorizationCode) {
    // Note: Facebook doesn't like us to url-encode the redirect_uri value
    var builder = new UriBuilder(TokenEndpoint);
    builder.AppendQueryArgs(
        new Dictionary<string, string> {
            { "client_id", this.appId },
            { "redirect_uri", NormalizeHexEncoding(returnUrl.AbsoluteUri) },
            { "client_secret", this.appSecret },
            { "code", authorizationCode },
            { "scope", "email" },
        });

    FacebookAccessTokenData graphData;
    var request = WebRequest.Create(builder.Uri);
    using (var response = request.GetResponse())
    {
        using (var responseStream = response.GetResponseStream())
        {
            graphData = JsonHelper.Deserialize<FacebookAccessTokenData>(responseStream);
        }
    }

    return graphData.AccessToken;
}

I solve my issue I will do the same thing as @Adam described in his answer, As per the @Adam, @SteveTerry and @Adeem's answer i change my code and create custom FacebookClient class with different name. and replace with original reference of FacebookClient in nopCommerce.

public class FacebookOAuth2Client : OAuth2Client
    {
        #region Constants and Fields

        /// <summary>
        /// The authorization endpoint.
        /// </summary>
        private const string AuthorizationEndpoint = "https://www.facebook.com/dialog/oauth";

        /// <summary>
        /// The token endpoint.
        /// </summary>
        private const string TokenEndpoint = "https://graph.facebook.com/oauth/access_token";

        /// <summary>
        /// The user info endpoint.
        /// </summary>
        private const string UserInfoEndpoint = "https://graph.facebook.com/me";

        /// <summary>
        /// The app id.
        /// </summary>
        private readonly string _appId;

        /// <summary>
        /// The app secret.
        /// </summary>
        private readonly string _appSecret;

        /// <summary>
        /// The requested scopes.
        /// </summary>
        private readonly string[] _requestedScopes;

        #endregion

        /// <summary>
        /// Creates a new Facebook OAuth2 client, requesting the default "email" scope.
        /// </summary>
        /// <param name="appId">The Facebook App Id</param>
        /// <param name="appSecret">The Facebook App Secret</param>
        public FacebookClient(string appId, string appSecret)
            : this(appId, appSecret, new[] { "email" }) { }

        /// <summary>
        /// Creates a new Facebook OAuth2 client.
        /// </summary>
        /// <param name="appId">The Facebook App Id</param>
        /// <param name="appSecret">The Facebook App Secret</param>
        /// <param name="requestedScopes">One or more requested scopes, passed without the base URI.</param>
        public FacebookClient(string appId, string appSecret, params string[] requestedScopes)
            : base("facebook")
        {
            if (string.IsNullOrWhiteSpace(appId))
                throw new ArgumentNullException("appId");

            if (string.IsNullOrWhiteSpace(appSecret))
                throw new ArgumentNullException("appSecret");

            if (requestedScopes == null)
                throw new ArgumentNullException("requestedScopes");

            if (requestedScopes.Length == 0)
                throw new ArgumentException("One or more scopes must be requested.", "requestedScopes");

            _appId = appId;
            _appSecret = appSecret;
            _requestedScopes = requestedScopes;
        }

        protected override Uri GetServiceLoginUrl(Uri returnUrl)
        {
            var state = string.IsNullOrEmpty(returnUrl.Query) ? string.Empty : returnUrl.Query.Substring(1);

            return BuildUri(AuthorizationEndpoint, new NameValueCollection
                {
                    { "client_id", _appId },
                    { "scope", string.Join(" ", _requestedScopes) },
                    { "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) },
                    { "state", state },
                });
        }

        protected override IDictionary<string, string> GetUserData(string accessToken)
        {
            var uri = BuildUri(UserInfoEndpoint, new NameValueCollection { { "access_token", accessToken } });

            var webRequest = (HttpWebRequest)WebRequest.Create(uri);

            using (var webResponse = webRequest.GetResponse())
            using (var stream = webResponse.GetResponseStream())
            {
                if (stream == null)
                    return null;

                using (var textReader = new StreamReader(stream))
                {
                    var json = textReader.ReadToEnd();
                    var extraData = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
                    var data = extraData.ToDictionary(x => x.Key, x => x.Value.ToString());

                    data.Add("picture", string.Format("https://graph.facebook.com/{0}/picture", data["id"]));

                    return data;
                }
            }
        }

        protected override string QueryAccessToken(Uri returnUrl, string authorizationCode)
        {
            var uri = BuildUri(TokenEndpoint, new NameValueCollection
                {
                    { "code", authorizationCode },
                    { "client_id", _appId },
                    { "client_secret", _appSecret },
                    { "redirect_uri", returnUrl.GetLeftPart(UriPartial.Path) },
                });

            var webRequest = (HttpWebRequest)WebRequest.Create(uri);
            string accessToken = null;            
            HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();

            // handle response from FB 
            // this will not be a url with params like the first request to get the 'code'
            Encoding rEncoding = Encoding.GetEncoding(response.CharacterSet);

            using (StreamReader sr = new StreamReader(response.GetResponseStream(), rEncoding))
            {
                var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
                var jsonObject = serializer.DeserializeObject(sr.ReadToEnd());
                var jConvert = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(jsonObject));

                Dictionary<string, object> desirializedJsonObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(jConvert.ToString());
                accessToken = desirializedJsonObject["access_token"].ToString();
            }
            return accessToken;
        }

        private static Uri BuildUri(string baseUri, NameValueCollection queryParameters)
        {
            var keyValuePairs = queryParameters.AllKeys.Select(k => HttpUtility.UrlEncode(k) + "=" + HttpUtility.UrlEncode(queryParameters[k]));
            var qs = String.Join("&", keyValuePairs);

            var builder = new UriBuilder(baseUri) { Query = qs };
            return builder.Uri;
        }

        /// <summary>
        /// Facebook works best when return data be packed into a "state" parameter.
        /// This should be called before verifying the request, so that the url is rewritten to support this.
        /// </summary>
        public static void RewriteRequest()
        {
            var ctx = HttpContext.Current;

            var stateString = HttpUtility.UrlDecode(ctx.Request.QueryString["state"]);
            if (stateString == null || !stateString.Contains("__provider__=facebook"))
                return;

            var q = HttpUtility.ParseQueryString(stateString);
            q.Add(ctx.Request.QueryString);
            q.Remove("state");

            ctx.RewritePath(ctx.Request.Path + "?" + q);
        }
    }

in this code i have no reference of JsonHelper so i use simple jsonConvert. Thanx again @Adam, @SteveTerry and @Adeem's for help.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!