I asked earlier today, but still struggling with this. I want to create an object Person
where the properties must be populated from an RPC call when instantiated.
I get this error:
Newtonsoft.Json.JsonReaderException
HResult=0x80131500
Message=Could not convert string to integer: getperson. Path 'id', line 1, position 103.
Source=Newtonsoft.Json
My example is below, I tried changing Id
property to a string
in the Person
object but then the none of the properties don't get set (null or zero).
I've also heard it mentioned that I should use a static factory method. What's that and how would it look in this example? Many thanks.
using Newtonsoft.Json;
class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Version { get; set; }
public Person(int Id)
{
// here would be an RPC call to get the FirstName,LastName,Version. result is JSON
string response = "{\"result\": {\"version\":1,\"Id\": 1, \"FirstName\": \"Bob\", \"LastName\": \"Jones\"},\"error\":null,\"id\":\"getperson\"}";
JsonConvert.PopulateObject(response, this);
}
}
class Program
{
static void Main(string[] args)
{
var p = new Person(1);
var f = p.FirstName;
// p.FirstName should be Bob but is null
}
}
EDIT: In my actual code I have another class like this, can I make use of that and somehow derserialize with RPCResponse<Person>
?
public class RPCResponse<T>
{
public T result { get; set; }
public string error { get; set; }
public string id { get; set; }
}
Based on the current example, the constructor is taking on too many responsibilities.
You mentioned using a factory method. Go with that.
class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Version { get; set; }
public Person() {
}
public static Person Get(int id) {
// here would be an RPC call to get the FirstName,LastName,Version. result is JSON
string json = "{\"result\": {\"version\":1,\"Id\": 1, \"FirstName\": \"Bob\", \"LastName\": \"Jones\"},\"error\":null,\"id\":\"getperson\"}";
dynamic jObject = JObject.Parse(json);
var person = jObject.result.ToObject<Person>();
return person;
}
}
The static Get(int Id)
factory method would be responsible for parsing the response from the service. That could have also been refactored out into a service, but the main point here is that the constructor should be kept as simple as needed.
public class Program
{
public static void Main(string[] args)
{
var p = Person.Get(1);
var f = p.FirstName;
var l = p.LastName;
Console.WriteLine("FirstName: "+ f);
Console.WriteLine("LastName: "+ l);
}
}
//Produces:
// FirstName: Bob
// LastName: Jones
the class you are trying to populate is in the inner properties of your json string. try to create a class like this
public class Response{
public Response(
string response = "{\"result\": {\"version\":1,\"Id\": 1, \"FirstName\": \"Bob\", \"LastName\": \"Jones\"},\"error\":null,\"id\":\"getperson\"}";
JsonConvert.PopulateObject(response, this);
){}
public Person result{get;set;}
}
public class Person{
public Person(){}
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Version { get; set; }
}
this is a non tested code, but i hope you will get the idea.
I have solved it like this, but I don't like my code. How could it be improved? It seems very verbose.
using Newtonsoft.Json;
class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Version { get; set; }
public Person(int Id)
{
// here would be an RPC call to get the FirstName,LastName,Version. result is JSON
string response = "{\"result\": {\"version\":1,\"Id\": 1, \"FirstName\": \"Bob\", \"LastName\": \"Jones\"},\"error\":null,\"id\":\"getperson\"}";
var o = JsonConvert.DeserializeObject<RPCResponse<PersonDetails>>(response).result;
this.Id = Id;
FirstName = o.FirstName;
LastName = o.LastName;
Version = o.Version;
}
private class PersonDetails
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Version { get; set; }
}
}
public class RPCResponse<T>
{
public T result { get; set; }
public string error { get; set; }
public string id { get; set; }
}
class Program
{
static void Main(string[] args)
{
var p = new Person(1);
var f = p.FirstName;
// p.FirstName should be Bob but is null
}
}
Not sure what the problem is with your code but this code maps the JSON directly into a class of PersonDetails
and it's properties correctly:
using System;
using Newtonsoft.Json;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
string json = "{\"result\": {\"version\":1,\"Id\": 1, \"FirstName\": \"Bob\", \"LastName\": \"Jones\"},\"error\":null,\"id\":\"getperson\"}";
var personDetails = new PersonDetails(json);
Console.WriteLine(personDetails.ToString());
Console.ReadLine();
}
}
public class RPCResponse<T>
{
public T Result { get; set; }
public string Error { get; set; }
public string Id { get; set; }
}
public class PersonDetails
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public int Version { get; set; }
public PersonDetails() {}
public PersonDetails(string json)
{
var result = JsonConvert.DeserializeObject<RPCResponse<PersonDetails>>(json).Result;
foreach (var prop in typeof(PersonDetails).GetProperties())
{
var value = prop.GetValue(result);
prop.SetValue(this, value);
}
}
public override string ToString()
{
var str = "Id: " + this.Id + Environment.NewLine;
str += "FirstName: " + this.FirstName + Environment.NewLine;
str += "LastName: " + this.LastName + Environment.NewLine;
str += "Version: " + this.Version + Environment.NewLine;
return str;
}
}
}
User contributions licensed under CC BY-SA 3.0