使用 Flurl 和 ASP.net Core 解析 Json 数据

Parsing Json Data With Flurl and ASP.net Core

不太确定我问这个问题的方式是否正确。但是我正在用 CRM 系统和 API 为我的大学做一个项目。 现在我发现 Flurl 可以帮助我执行 HTTP 请求。在我尝试将所有帐户添加到我的免费开发人员帐户到 salesforce 之前,它一直很好用(我添加了一些测试帐户)。我收到的 JSON 是这样的:

{ 
"objectDescribe": {
"activateable": false,
"createable": true,
"custom": false,
"customSetting": false,
"deletable": true,
"deprecatedAndHidden": false,
"feedEnabled": true,
"hasSubtypes": false,
"isSubtype": false,
"keyPrefix": "001",
"label": "Account",
"labelPlural": "Accounts",
"layoutable": true,
"mergeable": true,
"mruEnabled": true,
"name": "Account",
"queryable": true,
"replicateable": true,
"retrieveable": true,
"searchable": true,
"triggerable": true,
"undeletable": true,
"updateable": true,
"urls": {
  "compactLayouts": "/services/data/v39.0/sobjects/Account/describe/compactLayouts",
  "rowTemplate": "/services/data/v39.0/sobjects/Account/{ID}",
  "approvalLayouts": "/services/data/v39.0/sobjects/Account/describe/approvalLayouts",
  "defaultValues": "/services/data/v39.0/sobjects/Account/defaultValues?recordTypeId&fields",
  "listviews": "/services/data/v39.0/sobjects/Account/listviews",
  "describe": "/services/data/v39.0/sobjects/Account/describe",
  "quickActions": "/services/data/v39.0/sobjects/Account/quickActions",
  "layouts": "/services/data/v39.0/sobjects/Account/describe/layouts",
  "sobject": "/services/data/v39.0/sobjects/Account"
}  
},  
"recentItems": [
{
  "attributes": {
    "type": "Account",
    "url": "/services/data/v39.0/sobjects/Account/0015800000it9T3AAI"
  },
  "Id": "0015800000it9T3AAI",
  "Name": "Test 5"
},
{
  "attributes": {
    "type": "Account",
    "url": "/services/data/v39.0/sobjects/Account/0015800000it8eAAAQ"
  },
  "Id": "0015800000it8eAAAQ",
  "Name": "Test 4"
},
{
  "attributes": {
    "type": "Account",
    "url": "/services/data/v39.0/sobjects/Account/0015800000it8dbAAA"
  },
  "Id": "0015800000it8dbAAA",
  "Name": "Test 3"
},
{
  "attributes": {
    "type": "Account",
    "url": "/services/data/v39.0/sobjects/Account/0015800000it8dHAAQ"
  },
  "Id": "0015800000it8dHAAQ",
  "Name": "Test 2"
},
{
  "attributes": {
    "type": "Account",
    "url": "/services/data/v39.0/sobjects/Account/0015800000it8ciAAA"
  },
  "Id": "0015800000it8ciAAA",
  "Name": "Test 1"
}  
]
}

我收到的错误如下:

Request to https://eu6.salesforce.com/services/data/v39.0/sobjects/Account/ failed. 
Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.IEnumerable`1[InHollandCRMAPI.Models.AccountItem]' 
because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) that can be deserialized from a JSON object.
JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.
Path 'objectDescribe', line 1, position 18.

我也在此处找到了这个 link:

但我似乎无法用我的模型重新创建它:

public class AccountItem : ICRMItem
{
    public Describe[] ObjectDescribe { get; set; }
    public List<Recent> recentItems { get; set; }

    public class Recent
    {
        public Attributes[] Attributes { get; set; }
        public string Id { get; set; }
        public string Name { get; set; }
    }

    public class Describe
    {
        public bool activateable { get; set; }
        public bool createable { get; set; }
        public bool custom { get; set; }
        public bool customSetting { get; set; }
        public bool deletable { get; set; }
        public bool deprecatedAndHidden { get; set; }
        public bool feedEnabled { get; set; }
        public bool hasSubtypes { get; set; }
        public bool isSubtype { get; set; }
        public string keyPrefix { get; set; }
        public string label { get; set; }
        public string labelPlural { get; set; }
        public bool layoutable { get; set; }
        public bool mergeable { get; set; }
        public bool mruEnabled { get; set; }
        public string name { get; set; }
        public bool queryable { get; set; }
        public bool replicateable { get; set; }
        public bool retrieveable { get; set; }
        public bool searchable { get; set; }
        public bool triggerable { get; set; }
        public bool undeletable { get; set; }
        public bool updateable { get; set; }
        public Urls[] urls { get; set; }
    }
}

最后这就是我代码中反序列化的方式

                    response = request.GetAsync();
                    responseData = await response.ReceiveJson<T>().ConfigureAwait(true);

编辑 我的控制器class 请求的来源:

[HttpGet("{CRM}")]
    public IEnumerable<ICRMItem> Get(string CRM)
    {
        if(CRM == "SalesForce")
        {
            ICRMService AccountGetAll = new AccountService();
            var Account = AccountGetAll.With<AccountItem>().GetAll().ResponseData();
            return Account;
        }
}

在@Todd Menier 之后他的改变

作为我在托德的消息中的回应,可耻的是它没有达到目的。我仍然收到此异常消息。

Request to https://eu6.salesforce.com/services/data/v39.0/sobjects/Account/ ailed. Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type
'System.Collections.Generic.IEnumerable`1[InHollandCRMAPI.Models.AccountItem]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly. 
To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List<T>) 
that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. 
Path 'objectDescribe', line 1, position 18.

