not really sure if I'm asking this in the correct manner. But I am doing a project for my university with CRM systems and API's. Now I found Flurl to help me do my HTTP request. and it works great until I try and do a get all accounts to my free developer account to salesforce (i added some test accounts). The JSON I receive is this:
{
"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"
}
]
}
and the error I receive is the following:
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.
I also found this link on here: Parsing from json to object using FLURL
but I can't seem to recreate this with my model:
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; }
}
}
and at last this is how de Deserialize is in my code
response = request.GetAsync();
responseData = await response.ReceiveJson<T>().ConfigureAwait(true);
Edit my controller class where the requests come in:
[HttpGet("{CRM}")]
public IEnumerable<ICRMItem> Get(string CRM)
{
if(CRM == "SalesForce")
{
ICRMService AccountGetAll = new AccountService();
var Account = AccountGetAll.With<AccountItem>().GetAll().ResponseData();
return Account;
}
}
After @Todd Menier his changes
as my response in Todd's message shamefully it didn't do the trick. and i still get this exception message.
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.
Edit
Todd Menier asked me for the path my code takes so here it is:
After I do my call it comes in my controller
ICRMService AccountGetAll = new AccountService();
var Account = AccountGetAll.With<AccountItem>().GetAll().ResponseData();
return Account;
Where after it goes into my service:
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
};
}
then it gets the Recources
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;
and it gets into my GetAll function
public ICRMResponse<IEnumerable<T>> GetAll()
{
return Get<IEnumerable<T>>();
}
as you see it goes to a get function
private ICRMResponse<TOut> Get<TOut>(string id = "")
{
return DoRequest<TOut>(Resource + id, "GET", null).Result;
}
from where it goes into the 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;
from where it breaks and shows the message as state before
i'll check back around 16:00 GMT+1 or else Tuesday morning hope i gave you everything you needed