I m having Long property but in result I am expecting to get value as string by JasonCnvert
Property:
[JsonConverter(typeof(JsonNumberToStringConverter))]
public long Id { get; set; }
this JsonNumberToStringConverter I am using to Serialize to convert into string
as below :
Json converter Class:
public class JsonNumberToStringConverter : JsonConverter<long>
{
public override long Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return long.Parse(reader.GetString());
}
public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
Passing Value of ID as : long 123
Expecting the IS : as string "123"
Related
I am attempting to deserialize a json object using JsonConvert - the data is coming from a 3rd party API
return JsonConvert.DeserializeObject<UserRegistration>(content,
JsonSnakeCaseNameStrategySettings.Settings());
The UserRegistration class:
public class UserRegistration
{
public UserRegistrationData UserRegistration { get; set; }
}
public class UserRegistrationData
{
public int UserId { get; set; }
public string Email { get; set; }
public UserRegistrationCustomFields CustomFields { get; set; }
}
public class UserRegistrationCustomFields
{
private bool emailDelivery;
public string DeliveryTime { get; set; }
public bool EmailDelivery {
get
{
return emailDelivery;
}
set
{
emailDelivery = value.ToString() == "1";
}
}
public bool SmsDelivery { get; set; }
public string PhoneNumber { get; set; }
}
I've tried several ways, this is my current iteration. The goal is to have "EmailDelivery" be a boolean, the value from the API will always be "1" or "0". This throws a JsonReaderException: Could not convert string to boolean: 0. Path 'user_registration.custom_fields.email_delivery', line 1, position 208.
You need custom JsonConverter to modify the deserialize principle.
Change your model like below:
public class UserRegistrationCustomFields
{
public string DeliveryTime { get; set; }
public bool EmailDelivery{get;set;}
public bool SmsDelivery { get; set; }
public string PhoneNumber { get; set; }
}
Custom a JsonConverter:
public class JsonBooleanConverter : JsonConverter
{
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var value = reader.Value.ToString().ToLower().Trim();
switch (value)
{
case "1": return true;
}
return false;
}
public override bool CanConvert(Type objectType)
{
if (objectType == typeof(Boolean))
{
return true;
}
return false;
}
}
How to use:
JsonConvert.DeserializeObject<UserRegistration>(json, new JsonBooleanConverter());
I created Boolean converter expecting it would be used automatically on the property IsComplete, but get an error in cURL. What am I doing wrong?
Error
$ curl -k -X PUT -H "Content-Type: application/json" -d "{\"name\": \"momo\", \"isComplete\":\"true\"}" https://localhost:44358/api/TodoItems/PutItem?id=2
{"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"|f2fadf22-471bc26be11d1bad.","errors":{"$.isComplete":["The JSON value could not be converted to System.Boolean. Path: $.isComplete | LineNumber: 0 | BytePositionInLine: 36."]}}
Converter
namespace System.Text.Json.Serialization
{
public class BooleanConverter : JsonConverter<bool>
{
public override bool Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) =>
bool.Parse(reader.GetString());
public override void Write(
Utf8JsonWriter writer,
bool b,
JsonSerializerOptions options) =>
writer.WriteStringValue(b.ToString());
}
}
Attributes
namespace TodoApi.Models
{
public class TodoItem
{
public long Id { get; set; }
public string Name { get; set; }
public bool IsComplete { get; set; }
}
}
I created Boolean converter expecting it would be used automatically on the property IsComplete
You can try to register your custom converter on IsComplete property of your TodoItem class.
[JsonConverter(typeof(BooleanConverter))]
public bool IsComplete { get; set; }
For more information about "register a custom converter ", please check:
https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to#register-a-custom-converter
My ASP.NET Core 2.1 API exposes the following input DTO in a POST endpoint:
[Route("test")]
[ApiController]
public class TestController : ControllerBase
{
[HttpPost("endpoint")]
public async Task<IActionResult> Post([Required]MyDTO dto)
{
// Some code
}
}
public class MyDTO
{
[JsonProperty("foo")]
[Required]
public Foo Foo { get; set; }
}
The Foo class is defined as follow:
[JsonConverter(typeof(FooConverter))]
public abstract class Foo
{
[JsonProperty("foo_type")]
[Required]
public string FooType { get; set; }
}
The FooConverter class is able to instantiate the right implementation based on the foo_type field:
public class FooConverter : JsonConverter<Foo>
{
public override bool CanRead => true;
public override bool CanWrite => false;
public override Foo ReadJson(JsonReader reader, Type objectType, Foo existingValue, bool hasExistingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
Foo target = this.CreateFoo(jObject);
serializer.Populate(jObject.CreateReader(), target);
return target;
}
public override void WriteJson(JsonWriter writer, Foo value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
private Foo CreateFoo(JObject jObject)
{
string fooType = jObject.Value<string>("foo_type");
switch (fooType)
{
case "foo1":
return new Foo1();
case "foo2":
return new Foo2();
default:
throw new JsonSerializationException($"Invalid 'foo_type' '{fooType}'");
}
}
}
Here is one of the implementations of the Foo abstract class:
public class Foo1 : Foo
{
[JsonProperty("bar")]
[Required]
public string Bar { get; set; }
}
My problem is that the [Required] attribute on Foo1.Bar is ignored by ASP.NET validation, even though the [Required] attribute on Foo.FooType works as expected. How can I automatically validate the fields defined in the implementation types so that it works the same as with other fields?
Replace:
var jObject = JObject.Load(reader);
with:
JToken jObject = JToken.ReadFrom(reader);
The following code throws error at statement :
Result res = (Result)stdserialize.ReadObject(ms);
And the error is : There was an error deserializing the object of type TrackLocation.MainPage+Result. End element 'types' from namespace '' expected. Found element 'item' from namespace ''.
HttpClient gClientRequest = new HttpClient();
System.Uri gURI = new Uri("http://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&sensor=true");
HttpResponseMessage gResponse = await gClientRequest.GetAsync(gURI);
string strStream = await gResponse.Content.ReadAsStringAsync();
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(strStream));
DataContractJsonSerializer stdserialize = new DataContractJsonSerializer(typeof(Result));
Result res = (Result)stdserialize.ReadObject(ms);
//################################################################################################
[DataContract]
public class Address
{
[DataMember(Name = "long_name")]
public string address1;
[DataMember(Name = "short_name")]
public string shortaddress;
[DataMember(Name = "formatted_address")]
public string formattedtaddress;
[DataMember(Name = "lat")]
public string latitude;
[DataMember(Name = "long")]
public string latitude;
}
//###############################################################################################
[DataContract]
public class Result
{
[DataMember(Name = "results")]
public Address[] Results { get; set; }
[DataMember(Name = "status")]
public string Status { get; set; }
}
[DataContract]
public class Address
{
[DataMember(Name = "formatted_address")]
public string FormattedAddress;
[DataMember(Name = "address_components")]
public AddressComponent[] AddressComponents;
}
[DataContract]
public class AddressComponent
{
[DataMember(Name = "long_name")]
public string LongName;
[DataMember(Name = "short_name")]
public string ShortName;
[DataMember(Name = "types")]
public string Types;
}
any idea how to fix this issue.Any help would be greatly appreciated.
I just converted the JSON to XMl and found the types to be repeated(check screen shot below) but in your datacontract its
[DataMember(Name = "types")]
public string Types;
Just put this as
[DataMember(Name = "types")]
public string[] Types;
and it should work
Take a closer look at the JSON, your Type field of the AddressComponent should be string[] not string.
{
"results" : [
{
"address_components" : [
{
"long_name" : "285",
"short_name" : "285",
"types" : [ "street_number" ]
},
Also, you seem to have two Address classes and a result (lowercase) and Result (uppercase) class; I'm assuming those were cut-and-paste issues since they don't seem to match the JSON that's returned.
I'm using JSON.Net to try and deserialize some survey responses from SurveyGizmo.
Here's a snapshot of the data I'm reading in:
{"result_ok":true,
"total_count":"44",
"page":1,
"total_pages":1,
"results_per_page":50,
"data":[
{"id":"1",
"contact_id":"",
"status":"Complete",
"is_test_data":"0",
"datesubmitted":"2011-11-13 22:26:53",
"[question(59)]":"11\/12\/2011",
"[question(60)]":"06:15 pm",
"[question(62)]":"72",
"[question(63)]":"One",
"[question(69), option(10196)]":"10",
I've setup a class as far as datesubmitted but I'm not sure how to setup the class to deserialize the questions given that the amount of questions will change? I also need to capture the option if it's present.
I'm using this code to use the JSON.NET Deserialize function:
Dim responses As Responses = JsonConvert.DeserializeObject(Of Responses)(fcontents)
Classes:
Public Class Responses
Public Property result_OK As Boolean
Public Property total_count As Integer
Public Property page As Integer
Public Property total_pages As Integer
Public Property results_per_page As Integer
Public Overridable Property data As List(Of surveyresponse)
End Class
Public Class SurveyResponse
Public Property id As Integer
Public Property status As String
Public Property datesubmitted As Date
End Class
This trick to support totally crazy mappings is to use JsonConverter and completely replace the parsing for that object, (I apologize for the C#, but I'm no good at VB syntax):
class Program
{
static void Main(string[] args)
{
var result = JsonConvert.DeserializeObject<Responses>(TestData);
}
const string TestData = #"{""result_ok"":true,
""total_count"":""44"",
""page"":1,
""total_pages"":1,
""results_per_page"":50,
""data"":[
{""id"":""1"",
""contact_id"":"""",
""status"":""Complete"",
""is_test_data"":""0"",
""datesubmitted"":""2011-11-13 22:26:53"",
""[question(59)]"":""11\/12\/2011"",
""[question(60)]"":""06:15 pm"",
""[question(62)]"":""72"",
""[question(63)]"":""One"",
""[question(69), option(10196)]"":""10"",
}]}";
}
[JsonObject]
class Responses
{
public bool result_ok { get; set; }
public string total_count { get; set; }
public int page { get; set; }
public int total_pages { get; set; }
public int results_per_page { get; set; }
public SurveyResponse[] Data { get; set; }
}
[JsonObject]
// Here is the magic: When you see this type, use this class to read it.
// If you want, you can also define the JsonConverter by adding it to
// a JsonSerializer, and parsing with that.
[JsonConverter(typeof(DataItemConverter))]
class SurveyResponse
{
public string id { get; set; }
public string contact_id { get; set; }
public string status { get; set; }
public string is_test_data { get; set; }
public DateTime datesubmitted { get; set; }
public Dictionary<int, string> questions { get; set; }
}
class DataItemConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(SurveyResponse);
}
public override bool CanRead
{
get { return true; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var value = (SurveyResponse)existingValue;
if (value == null)
{
value = new SurveyResponse();
value.questions = new Dictionary<int, string>()
}
// Skip opening {
reader.Read();
while (reader.TokenType == JsonToken.PropertyName)
{
var name = reader.Value.ToString();
reader.Read();
// Here is where you do your magic
if (name.StartsWith("[question("))
{
int index = int.Parse(name.Substring(10, name.IndexOf(')') - 10));
value.questions[index] = serializer.Deserialize<string>(reader);
}
else
{
var property = typeof(SurveyResponse).GetProperty(name);
property.SetValue(value, serializer.Deserialize(reader, property.PropertyType), null);
}
// Skip the , or } if we are at the end
reader.Read();
}
return value;
}
public override bool CanWrite
{
get { return false; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Now obviously there's a lot more you would want to do to get this really robust, but this gives you the basics of how to do it. There are more lightweight alternatives if you simply need to change property names (either JsonPropertyAttribute or overriding DefaultContractResolver.ResolvePropertyName(), but this gives you full control.