How to deserialise Array with Refit? - c#

I have the following error trying to deserialise a Json with Refit in a PCL :
Cannot deserialize the current JSON object (e.g. {"name":"value"})
into type 'System.Collections.Generic.List`1[UserItem]' 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) 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 'user.id', line 1, position 42.
I think it comes from the Arrays returned for the interests ?
{
"error": {
"code": 0,
"msg": ""
},
"user": {
"id": "5",
"first_name": "test",
"last_name": "test",
"email": "a#gmail.com",
"auth_token": "****",
"date_of_birth": "0001-05-06 00:00:00",
"group_id": "1",
"group_name": null,
"postal_code": "56456",
"city": "Annecy",
"country": "France",
"facebook_id": null,
"facebook_img": null,
"status": null,
"is_activated": null,
"gcm_id": "GHJK",
"device_id": null,
"platform": "android",
"interest": ["1", "2"],
"profile_pic": "profile.jpg",
"cover_img": "cover.jpg",
"address": null,
"invoicing_address": "address",
"invoicing_city": "city",
"invoicing_country": "",
"invoicing_postal_code": "78654",
"gender": null,
"company_no": "1234",
"company_name": "",
"about_company": "",
"company_logo": "",
"company_legal_name": "lumao",
"company_contact_no": "",
"company_address": "",
"company_city": "",
"company_country": "",
"company_postal_code": "",
"vat_no": "",
"telephone": null,
"membership_status": null,
"contact_status": 2,
"company_interests": [],
"needs": ["not_implemented"]
}
}
EDIT :
Here is how I instantiate Refit :
Func<HttpMessageHandler, IFlairPlayApi> createClient = messageHandler =>
{
var client = new HttpClient(messageHandler)
{
BaseAddress = new Uri(ApiBaseAddress)
};
return RestService.For<IFlairPlayApi>(client);
};
NativeMessageHandler msgHandler = new NativeMessageHandler();
msgHandler.DisableCaching = true;
_speculative = new Lazy<IFlairPlayApi>(() => createClient(
new RateLimitedHttpMessageHandler(msgHandler, Priority.Speculative)
));
And how I call the service :
[Get("/getuser.json")]
Task<UserResponse> GetUser(int userid, int contact_id, string langval);
EDIT 2 :
I tried to change UserResponse to dynamic and then parse the dynamic object into a UserReponse, but it still strip the interests. And I would loose the benefit of using Refit :
[Get("/getuser.json")]
Task<dynamic> GetUser(int userid, int contact_id, string langval);
dynamic userObject = await FPApi.Speculative.GetUser(user.id, contact_id, FPEngine.Instance.Lang);
JObject jUser = userObject as JObject;
UserResponse response = jUser.ToObject<UserResponse>();
Am I doing it wrong ? isn't there a simple way to retrieve Arrays of strings ?

