i have a solution where i consume a WebService using RestSharp providing JSON data. I have a class model like this, matching the received data:
public class PBase
{
public string Name { get; set; }
public virtual string GetValue()
{
return string.Empty;
}
}
public class PDouble : PBase
{
public double DoubleValue { get; set; }
public string Scale { get; set; }
public override string GetValue()
{
return DoubleValue.ToString(CultureInfo.InvariantCulture);
}
}
public class PBool : PBase
{
public bool? BoolValue { get; set; }
public override string GetValue()
{
if (!BoolValue.HasValue)
return null;
return BoolValue.Value ? "1" : "0";
}
}
Meerely deep within the data, such blocks as the following appear multiple times, holding the parameters of a parent object, which is not of much interest here (as everything else except the parameter thingy works fine):
"Parameters":
[
{
"__type": "PDouble:http://name.space.de/Parameter",
"Name": "DEPTH",
"DoubleValue": 5,
"Scale": "MM"
},
{
"__type": "PDouble:http://name.space.de/Parameter",
"Name": "HEIGHT",
"DoubleValue": 10,
"Scale": "MM"
},
{
"__type": "PBool:http://name.space.de/Parameter",
"Name": "ESSENTIAL",
"BoolValue": true
},
]
Now, the problem is, the deserialized data contains only PBase instances. So everything except Name is gone. How can i achieve correct deserialization?
EDIT:
For deserialization i have nothing special implemented, just like this:
var client = new RestClient()
{
BaseUrl = new Uri("MyURL")
};
var request = new RestRequest()
{
Resource = "MyResource",
Method = Method.GET
};
request.AddHeader("Accept", "application/json");
request.RequestFormat = DataFormat.Json;
var response = client.Execute<MyType>(request);
return response.Data;
Related
I'm using PostAsJsonAsync in the HttpClient to query Elastic, and it's failing on line 12, "wildcard"
I used https://json2csharp.com/ to convert the example JSON to C# objects.
This is the json that's being produced by Newtonsoft which fails.
{
"query": {
"bool": {
"must": [
{
"range": {
"#timestamp": {
"gte": "now-7d",
"lt": "now"
}
},
"wildcard": {
"request.keyword": {
"value": "/message/*/*-message/2c35669dd87e471faad1f90374d8d380/status",
"case_insensitive": true
}
}
}
]
}
}
}
This is an example that I was provided and used to convert the json to C# objects.
{
"query": {
"bool": {
"must": [
{
"range": {
"#timestamp": {
"gte": "now-7d",
"lt": "now"
}
}
},
{
"wildcard": {
"request.keyword": {
"value": "/message/*/*-message/2c35669dd87e471faad1f90374d8d380/status",
"case_insensitive": true
}
}
}
]
}
}
}
Both are valid JSON, but only the 2nd one is accepted by Elastic. It's seems to be expecting curly braces around the properties in must, but I can't figure out how to get the JSON to serialize this way.
You are encountering a limitation with code-generation tools such as https://json2csharp.com/, namely that they do not handle implied polymorphism very well. In such cases you may need to manually fix the generated classes.
Consider the following JSON array containing two different types of object:
[{"A" : "a value"},{"B" : "b value"}]
The array contains objects that either have a property A or a property B, but if you generate classes from this JSON, you will get a single, merged type with both properties:
public class Root
{
public string A { get; set; }
public string B { get; set; }
}
Whereas what you really want is something like:
public interface IRootBase { }
public class A : IRootBase
{
public string A { get; set; }
}
public class B : IRootBase
{
public string B { get; set; }
}
Given such a model, you will be able to construct a List<IRootBase> and serialize it to get the JSON shown. (And, to deserialize, see Deserializing polymorphic json classes without type information using json.net.)
In your case, the problem is with the array value of "must". As you can see this array contains two different types of object:
[
{
"range":{
"#timestamp":{
"gte":"now-7d",
"lt":"now"
}
}
},
{
"wildcard":{
"request.keyword":{
"value":"/message/*/*-message/2c35669dd87e471faad1f90374d8d380/status",
"case_insensitive":true
}
}
}
]
But https://json2csharp.com/ will create the following combined type:
public class Must
{
public Range range { get; set; }
public Wildcard wildcard { get; set; }
}
If you were to create an array with a single instance of Must containing both properties, you would get the invalid JSON rejected by Elastic.
Instead, you need to manually modify the auto generated types as follows:
#region Manually created from Must
public interface IMustConstraint { }
public class RangeConstraint : IMustConstraint
{
public Range range { get; set; }
}
public class WildcardConstraint : IMustConstraint
{
public Wildcard wildcard { get; set; }
}
#endregion Manually created from Must
public class Range
{
[JsonProperty("#timestamp")]
public Timestamp Timestamp { get; set; }
}
public class Timestamp
{
public string gte { get; set; }
public string lt { get; set; }
}
public class Wildcard
{
[JsonProperty("request.keyword")]
public RequestKeyword RequestKeyword { get; set; }
}
public class RequestKeyword
{
public string value { get; set; }
public bool case_insensitive { get; set; }
}
public class BoolQuery // Renamed from Bool for clarity
{
public List<IMustConstraint> must { get; set; } // Modified from List<Must>
}
public class Query
{
public BoolQuery #bool { get; set; }
}
public class Root
{
public Query query { get; set; }
}
And now you will be able to do:
Root root = new ()
{
query = new ()
{
#bool = new ()
{
must = new ()
{
new RangeConstraint() { range = new () { Timestamp = new () { gte = "now-7d", lt = "now" } } },
new WildcardConstraint() { wildcard = new () { RequestKeyword = new () { value = "/message/*/*-message/2c35669dd87e471faad1f90374d8d380/status", case_insensitive = true } } },
},
},
},
};
var json = JsonConvert.SerializeObject(root, Formatting.Indented);
And create your required JSON.
Demo fiddle here.
I'm trying to collect data from a client through an API. Eventually sending individual parts of the data that I collected to another project.
So for example I'm collecting an entire data object with id,Name,Status, etc. And I only want the id variable with it's value to be send to another project.
Everything works fine except from the sending part. I still had to paste all related classes to make it easier to understand.
I'm trying to send a list of objects. The problem is that I don't know how to send it the right way. You can see what I tried below. I'm creating my own object named WatchdogDTO which contains only the values that I want to send. Eventually I serialize it to send it to http://localhost:53661/api/Values. Which is another project I use to test if it works. Now it just literally sends the name of the list instead of the actual WatchdogDTO.
This is the data I'm collecting:
[
{
"id": "200",
"name": "Kerno (Camera)",
"hostName": "Amsterdam",
"status": false,
"hasCamera": true,
"cameraStatus": "0",
"lastSeen": "34324"
},
{
"id": "202",
"name": "Bassy (Location)",
"hostName": "Limburg",
"status": true,
"hasCamera": false,
"cameraStatus": "-1",
"lastSeen": "2344"
}
]
I created a corresponding model:
public class ServerStateDto
{
public string id { get; set; }
public string Name { get; set; }
public string HostName { get; set; }
public bool Status { get; set; }
public bool hasCamera { get; set; }
public string CameraStatus { get; set; }
public DateTime LastSeen { get; set; }
}
In the class ApiManager I collect the data above and deserialize it:
class ApiManager
{
HttpClient client = new HttpClient();
public List<ServerStateDto> CollectWatchdogData()
{
client.BaseAddress = new Uri("https://classified.Data.net:4802");
HttpResponseMessage response = client.GetAsync("/api/pdf/process/getalldata").Result;
if (response.IsSuccessStatusCode)
{
string dto = response.Content.ReadAsStringAsync().Result;
List<ServerStateDto> model = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ServerStateDto>>(dto);
return model;
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
return null;
}
}
}
This is just a general class that calls the functions CollectWatchdogData(); and PostWatchdogData();
{
public bool Start(HostControl hostControl)
{
ApiManager x = new ApiManager();
List<ServerStateDto> returnedData = x.CollectWatchdogData();
if (returnedData == null)
{
return false;
}
WatchdogApiClient cli = new WatchdogApiClient();
cli.PostWatchdogData(returnedData);
return true;
}
}
This is a model for the object that I'm sending. I only want to send Id from the model above:
public class WatchdogDTO
{
public string id { get; set; }
}
This class actually sends the WatchdogDTO from above to localhost:53661 which is another visual studio project of my which I use to test if the sending works.
public class WatchdogApiClient
{
private static readonly HttpClient client = new HttpClient();
//public async void PostWatchdogData(ServerStateDto toSend)
public async void PostWatchdogData(List<ServerStateDto> toSend)
{
//to actually send the data
WatchdogDTO toActuallySend = new WatchdogDTO()
{
id = toSend.ToString()
};
//Serialize data to bytestream so it can be sent
string serializedWatchDogData = JsonConvert.SerializeObject(toActuallySend);
if (string.IsNullOrEmpty(serializedWatchDogData))
{
return;
try
{
var response = await client.PostAsync("http://localhost:53661/api/Values", new StringContent(serializedWatchDogData, Encoding.UTF8, "application/json"));
}
catch (Exception ex)
{
Console.WriteLine($"Encountered an exception during PostAsync in method PostWatchDogData: {ex.Message}");
throw ex;
}
}
}
Eventually the destination of the data has a class and a model aswell to receive the data sent
model:
public class WatchdogDTO
{
public string id { get; set; }
}
This is the sending part, the sending works but the problem is that the value of WatchdogDTO data is the name of the list instead of the actual list with its values.
Class to receive the data send:
public class ValuesController : ApiController
{
[HttpPost]
public void PostWatchdogData([FromBody] WatchdogDTO data)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
hubContext.Clients.All.BroadcastMessage("Server", "b");
}
}
How can I send individual parts like for example only the id, or the host name, or the id AND the hostname.
Thanks in advance and sorry for the bunch of code.
I need to get GET response from REST API. I use RestSharp. The problem is, that one name of the response attribute is "$". This is the response:
[
{
"CodeId": {
"$": "00000000"
},
"Entity": {
"LegalName": {
"#xml:lang": "cs",
"$": "xxxxx"
}
}
}
]
How should I use the RestSharp to get the value of Entity.LegalName.$ ?
I found the answer thanks by #fredrik.
var client = new RestClient(url);
var request = new RestRequest(urlRequest, DataFormat.Json);
var response = client.Get(request);
Console.WriteLine(JsonSerializer.Deserialize<List<TestRestResponseTemplate>>(response.Content)[0].Entity.LegalName.Value);
TestRestResponseTemplate:
public class TestRestResponseTemplate
{
public Entity Entity { get; set; }
}
public class LegalName
{
[JsonPropertyName("#xml:lang")]
public string Language { get; set; }
[JsonPropertyName("$")]
public string Value { get; set; }
}
public class Entity
{
public LegalName LegalName { get; set; }
}
I have a problem with deserialization.
It's my json structure
{ "status": "ok",
"data": [
{
"issued": 1447358848072,
"volume": "5.52565454",
"currency": "pln",
"limit": "724.2500",
"type": "bid",
"id": "2015/11/12/13328345/4836"
},
{
"issued": 1447359927423,
"volume": "1.25465440",
"currency": "pln",
"limit": "1850.5000",
"type": "ask",
"id": "2015/11/12/13328342/8188"
}
]
}
It's my class in C# and functions:
public class oferta
{
public string issued { get; set; }
public string volume { get; set; }
public string currency { get; set; }
public string limit { get; set; }
public string type { get; set; }
public string id { get; set; }
}
public class tBitCurex_PRV_Offers
{
public string status { get; set; }
public List<oferta> data { get; set; }
}
public void GetPRV_Offers(tBitCurex_PRV_Offers B)
{
try
{
var RSP = "my json string";
B = JsonConvert.DeserializeObject<tBitCurex_PRV_Offers>(RSP);
if (B.data.Count > 0)
{
// in here COUNT = 2 and all works fine.
// and B.status = "ok"
// but when function is end i have a null
}
}
catch (Exception oException)
{
MessageBox.Show(oException.Message);
}
}
public void Pobierz_PRV_Offers()
{
try
{
var BitCurexOfers = new tBitCurex_PRV_Offers();
GetPRV_Offers(BitCurexOfers);
if (BitCurexOfers.status == "ok")
{
// do something with BitcurexOffers;
// I have a NULL if a use deserialize.
}
}
catch
{
sbInfo2.Text = "Error..xxxx";
}
finally
{
Application.DoEvents();
}
}
When in similar fuction i use
JObject oObject = JObject.Parse("json string");
B.status = (string)oObject["status"];
then all works fine inside and outside the function.
How should i do this properly with JsonConvert.DeserializeObject ???
Your problem is not with deserialization but with reference pointers
Instead of void, change the return type of the Function to BitCurex_PRV_Ofers and at the end of the function return B; and assign BitCurexOfers to the result of the function call instead of instantiating a new instance
Or just change the parameter to
ref BitCurex_PRV_Ofers B)
This is happening because you get a pointer to BitCurexOfers in B, then change that pointer with the result of deserialization
If you use JsonConvert.Poupulate(B); this will also work for you without any other changes
Your problem is that you're not altering B in the caller, just the method in which you're doing the deserialization. You can either change B to a ref parameter, or you can return it from the method instead.
Your sample code has some errors. try adding this attribute and it should work.
[Newtonsoft.Json.JsonObject(Title = "root")]
public class tBitCurex_PRV_Offers
I have this JSON file:
{
"result":
[
{
"desc" : "Ok",
"cod" : "1"
}
],
"data":
[
{
"cod" : "95B86DF6AE282E67B6B7437D09570847"
}
]
}
A method which deserializes it
protected void Deserialize()
{
string path = AppDomain.CurrentDomain.BaseDirectory + #"\token.json";
string file = System.IO.File.ReadAllText(path);
var deserializer = new JavaScriptSerializer();
var results = deserializer.Deserialize<data>(file);
}
public class result
{
public int cod { get; set; }
public string desc{ get; set; }
}
public class data
{
public string cod{ get; set; }
}
The problem is that it doesn't deserialize it, and creates empty Data object.
I'm missing something but I don't know what, hope someone will help me.
Your data model does not correspond to the JSON object, and the serializer is not able to deserialize it properly. Notice that inside that object you have arrays of objects, so the correct structure you need to deserialize that would be something like:
public class Token
{
public Result[] result { get; set; }
public Data[] data { get; set; }
}
And then you can do:
var res = JsonConvert.DeserializeObject<Token>(file);