【问题标题】:Problem deserializing Google profile response反序列化 Google 个人资料响应的问题
【发布时间】:2019-08-18 10:04:35
【问题描述】:

我在 Xamarin.Forms 应用程序中向 google 进行身份验证。一旦通过身份验证,我想检索用户电子邮件,并使用我改编自 this blog 的代码,用于检索电子邮件的代码:

public class GoogleProfile
{
    [Preserve]
    [JsonConstructor]
    public GoogleProfile() { }

    public string sub { get; set; }
    public string name { get; set; }
    public string given_name { get; set; }
    public string profile { get; set; }
    public string picture { get; set; }
    public string email { get; set; }
    public string email_verified { get; set; }
    public string locale { get; set; }
}

public class GoogleService
{
    public async Task<string> GetEmailAsync(string tokenType, string accessToken)
    {
        var httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(tokenType, accessToken);
        var json = await httpClient.GetStringAsync("https://www.googleapis.com/oauth2/v3/userinfo");//https://www.googleapis.com/userinfo/email?alt=json");
        var profile = JsonConvert.DeserializeObject<GoogleProfile>(json);
        return profile.email;
    }
}

现在,在最后一行 return profile.email 中有一个断点,我已经“看到”了这样的 json 文件:

{
  "sub": "",
  "name": "",
  "given_name": "",
  "profile": "",
  "picture": "",
  "email": "",
  "email_verified": "",
  "locale": "",
}

引号之间显然是数据。

我不是很习惯 JSon 但是阅读this 我认为格式只是"nameOfProperty":"ValueOfProperty",所以我做了GoogleProfile 对象。

我也读到[Preserve][JsonConstructor] 属性是必需的,因此链接器在编译时不只是“删除”空的构造函数。

没有异常,也没有明显的问题,但是如果我在最后一行 return profile.email; 下放一个断点,我可以看到 json 对象包含所有数据并且非常好,但是 profile 对象有 email 属性值为null...

我不明白:其他属性发生了什么?甚至可能吗?你知道,你用一堆属性编写了一个对象,但创建的对象只有其中一个属性吗?如果该对象的所有属性的值为 null,则可以,但是其他属性到哪里去了?

为了确定,我已经清理并重建了项目和解决方案,我删除了 binobj 文件夹,然后再次清理并重建......我已经完成了显而易见的事情。

问题是,正如您在我之前提到的博客中看到的那样,首先我没有使用GoogleProfile 对象,我只是复制了博客中的对象......只有一个名为email 的属性。视觉工作室或xamarin或其他东西是否有可能被窃听并且更改没有得到反映?我对此表示怀疑,因为我已经更改了 GetStringAsync 方法中使用的 URI,它确实得到了反映,但是我不知道。

PD:与此同时,我将 JSON 直接解析为普通字符串,它是一个简单的对象,我只需要电子邮件,但是,如果我不得不以这种方式解析它,那就太可惜了而不是仅仅反序列化它。


编辑: 正如皮肤在我使用过的 cmets 中所建议的那样http://jsonutils.com/

其中一个属性是 bool(当然),所以我更改了它,现在的对象是:

public class GoogleProfile
{
    [Preserve]
    [JsonConstructor]
    public GoogleProfile() { }

    public string sub { get; set; }
    public string name { get; set; }
    public string given_name { get; set; }
    public string profile { get; set; }
    public string picture { get; set; }
    public string email { get; set; }
    public bool email_verified { get; set; }
    public string locale { get; set; }
}

但这并没有改变结果,仍然发生同样的事情。断点处的结果图片:

【问题讨论】:

  • ???那么示例 POCO GoogleProfile 没有 API 调用返回的所有其他属性?为什么需要解析 JSON 字符串? JSONConvert.Deserialize 应该为您完成工作,并将所有属性值放在您的 POCO 类对象中。您是否在var profile = JsonConvert.DeserializeObject&lt;GoogleProfile&gt;(json); 设置了断点并检查了变量json 的值?它有电子邮件地址吗?如果不是,它将被设置为 null。
  • 是的,正如我在问题中所说的那样。使用断点检查变量 json 的值,并且与我在问题中编写的示例完全相同,但引号之间的值正确......然后我进行 json 反序列化和对象 profile 仅使用创建一个名为 email 的属性值为 null。
  • 您是否尝试过添加其余属性以便反序列化所有这些属性?也许试试看。
  • 对不起,我不明白“在其余属性中添加”。所有属性都编码在对象中,并检索到 json 中的所有值。我是一个业余爱好者,我没有用过那么多 JSON,也许你指的是我不知道的东西。我只是想如果文本文件有一个与对象属性名称匹配的标签,反序列化器会将这些值应用于正确的属性而无需进一步编码。
  • 获取你的 json,去 jsonutils.com 让它为你创建类。

标签: c# json xamarin.forms google-oauth xamarin.auth


【解决方案1】:

我认为您的代码没有任何问题。我使用了与您相同的代码,但没有更改任何内容。我使用我自己的tokenTypeaccessToken

我的步骤:

  1. 将您的代码复制到我的项目中。
  2. 使用blog中的项目获取我自己的令牌
  3. 安装newtonsoft Nuget 包
  4. 运行项目并获得结果

那么,您的帐户有问题吗?你的账户有邮箱吗?和我的有区别吗?

这是我得到的:

代码:

public partial class MainPage : ContentPage
{
    public MainPage()
    {

        InitializeComponent();

        testAsync();
    }

    public async Task testAsync()
    {

        GoogleService googleS = new GoogleService();
        // use your token here
        var email = await googleS.GetEmailAsync("", "");
        Console.WriteLine(email);
    }

    public class GoogleProfile
    {
        [Preserve]
        [JsonConstructor]
        public GoogleProfile() { }

        public string sub { get; set; }
        public string name { get; set; }
        public string given_name { get; set; }
        public string profile { get; set; }
        public string picture { get; set; }
        public string email { get; set; }
        public string email_verified { get; set; }
        public string locale { get; set; }
    }

    public class GoogleService
    {
        public async Task<string> GetEmailAsync(string tokenType, string accessToken)
        {
            var httpClient = new HttpClient();
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            var json = await httpClient.GetStringAsync("https://www.googleapis.com/oauth2/v3/userinfo");//https://www.googleapis.com/userinfo/email?alt=json");
            var profile = JsonConvert.DeserializeObject<GoogleProfile>(json);

            Console.WriteLine(json);
            Console.WriteLine(profile);


            return profile.email;
        }
    }
}

【讨论】:

  • 我的代码和你的一样,json包含包括电子邮件在内的所有数据。恐怕真正的问题与这个有关:forums.xamarin.com/discussion/45327/…
  • 基本上,并非所有更改都不会在部署时得到反映。在这之前我有一个不同的对象,我怀疑应用程序正在使用GoogleService 上的新代码编译,但GoogleProfile 中的旧代码编译,所以 JSON 无法正确反序列化它,因此没有给我的电子邮件。我会尝试看看是否能解决问题并更新问题
  • 你可以尝试删除bin和obj文件夹,然后重建项目。
  • 你也可以新建一个项目来排查问题。
  • 现在它可以工作了……我一度以为我做不到。我尝试删除文件夹和所有文件夹,但对我来说,仅在 android 项目属性中停用快速部署并将链接器更改为仅 SDK 程序集。但是,它现在可以工作了。我会接受你的回答,因为它确认我问题不是代码并引导我解决真正的问题。
猜你喜欢
  • 1970-01-01
  • 2014-02-15
  • 2019-02-03
  • 2012-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多