I had the same problem, I solved it as follows:
The service return, returns string, that is, the raw Json:
public interface IApiHgFinance
{
[Get("/taxes?key=minhachave")]
Task<string> GetTaxes();
}
And in the code where I call the service, I treat Json:
try
{
IApiHgFinance ApiHgFinance = Refit.RestService.For<IApiHgFinance>("https://api.hgbrasil.com/finance");
var result = await ApiHgFinance.GetTaxes();
var jo = Newtonsoft.Json.Linq.JObject.Parse(result);
var taxes = jo["results"].ToObject<itemTaxes[]>();
foreach (var item in taxes)
{
MessageBox.Show($"Taxa CDI : {item.Cdi} \nTaxa Selic : {item.Selic} \nData Atualização: {item.Date}",
"Atualização de informações", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
catch (Exception ex)
{
MessageBox.Show($"Erro: {ex.Message}", "Erro ao tentar recuperar as taxas do dia.", MessageBoxButtons.OK, MessageBoxIcon.Error);
}

Related

.net core How to get json object using path in string variable

How to get json object using path in string variable,This is the JSON Schema data structure string stored in my database,I tried to convert to json data structure but it didn't work,I want to convert such a string data structure into a json object.
string json = $#"{{
""xcollapse.id"":""xcollapse"",
""xcollapse.el"":202,
""xcollapse.cols.props.cn"":""title"",
""xcollapse.cols.props.desc"":"""",
""xcollapse.cols.props.visible"":-1,
""xcollapse.cols.children.id"":""f272681"",
""xcollapse.cols.children.el"":200,
""xcollapse.cols.children.props"":""{{}}""
}}";
var jObj = JObject.Parse(json);
var result = jObj.ToString();
I would like to get the following results.
{
"xcollapse": {
"id": "xcollapse",
"el": "202",
"cols": [
{
"props": {
"cn": "title",
"desc": "",
"visible": "-1"
},
"children": {
"id": "title",
"el": "",
"props": [
{}
]
}
}
]
}
}
The complete data structure in the database looks like this,I now need to convert to json objects to return to the front end.
{
"xcollapse.id":"xcollapse",
"xcollapse.el":202,
"xcollapse.props":{
},
"xcollapse.styles.visible":-1,
"xcollapse.cols.deletable":false,
"xcollapse.cols.props.cn":"title",
"xcollapse.cols.props.desc":"",
"xcollapse.cols.props.visible":-1,
"xcollapse.cols.styles":null,
"xcollapse.cols.children.id":"f272681",
"xcollapse.cols.children.el":200,
"xcollapse.cols.children.props":{
},
"xcollapse.cols.children.styles.visible":-1,
"xcollapse.cols.children.cols.deletable":false,
"xcollapse.cols.children.cols.props.visible":-1,
"xcollapse.cols.children.cols.styles.span":8,
"xcollapse.cols.children.cols.children.id":"fname",
"xcollapse.cols.children.cols.children.el":100,
"xcollapse.cols.children.cols.children.props.ek":"fbillhead",
"xcollapse.cols.children.cols.children.props.cn":"title",
"xcollapse.cols.children.cols.children.props.group":"",
"xcollapse.cols.children.cols.children.props.fn":"fname",
"xcollapse.cols.children.cols.children.props.pn":"fname",
"xcollapse.cols.children.cols.children.props.desc":"",
"xcollapse.cols.children.cols.children.props.must":"0",
"xcollapse.cols.children.cols.children.props.visible":-1,
"xcollapse.cols.children.cols.children.props.len":"100",
"xcollapse.cols.children.cols.children.props.lock":"0",
"xcollapse.cols.children.cols.children.props.copy":"1",
"xcollapse.cols.children.cols.children.props.defval":"",
"xcollapse.cols.children.cols.children.props.canchange":"0",
"xcollapse.cols.children.cols.children.props.xlsin":"1",
"xcollapse.cols.children.cols.children.props.acl":"1",
"xcollapse.cols.children.cols.children.props.sbm":"0",
"xcollapse.cols.children.cols.children.props.notrace":"1",
"xcollapse.cols.children.cols.children.props.apipn":"sourceType",
"xcollapse.cols.children.cols.children.props.ctlfk":"",
"xcollapse.cols.children.cols.children.props.editmode":"0",
"xcollapse.cols.children.cols.children.props.xsslv":"0",
"xcollapse.cols.children.cols.children.styles.align":"left",
"xcollapse.cols.children.cols.children.styles.width":"",
"xcollapse.cols.children.cols.children.styles.row":2,
"xcollapse.cols.children.cols.children.cols":{},
"xcollapse.cols.children.cols.children.deletable":true,
"xcollapse.cols.children.cols.children.pid":"",
"xcollapse.cols.children.cols.children.seq":1,
"xcollapse.cols.children.cols.seq":1,
"xcollapse.cols.children.deletable":true,
"xcollapse.cols.children.pid":"",
"xcollapse.cols.children.seq":1,
"xcollapse.cols.seq":1,
"xcollapse.deletable":true,
"xcollapse.pid":"",
"xcollapse.seq":1,
}

Best way to Deserialize JSON to Dynamic using C#

I'd like to know which is the best way do Deserialize to Dynamic, using NewtonSoft.Json and C#
The code below works, but I didn't like it. I would like to simplify it, using "named properties".
The main purpose is to get the last object named "results". It is an array of objects.
I know I can use a response object, but I need to use a dynamic or generic object.
var searchprod = wscli.BuscarImagensPorProdutoId(prodSku.ToString());
dynamic obj = JsonConvert.DeserializeObject<dynamic>(searchprod.Result.ToString());
dynamic obj1 = obj.results.ToString();
dynamic obj2 = JsonConvert.DeserializeObject<dynamic>(obj1);
dynamic results = ((JContainer)obj2).ToList();
if (results != null)
{
foreach (IEnumerable<JToken> item in results)
{
var prodId = item.ToList()[0];//id is first position
var id = ((JProperty)prodId).Value.ToString();
if (!string.IsNullOrEmpty(id))
{
//Delete image
var res = await wscli.ExcluirImagemProduto(id);
if (res == null || res is string)
{
throw new Exception($"Error image {id}. Details: {(res == null ? "null" : res.ToString())}");
}
if (res.status == null || res.status.ToString() != "OK")
{
throw new Exception($"Error image {id} and product {prodSku}. Details: {JsonConvert.SerializeObject(res)}");
}
}
}
}
Json:
{
"count": 5,
"next": null,
"previous": null,
"results": [
{
"id": 62217,
"image": "https://io.com/image1.jpg",
"position": 5,
"title": null,
"video": null,
"add_date": "2022-07-06T22:13:14.538307",
"change_date": "2022-07-06T22:13:14.538331",
"product": 12528,
"skus": []
},
{
"id": 62216,
"image": "https://io.com/image2.jpg",
"position": 4,
"title": null,
"video": null,
"add_date": "2022-07-06T22:13:00.435415",
"change_date": "2022-07-06T22:13:00.435436",
"product": 12528,
"skus": []
},
{
"id": 62215,
"image": "https://io.com/image3.jpg",
"position": 3,
"title": null,
"video": null,
"add_date": "2022-07-06T22:12:51.071782",
"change_date": "2022-07-06T22:12:51.071808",
"product": 12528,
"skus": []
},
{
"id": 62214,
"image": "https://io.com/image4.jpg",
"position": 2,
"title": null,
"video": null,
"add_date": "2022-07-06T22:12:35.943846",
"change_date": "2022-07-06T22:12:35.943871",
"product": 12528,
"skus": []
},
{
"id": 62213,
"image": "https://io.com/image5.jpg",
"position": 1,
"title": null,
"video": null,
"add_date": "2022-07-06T22:12:17.221066",
"change_date": "2022-07-06T22:12:17.221089",
"product": 12528,
"skus": []
}]
}
Thanks
It's not super clear what you don't like about what you have, but if you're looking to be able to access things by path / property name, something like this might work out for you. (getting strings into C# annoys me, I popped it to a file)
[TestMethod]
public void GetNode()
{
string jsonString = File.ReadAllText("json1.json");
Assert.IsNotNull(jsonString);
JObject jObject = JObject.Parse(jsonString);
// selects the node with results
var resultsNode = jObject.SelectToken("$..results");
foreach (JToken item in resultsNode)
{
Console.WriteLine(item["image"]);
}
}
I think reading this article can be useful.
https://inspiration.nlogic.ca/en/a-comparison-of-newtonsoft.json-and-system.text.json
If you have used Newtonsoft.Json features in your existing projects that are missing in System.Text.Json or have heavily decorated your DTO’s with several attributes from Newtonsoft.Json, you will probably encounter many obstacles during migration.
If you are starting a new project, I would recommend using System.Text.Json. Microsoft is constantly improving System.Text.Json and there have been significant improvements between .Net Core 3.1 and .Net 5.0 and Microsoft has already started planning for .Net 6.0.

How do I append an JsonProperty to another JsonProperty

I have this JsonDocument which looks like this
string jsonString = "{\"year\": 0, \"class\": [], \"schools\": []}";
JsonDocument newSchema = JsonDocument.Parse(jsonString)
And a bunch of JSON files, with these properties filed out.
Each of the JSON file have the same year, but contain information of one specific class and one specific school. None of the them is the same beside the year.
I trying to create a one JsonDocument with all class and schools put together into one JsonDocument, but seem to have a problem with appending the JsonProperty together..
This is what I have tried so far:
using (JsonDocument newSchema = JsonDocument.Parse(jsonString))
{
List<JsonProperty> properties = new List<JsonProperty>();
foreach(JsonProperty a in newSchema.RootElement.EnumerateObject())
{
properties.Add(a);
}
foreach (string classandSchoolDefinition in loadableSchemaDefinitions)
{
string schemaDefinitionAsJson = File.ReadAllText(classandSchoolDefinition );
JsonDocument schemaJson = JsonDocument.Parse(schemaDefinitionAsJson);
foreach (JsonProperty a in schemaJson.RootElement.EnumerateObject())
{
switch (a.Name)
{
case "year":
Console.WriteLine($#"({a.Name}+{a.Value}, {a.Value.ValueKind})");
break;
case "class":
Console.WriteLine($#"({a.Name}+{a.Value}, {a.Value.ValueKind})");
break;
case "school":
Console.WriteLine($#"({a.Name}+{a.Value}, {a.Value.ValueKind})");
break;
default:
break;
}
}
}
How do I concat each the Jsonproperty value to one combined newSchema, and not keep the into one?
In this case I only want append an array to another array.
You can reach this with Newtonsoft.Json
For example, you have
var o1 = JObject.Parse(#"{
'Name': 'Max',
'Enabled': false,
'Roles': [ 'User' ]
}");
and another object
var o2 = JObject.Parse(#"{
'Enabled': true,
'Roles': [ 'User', 'Admin' ]
}");
simply use Merge function like this -
o1.Merge(o2, new JsonMergeSettings
{
// to avoid duplicates
MergeArrayHandling = MergeArrayHandling.Union
});
the result will be -
{
"FirstName": "Max",
"Enabled": true,
"Roles": [
"User",
"Admin"
]
}

Transform a JSON object to a JSON array, taking the first level of properties

I've this JSON object
{
"08f4f705-6e14-4781-8241-d04bf2dc6ada": {
"description": "xxxxxxxx",
"note": "yyyyyyyy"
},
"05f4f995-6e14-4567-8241-d04bf2d456ee": {
"description": "aaaaaa",
"note": "bbb"
},
"0675f995-6e14-4567-8241-d4567f2d456z": {
"description": "fffff",
"note": "gggg"
}
}
I need to convert into a JSON array like this:
(the elements should be the content of the first level properties)
[
{
"description": "xxxxxxxx",
"note": "yyyyyyyy"
},
{
"description": "aaaaaa",
"note": "bbb"
},
{
"description": "fffff",
"note": "gggg"
}
]
I can't manipulate the object and I didn't find an appropriate resource to follow. How can I do it?
You can achieve this by deserializing your json string into Dictionary<string, object>:
var obj = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
After that you extract the values and serialize them back to json:
var newJson = JsonConvert.SerializeObject(obj.Values);

deserialize json c# get value of variable

I deserialize JSON with Newtonsoft JSON DLL. I have next JSON answer
string answer = getjsonnanswer(url);
JObject a = JObject.Parse(answer);
How can I refer to a, that get 615 - Its value of variable in JSON answer, but it hasn't got a name.
{
"response": [615,
{
"body": "Привет) как жизнь?",
"title": "Re(2): ...",
"date": 1268238828,
"uid": 10024748,
"mid": 11056,
"read_state": 0,
"out":0
},
{
"body": "Жду :)",
"title": "Re(23): ...",
"date": 1268238448,
"uid": 27495120,
"mid": 11045,
"read_state": 1,
"out":1
}]
}
You just need to add the indexer to get the first item from the "response" array:
JObject a = JObject.Parse(answer);
var val = a["response"][0];
JObject a = JObject.Parse(answer);
JsonObject a = new JsonObject(answer);
JsonArray ss = (JsonArray)a["response"];
var result = ss[0];

Categories

Resources