Facebook C#SDK LoginButton状态管理

时间:2013-08-16 08:38:00

标签: facebook-c#-sdk

我已经在我的Windows 8应用程序中实现了Facebook C#SDK客户端LoginButton,并使其在类似于提供的示例应用程序的模式下正常工作。我的问题是,除了某种“Hello World”示例应用程序之外,登录按钮需要能够同步其状态以便有用。

最明显的问题是,当使用登录按钮导航离开页面,然后导航回该页面时,登录按钮根本没有状态(它没有会话,没有用户,不知道你'实际登录等)。这个问题的一个更微妙的版本是,在真实的应用程序中,您通常不希望强制用户向Facebook进行身份验证,除非它是必需的(因此,如果您的应用程序的上一个会话中有一个有效的令牌,则该用户被视为已登录,并且当您的应用程序启动时,您不会提示他们再次登录)。但由于没有办法将任何状态传递给登录按钮控件,并且控件似乎没有序列化/管理自己的状态,所以你不能这样做。

我是Windows 8编程的新手,所以也许我错过了一些可以使其工作的神奇连接(我看到指示状态发生变化的事件和序列化状态的类,但我不知道看到任何方式将该状态转换为LoginButton,或以其他方式指示登录按钮序列化其状态)。并且LoginButton类被固定到似乎没有办法打破状态 - 与会话状态相关的所有内容都是只读/私有。

登录按钮(以及其他控件)未用于唯一的非平凡SDK示例(Scrumptious)这一事实并不能真正激发人们对这些控件的实际准备情况的信心。

1 个答案:

答案 0 :(得分:6)

好的,好像我要回答我自己的问题;)

LoginButton在内部使用FacebookSessionClient登录/注销,而FacebookSessionClient实际上使用适当的FacebookSessionCacheProvider序列化会话状态。到目前为止,非常好。

然后,技巧是在加载页面时将任何现有会话状态设置为按钮。我原先确信这是不可能的,因为CurrentSession和CurrentUser的LoginButton属性是只读的。但经过进一步审查后,我发现我实际上可以使用SetValue通过其依赖属性设置这些值。

我使用适当的事件处理程序从LoginButton跟踪会话和用户状态,如下所示:

    private void OnSessionStateChanged(object sender, Facebook.Client.Controls.SessionStateChangedEventArgs e)
    {
        if (e.SessionState == Facebook.Client.Controls.FacebookSessionState.Opened)
        {
            App.CurrentSession = this.loginButton.CurrentSession;
        }
        else if (e.SessionState == Facebook.Client.Controls.FacebookSessionState.Closed)
        {
            App.CurrentSession = null;

            // The control signals when user info is set (handled in OnUserInfoChanged below), but not when it
            // is cleared (probably a bug), so we clear our reference here when the session ends.
            //
            App.CurrentUser = null;
        }
    }

    private void OnUserInfoChanged(object sender, UserInfoChangedEventArgs e)
    {
        App.CurrentUser = this.loginButton.CurrentUser;
    }

在页面加载时,我从缓存中获取会话状态(因此这在启动应用程序时,在恢复应用程序时以及从另一页面导航回此页面时都有效)并且我使用SetValue适当地恢复LoginButton状态。我有一些额外的逻辑,如果用户以前登录过,则自动重新验证,但是有一个过期的令牌(由于使用短期令牌而经常在启动时发生)。我还有逻辑在需要时重新加载CurrentUser。结果是登录按钮在所有三种情况下都具有正确的状态。

    private async void navigationHelper_LoadState(object sender, LoadStateEventArgs e)
    {
        this.loginButton.ApplicationId = Constants.FacebookAppId;

        App.CurrentSession = FacebookSessionCacheProvider.Current.GetSessionData();
        if ((App.CurrentSession != null) && (App.CurrentSession.Expires <= DateTime.UtcNow))
        {
            // User was previously logged in, but session expired.  Log them in again...
            App.CurrentSession = await App.FacebookSessionClient.LoginAsync(Constants.FacebookPermissions);
        }

        if (App.CurrentSession != null)
        {
            this.loginButton.SetValue(LoginButton.CurrentSessionProperty, App.CurrentSession);
            if (App.CurrentUser == null)
            {
                FacebookClient client = new FacebookClient(App.CurrentSession.AccessToken);
                dynamic result = await client.GetTaskAsync("me");
                App.CurrentUser = new GraphUser(result);
            }
        }

        if (App.CurrentUser != null)
        {
            this.loginButton.SetValue(LoginButton.CurrentUserProperty, App.CurrentUser);
        }
    }

我认为正确的解决方案是让LoginButton使用缓存提供程序获取会话状态并适当地初始化自身(至少在会话有效/未到期的情况下),这样它就可以“神奇地”工作而不会这些体操。