1

我有一对使用 Dropnet 进行 Dropbox 集成的 Windows Phone 应用程序。一种是在 Visual Studio Express 2012 中开发的,目标是 7.1,另一种是在 Visual Studio 2013 中开发的,目标是 8.0。

两者都通过 NuGet 使用 Dropnet 1.9.6 和 RestSharp 104.4.0。

7.1 项目使用以下静态类与 DropNet 身份验证(和文件操作,但为了清楚起见我已将它们排除在外)进行交互。

public static class DropboxStorage
{
    const string UserToken = "UserToken";
    const string UserSecret = "UserSecret";

    private static DropNetClient _Dropbox;
    public static DropNetClient Dropbox
    {
        get
        {
            if (_Dropbox == null)
            {
                _Dropbox = new DropNetClient(AppKey, AppSecret);
                if (IsAuthenticated)
                {
                    _Dropbox.UserLogin = new UserLogin
                    {
                        Token = (string)IsolatedStorageSettings.ApplicationSettings[UserToken],
                        Secret = (string)IsolatedStorageSettings.ApplicationSettings[UserSecret]
                    };
                }
                _Dropbox.UseSandbox = true;
            }
            return _Dropbox;
        }
    }

    public static bool IsAuthenticated
    {
        get
        {
            return IsolatedStorageSettings.ApplicationSettings.Contains(UserToken) &&
                IsolatedStorageSettings.ApplicationSettings.Contains(UserSecret);
        }
    }

    public static void StartAuthentication(Action<Uri> success, Action<Exception> failure)
    {
        Dropbox.GetTokenAsync(userLogin =>
        {
            var url = Dropbox.BuildAuthorizeUrl(userLogin);
            if (success != null) success(new Uri(url, UriKind.RelativeOrAbsolute));
        }, error =>
        {
            if (failure != null) failure(error);
        });
    }

    public static void CheckAuthentication(Uri uri, Action success, Action<Exception> failure)
    {
        if (uri.LocalPath == "/1/oauth/authorize_submit")
        {
            Dropbox.GetAccessTokenAsync((accessToken) =>
            {
                IsolatedStorageSettings.ApplicationSettings[UserToken] = accessToken.Token;
                IsolatedStorageSettings.ApplicationSettings[UserSecret] = accessToken.Secret;
                IsolatedStorageSettings.ApplicationSettings.Save();
                if (success != null) success();
            },
            (error) =>
            {
                if (failure != null) failure(error);
            });
        }
    }

然后通过带有 WebBrowser 控件的页面访问它。

XAML

<phone:WebBrowser x:Name="Browser"
                              IsScriptEnabled="True"
                              Navigated="Browser_Navigated"/>

C#

public partial class DropboxPage : PhoneApplicationPage
{
    public DropboxPage()
    {
        InitializeComponent();

         DropboxStorage.StartAuthentication(
                uri => Browser.Navigate(uri),
                ex => ShowException(ex));
     }

    public void Browser_Navigated(object sender, NavigationEventArgs e)
    {
        Debug.WriteLine(e.Uri.OriginalString);
        DropboxStorage.CheckAuthentication(
            e.Uri,
            () => NavigationService.GoBack(),
            ex => ShowException(ex));
    }

    private void ShowException(Exception e)
    {
        MessageBox.Show(e.Message);
        NavigationService.GoBack();
    }
}

显示 Dropbox 身份验证网页

  • 登入
  • 允许应用访问
  • 成功,应用已连接

当 Dropbox url 包含/1/oauth/authorize_submit.

这一切都完美无缺,但是 8.0 项目的行为略有不同。

第一个区别是BuildAuthorizeUrl调用返回的 url。

  • 7.1 https://www.dropbox.com/1/oauth/authorize?oauth_token=<token>
  • 8.0 https://api.dropbox.com/1/oauth/authorize?oauth_token=<token>

/authorize?oauth_token=第二个区别是,/authorize_submit一旦应用程序连接,Dropbox url 就不会改变,因此GetAccessTokenAsync永远不会被调用,并且不会存储用户令牌和用户密码。

迄今为止,我的调查提出了几种不理想的解决方法

  1. GetAccessTokenAsync调用周围删除 url 验证并吃掉生成的 DropboxExceptions
  2. 在初始调用中添加回调 url BuildAuthorizeUrl

我目前正在做 1. 只是为了让事情正常运行,但显然这不是一个长期的解决方案。我宁愿避免使用回调 url,因为这对于移动应用程序来说似乎过于复杂。

我所追求的是一种让 8.0 项目以与 7.1 项目相同的方式运行的方法。我已经查看了 Dropnet 源代码,其中包含https://api.dropbox.com作为它的基本 URL,所以我更不清楚 7.1 代码是如何工作的。

4

2 回答 2

1

行为差异是由 8.0 项目使用 System.Windows.Interactivity 将 Navigated 事件转换为对 ViewModel 上的 Command 的调用引起的。这似乎会阻止网站和 WebBrowser 控件正确交互并重定向到https://www.dropbox.com


当前的

XAML

<phone:WebBrowser x:Name="Browser"
                  IsScriptEnabled="True"
                  Visibility="{Binding IsAuthenticated, Converter={StaticResource BoolToInvisibilityConverter}}"
                  Source="{Binding AuthenticateUri}">               
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Navigated" >
            <i:InvokeCommandAction Command="{Binding BrowserNavigated}" 
                                    CommandParameter="{Binding Source, ElementName=Browser}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</phone:WebBrowser>

C#

BrowserNavigated = new RelayCommand<Uri>(u =>
                {                   
                    RemoteStorage.CheckAuthentication(u, () => IsAuthenticated = true, ex => ShowException(ex));
                });

已更正

XAML

        <phone:WebBrowser x:Name="Browser"
                          IsScriptEnabled="True"
                          Visibility="{Binding IsAuthenticated, Converter={StaticResource BoolToInvisibilityConverter}}"
                          Source="{Binding AuthenticateUri}"
                          Navigated="Browser_Navigated"/>

C#

    private void Browser_Navigated(object sender, NavigationEventArgs e)
    {
        ViewModel.BrowserNavigated.Execute(e.Uri);
    }

在这两种情况下,绑定到 WebBrowser Source 的视图模型的 AuthenticateUri 属性由 DropboxStorage 类中的 StartAuthentication 方法设置。

添加事件处理程序后,8.0 项目按预期工作。

于 2014-08-04T19:15:19.773 回答
0

不久前我也开始看到这个问题。直到那时,我的应用程序在 WP8 上运行良好。我不记得所有细节,但我查看了我的签入以修复它,我认为第一个 url 的额外页面加载开始发生。Dropbox 也没有关于更改的警告。

为了解决它,我等待某个 url 出现在LoadCompleted事件中。您使用Navigated我认为也应该起作用的事件。

我会像这样修改你的事件处理程序:

public void Browser_Navigated(object sender, NavigationEventArgs e)
{
    if (e.Uri.AbsolutePath == "/1/oauth/authorize_submit")
    {
        DropboxStorage.CheckAuthentication(
            e.Uri,
            () => NavigationService.GoBack(),
            ex => ShowException(ex));
    }
}
于 2014-08-04T15:18:35.107 回答