编辑

Todd Menier 问我代码的路径,所以这里是:

在我调用之后,它会进入我的控制器

            ICRMService AccountGetAll = new AccountService();
            var Account = AccountGetAll.With<AccountItem>().GetAll().ResponseData();
            return Account;

它进入我的服务后的位置:

    public ICRMServiceWithResource<T> With<T>(bool beta = false) where T : ICRMItem
    {
        var Uri = "https://eu6.salesforce.com/services/data/v39.0/";
        return new SalesForceServiceWithResource<T>()
        {
            Resource = Resources.Resources.GetResource<T>(),
            Uri = Uri
        };
    }

然后获取资源

  public class Resources
{
    public const string Accounts = "sobjects/Account/";

    public static string GetResource<T>() where T : ICRMItem
    {
        var type = typeof(T);

        if (type == typeof(AccountItem)) return Accounts;

它进入我的 GetAll 函数

    public ICRMResponse<IEnumerable<T>> GetAll()
    {
        return Get<IEnumerable<T>>();
    }

如您所见,它进入了一个 get 函数

    private ICRMResponse<TOut> Get<TOut>(string id = "")
    {
        return DoRequest<TOut>(Resource + id, "GET", null).Result;
    }

从哪里进入 DoRequest:

public async Task<ICRMResponse<T>> DoRequest<T>(string url, string method, object body)
        {
            ICRMResponse<T> result;
            try
            {
                GetCRM(AppConfig.Key);
                var request = Authorise(url);
                Task<HttpResponseMessage> response;
                T responseData;
                switch (method.ToLower())
                {
                    case "post":
                        if (body == null)
                        {
                            throw new ArgumentNullException("body");
                        }
                        response = request.PostJsonAsync(body);
                        responseData = await response.ReceiveJson<T>().ConfigureAwait(false);
                        break;
                    case "get":
                        response = request.GetAsync();
                        responseData = await response.ReceiveJson<T>().ConfigureAwait(true);
                    break;

从它中断的地方开始,并将消息显示为之前的状态

我会在 16:00 格林威治标准时间 +1 左右回来查看,否则周二早上希望我能给你你需要的一切

在你的C#模型中,urls是一个数组,但它不是JSON表示中的数组;它是一个对象。

你没有 post 你的 Urls class 的定义,但我猜它看起来像这样:

public class Urls
{
    public string compactLayouts { get; set; }
    public string rowTemplate { get; set; }
    public string approvalLayouts { get; set; }
    public string defaultValues { get; set; }
    public string listviews { get; set; }
    public string describe { get; set; }
    public string quickActions { get; set; }
    public string layouts { get; set; }
    public string sobject { get; set; }
}

JSON 返回一个 单个 对象,看起来像这样,而不是它们的集合。因此,在您的 Describe class 中,只需删除数组并像这样定义它:

public Urls urls { get; set; }

更新:

起初我没有看到,但 objectDescribeattributes 也有类似的问题。这些也不是数组,所以不要在 C# 模型中以这种方式定义它们。以下是所有更改的摘要:

public class AccountItem : ICRMItem
{
    public Describe ObjectDescribe { get; set; }
    ...

    public class Recent
    {
        public Attributes Attributes { get; set; }
        ...
    }

    public class Describe
    {
        ...
        public Urls urls { get; set; }
    }
}

Soo,我刚刚修复了错误。试图获取所有帐户的列表。但 salesforce 已经为您列出(部分)客户。

问题是 IEnumerableGetAll() 函数中(对大多数 CRM 系统来说效果很好)但是如果你想完成这个,你需要将 IEnumerable<T> 更改为只是 T,这将是 SalesForce

的快速修复

我的下一步是生成包含所有帐户信息的帐户列表(因为大多数 GetAll 使用 CRM API)。

TL;DR

public ICRMResponse<IEnumerable<T>> GetAll() { return Get<IEnumerable<T>>(); }

应该是

public ICRMResponse<T> GetAll() //Technicly isn't a GetAll But a Get { return DoRequest<T>(Resource, "GET", null).Result; }

这是对此的修复 post 不是我最终愿望的修复,但我会关闭这个主题,否则我们会偏离主题