Asp .Net Core Json deserialize to model - json

Returns Json format data to me from an api.
However, the type of the "FuelType" property inside the object may be different. For example, 1 time comes as follows:
{
...
fuelType: "gasoline"
...
}}
But then it can happen:
{
...
fuelType: ["gasoline", "any"]
...
}}
If I set the "FuelType" property type on my model to a string, in the second case, Json will give me an error when it arrives, because it can't convert from array to string. No, if I set the type to an array, then, conversely, if a string arrives, it will issue an error because it cannot convert from a string to an array.
In this case, what should I put the "FuelType" property type in my model so that it does not make an error when deserializing?

It all depends on you,what type of value you want to receive?string or List?
I tried with the codes:
public class SomeModel
{
public SomeModel()
{
fuelType = new List<string>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<string> fuelType { get; set; }
//you could move the codes to someservice
public List<string> someresult(string a)
{
var targetlist = new List<string>();
targetlist.Add(a);
return targetlist;
}
public List<string> someresult(List<string> a)
{
var targetlist = new List<string>();
targetlist.AddRange(a);
return targetlist;
}
}
[HttpPost]
public JsonResult SomeAction()
{
var somemodel = new SomeModel() { Id = 1, Name = "name" };
var somevalue = /*"a"*/new List<string>() { "a", "b", "c" };
var targetvalue = somemodel.someresult(somevalue);
somemodel.fuelType.AddRange(targetvalue);
return new JsonResult(somemodel);
}
Result:

try this
var fuelType = JsonConvert.DeserializeObject<MyClass>(json);
public class MyClass
{
[JsonProperty("fuelType")]
private JToken _fuelType;
[JsonIgnore]
public string[] fuelType
{
get {
if (_fuelType==null) return null;
return _fuelType is JArray ? _fuelType.ToObject<string[]>() : new string[] { (string)_fuelType }; }
set { _fuelType = JsonConvert.SerializeObject(value); }
}
}

Related

Insert JSON formatted string into JSON structure

I have a question about inserting a json formatted string into a json structure and having the final version be a combined JSON formatted string that can be serialized into a JSON structure. I am using the newtonsofts Json.NET
I have the following JSON structure:
public class ResponseJson
{
[JsonProperty(PropertyName = "header")]
public ResponseHeader responseHeader { get; set; }
[JsonProperty(PropertyName = "results")]
public string responseResults { get; set; }
}
public class ResponseHeader
{
[JsonProperty(PropertyName = "name")]
public string name { get; set; }
[JsonProperty(PropertyName = "version")]
public string version { get; set; }
}
In the code, I do the following:
ResponseJson responseJson = new ResponseJson();
responseJson.responseHeader = new ResponseHeader()
{
name = A_NAME,
version = A_VERSION
};
responseJson.responseResults = resultJson;
return JsonConvert.SerializeObject(responseJson, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
resultJson is a properly formatted JSON string (in this case, an array of objects, but could be anything JSON formatted). Right now, if i execute the code, I get the following (which is expected, since "results" is declared as a string):
{
"header":
{
"name":"abcd",
"version":"1.0"
},
"results":
"[{\"data\":{\"level\":\"100\"},\"code\":{\"value\":\"JBC\",\"type\":\"ev\"},\"time\":{\"start\":\"20\",\"end\":\"101\"}}]"
}
what I do need as an output is:
{
"header":
{
"name":"abcd",
"version":"1.0"
},
"results":
[
{
"data":
{
"level":"100"
},
"code":
{
"value":"JBC",
"type":"ev"
},
"time":
{
"start":"20",
"end":"101"
}
}
]
}
While you don't explain how you create your resultJson variable, it's implied from your code that you are double-serializing your results: you compute an array of "result" classes, serialize them to a JSON string, store the string in your ResponseJson class, and them serialize that in turn. The embedded JSON string then gets escaped as per the JSON standard, which is what you are seeing.
You need to avoid double-serializing your data, for instance by using the following data model:
public class ResponseJson<T>
{
[JsonProperty(PropertyName = "header")]
public ResponseHeader responseHeader { get; set; }
[JsonProperty(PropertyName = "results")]
public T responseResults { get; set; }
}
public static class ResponseJson
{
public static ResponseJson<T> Create<T>(T responseResults, ResponseHeader responseHeader)
{
return new ResponseJson<T> { responseResults = responseResults, responseHeader = responseHeader };
}
}
public class ResponseHeader
{
[JsonProperty(PropertyName = "name")]
public string name { get; set; }
[JsonProperty(PropertyName = "version")]
public string version { get; set; }
}
Then you would do:
var results = GetResults(); // Get your result data
var responseJson = ResponseJson.Create(results, new ResponseHeader()
{
name = A_NAME,
version = A_VERSION
});
return JsonConvert.SerializeObject(responseJson, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
If for whatever reason you must embed a previously serialized JSON string as JSON rather than as a string literal, you'll need to re-parse it back to a JToken:
string resultJson = GetResultJson(); // Get result json string.
var responseJson = ResponseJson.Create(JToken.Parse(resultJson), new ResponseHeader()
{
name = A_NAME,
version = A_VERSION
});
return JsonConvert.SerializeObject(responseJson, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
Json.NET will include the JToken in your outer JSON as nested JSON rather than as a string literal.

DeserializeObject Json

I have the following json data and i need to deserialize it. Btw i am using C# and i tried the following:
C#
// the data has been assigned to json variable
Result deserializedResult = JsonConvert.DeserializeObject<Result>(json);
Result class
private String _id = String.Empty;
private String[] _result = { };
private String _error = String.Empty;
public Result()
{
}
public String id
{
get { return _id; }
set { _id = value; }
}
public String[] result
{
get { return _result; }
set { _result = value; }
}
public String error
{
get { return _error; }
set { _error = value; }
}
JSon
{"id":1,"result":
[
{"id":12345,
"list_id":54321,
"is_test":false,
"type":"manual",
"creator_name":"Test Solutions"
},
{"id":54321,
"list_id":12345,
"is_test":false,
"type":"manual",
"creator_name":"Test Solutions"
}
],
"error":null}
ERROR
Additional information: Error reading string. Unexpected token: StartObject. Path 'result[0]', line 1, position 19.
I was missing something so obvious. Instead of another object e.g. Result class i was expecting an array. I fixed the issue editing Result property chaning
public String[] result { get; set; }
to
public List<Result> result { get; set; }
Thank you and sorry for bothering. Have a nice day

Deserialise dynamic json types

I want to deserialize json which returns different data for different parameters.
Mostly I get:
{"posts": [{ "id" : 1, "name":"post1" },{ "id" : 1, "name":"post1" }]}
But sometimes the data returned is
{"posts": false}
I want to deserialize this as the following class
public class GetReaderResponse
{
public IEnumerable<ReaderPost> posts {get; set;}
}
public class ReaderPost
{
public int id {get; set;}
public string name{get; set;}
}
I am using C#,json.net but not able to do this correctly.
Newtonsoft.Json.JsonConvert.DeserializeObject<GetReaderResponse>(dataString);
You could build a custom converter, but an easy way to handle this would be to write an error handler that detects errors with the posts property:
var settings = new JsonSerializerSettings();
settings.Error += (sender, args) =>
{
if (string.Equals("posts", args.ErrorContext.Path, StringComparison.OrdinalIgnoreCase))
{
var currentObject = args.CurrentObject as GetReaderResponse;
currentObject.posts = Enumerable.Empty<ReaderPost>();
args.ErrorContext.Handled = true;
}
};
GetReaderResponse resp =
JsonConvert.DeserializeObject<GetReaderResponse>(json, settings);
This sets posts to Enumerable.Empty<ReaderPost>. This is still a little unsatisfying because if any error occurs, the property will be set. You could build a full custom converter to do this as a more complete solution.
Here's a converter that will take care of this:
public class PostsConverter : JsonConverter
{
public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
JToken val = JValue.ReadFrom(reader);
object result = null;
if (val.Type == JTokenType.Array)
{
result = val.ToObject<IEnumerable<ReaderPost>>();
}
else if (val.Type == JTokenType.Boolean)
{
result = Enumerable.Empty<ReaderPost>();
}
return result;
}
public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override bool CanConvert (Type type)
{
return typeof(IEnumerable<ReaderPost>).IsAssignableFrom(type);
}
public override bool CanRead
{
get { return true; }
}
}
Usage:
var settings = new JsonSerializerSettings();
settings.Converters = new [] { new PostsConverter() };
GetReaderResponse resp =
JsonConvert.DeserializeObject<GetReaderResponse>(json, settings);
Example: https://dotnetfiddle.net/i9CXwp
By using JSON.NETs built in LINQ to JSON, you can try someting like this:
JObject jObject = JObject.Parse(json);
GetReaderResponse response = new GetReaderResponse();
if (jObject["posts"] is JArray)
response = jObject.ToObject<GetReaderResponse>();
// Do something with the response object.
where json variable is the json string you need to deserialize.
try this:
public class GetReaderResponse
{
public bool posts { get; set; }
public ReaderPost[] post { get; set; }
}
After reading #Ilija's comment I think I might have found a answer. I did not want not use string literals so I modified my class GetReaderResponse to look like below:
public class GetReaderResponse
{
public dynamic posts {get; set;}
public IEnumerable<ReaderPost> Posts
{
get
{
if (posts is bool )
return new ReaderPost[0];
return posts.ToObject<IEnumerable<ReaderPost>>();
}
}
}
Does this sound fine or does it look messy?

BSON Object Being Partially Deserialized

I'm trying to deserialize a BSON HTTP Response Message from a Web API call into a custom type.
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:1234");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/bson"));
HttpResponseMessage result;
result = await client.GetAsync("/endpoint/");
MediaTypeFormatter[] formatters = new MediaTypeFormatter[] {
new BsonMediaTypeFormatter()
};
if (result.IsSuccessStatusCode)
{
try
{
RootObject res = await result.Content.ReadAsAsync<RootObject>(formatters);
}
catch (Exception e)
{
}
}
I know the Web API is returning BSON, I checked through Fiddler and the above code actually does deserialize most things correctly in the RootObject. It appears that all of the derived classes are not being deserialized and are just being input into the object as null. Here is an example of a derived class that is not being deserialized.
RootObject.Events.Teams.Linescores
RootObject
[DataContract(Namespace = "", Name = "RootObject")]
[Serializable]
public class RootObject: infoBase
{
[DataMember(EmitDefaultValue = false, Order = 30)]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, Order = 30)]
public IEnumerable<eventInfo> events { get; set; }
public RootObject() { }
}
Events Object
[DataContract(Namespace = "", Name = "event")]
[Serializable]
[KnownType(typeof(subEventTeam))]
public class eventInfo : infoBase
{
[DataMember(EmitDefaultValue = false, Order = 170)]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, Order = 170)]
public List<eventTeamBase> teams { get; set; }
public eventInfo() { }
}
Teams Base and Specific Team Type
[DataContract(Namespace = "", Name = "team")]
[Serializable]
[KnownType(typeof(bbLinescoreInfo))]
public class eventTeamBase : infoBase {
[DataMember(Order = 20)]
[JsonProperty(Order = 20)]
public string location { get; set; }
[DataMember(Order = 30, EmitDefaultValue = false)]
[JsonProperty(Order = 30, NullValueHandling = NullValueHandling.Ignore)]
public string nickname { get; set; }
[DataMember(EmitDefaultValue = false, Name = "linescores", Order = 130)]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, Order = 130)]
public IEnumerable<linescoreBase> linescores { get; set; }
public eventTeamBase() { }
}
[DataContract(Namespace = "", Name = "team")]
[Serializable]
public class subEventTeam : eventTeamBase
{
public subEventTeam () { }
}
Linescore Base and Specific Object
[DataContract(Name = "linescores", Namespace = "")]
[Serializable]
[KnownType(typeof(subLinescoreInfo))]
public class linescoreBase : infoBase
{
public bool isProcessing = false;
public int teamId { get; set; }
public linescoreBase() { }
}
[DataContract(Name = "linescores", Namespace = "")]
[Serializable] public class subLinescoreInfo : linescoreBase
{
[DataMember]
public int inning { get; set; }
[DataMember]
public int? score { get; set; }
public subLinescoreInfo() { };
}
Here is the deserialized (and then re-serialized) part of the response that isn't working output into JSON.
{
"status":"OK",
"recordCount":1,
"RootObject":[
{
"events":[
{
"teams":[
{
"location":"Tallahassee",
"nickname":"Razors",
"linescores":[
{},{},{},{},{},{},{},{}]
}
}
}
}
So as you can see, it is filling in some information correctly (There is a lot more, I've cut down significantly just to illustrate the problem). But the linescores are returning null. As mentioned, the data is returning correctly and it is not null.
I feel like I'm doing something wrong with the known types and I've tried numerous combinations of putting them in different places and the results don't change. Any help would greatly appreciated.
After much searching and trying wrong things, I found a similar solution in another thread.
JSON Solution
I solved this by doing pretty much that exact same thing but with BSON instead of JSON.
This is the code that I needed to add in the global config file of the Web API
BsonMediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
bsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
bsonFormatter.AddQueryStringMapping("accept", "bson", "application/bson");
GlobalConfiguration.Configuration.Formatters.Add(bsonFormatter);
And this code went into the client.
BsonMediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
bsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
MediaTypeFormatter[] formatters = new MediaTypeFormatter[] {
bsonFormatter
};
Everything else remained the same and was deserialized without incident.

Service Stack POST-Request Body-Format / Transformation

iam using a RequestClass with the Route anotation to call a Json-Client POST method.
Now, while the paramters are structured like this
public class GetTicketRequest: IReturn<JsonObject>
{
public string CartId {
get;
set;
}
public string PriceId {
get;
set;
}
}
The BackendAPI needs them to be nesten in "data" in the json request, so more like
{
"data":[
{"cartid":123,
"priceId":11}]
}
Is there any way to transfrom the request object for the body before calling
JsonServiceClient _restClient = new JsonServiceClient(baseUrl);
JsonObject oneResponse = _restClient.Post(options);
This solution is useful where many DTOs require to be wrapped & converted, and is highly reusable, with no changes to your existing DTOs.
You can convert the requests of the JsonServiceClient by overriding the methods that handle preparing the requests for sending. Which means implementing your own extended JsonServiceClient as given below.
If you want to do this for all verbs then you override it's Send<TResponse> methods (otherwise, if it's just for POST then uncomment the commented out code, and remove the Send methods).
public class MyJsonServiceClient : JsonServiceClient
{
public Dictionary<Type, Func<object, object>> DtoConverters = new Dictionary<Type, Func<object, object>>();
public MyJsonServiceClient() {}
public MyJsonServiceClient(string baseUri) : base(baseUri) {}
public MyJsonServiceClient(string syncReplyBaseUri, string asyncOneWayBaseUri) : base(syncReplyBaseUri, asyncOneWayBaseUri) {}
public override TResponse Send<TResponse>(object request)
{
return base.Send<TResponse>(ConvertRequest(request));
}
public override TResponse Send<TResponse>(string httpMethod, string relativeOrAbsoluteUrl, object request)
{
return base.Send<TResponse>(httpMethod, relativeOrAbsoluteUrl, ConvertRequest(request));
}
/*
public override TResponse Post<TResponse>(string relativeOrAbsoluteUrl, object requestDto)
{
return base.Post(relativeOrAbsoluteUrl, ConvertRequest(requestDto));
}
*/
object ConvertRequest(object request)
{
Type dtoType = request.GetType();
return (DtoConverters.ContainsKey(dtoType)) ? DtoConverters[dtoType](request) : request;
}
}
Usage:
So given this DTO:
[Route("/test", "POST")]
public class TicketRequest : IReturnVoid
{
public string CartId { get; set; }
public string PriceId { get; set; }
}
You simply add the converter:
var client = new MyJsonServiceClient("http://localhost:9000");
// Simple converter for TicketRequest
client.DtoConverters.Add(typeof(TicketRequest), dto => {
var d = (TicketRequest)dto;
return new {
data = new {
CartId = d.CartId.ToInt(),
PriceId = d.PriceId.ToInt()
}
};
});
client.Post(new TicketRequest { CartId = "123", PriceId = "456" });
i solved this issue using a typed data property
public class GetTicketRequest: IReturn<JsonObject>
{
public class TicketCreateData
{
public int priceId {
get;
set;
}
}
public string CartId {
get;
set;
}
public string PriceId {
get;
set;
}
public List<TicketCreateData> data {
get {
var list = new List<TicketCreateData>();
list.Add(new TicketCreateData {
priceId = this.PriceId.ToInt()
});
return list;
}
set {
data = value;
}
}
}
To notes on this:
if neede, use DataContract/DataMember(Name="") to rename fields or only do partial serializing
Do never use structs for, like in this case, the data class - they are not serializeable at all
in my spefici case data even needs to be an array, thats why i used the list