Null encountered when deserializing JSON - c#

I have json message
{"code":200,
"description":{
"15":{"id":"15","name":"US"},
"25":{"id":"25","name":"Canada"},
"msg":"Ok"}}
I am trying to deserialize it with such classes
public class NewCountry
{
public string id { get; set; }
public string name { get; set; }
}
public class NewCountryDescription
{
public List<NewCountry> Countries{ get; set; }
public string msg { get; set; }
}
public class RootObject
{
public int code { get; set; }
public NewCountryDescription description { get; set; }
}
var ListOfCountries = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(res);
But I am always getting null at NewCountry what i am doing wrong?

If you remove msg from your json or move it somewhere else (not in the descrition), it will work:
{"code":200,
"description":{
"15":{"id":"15","name":"US"},
"25":{"id":"25","name":"Canada"}
}}
public class RootObject
{
public int code { get; set; }
public Dictionary<string, NewCountry> description { get; set; }
}
public class NewCountry
{
public string id { get; set; }
public string name { get; set; }
}

You doesn't have parsable collection, so you can use JObject and dynamic or key/value access.
var result = JObject.Parse(res);
var description = (result["description"] as JObject);
if (description != null)
{
var root = new RootObject
{
code = (int)result["code"],
description = new NewCountryDescription
{
msg = description["msg"].ToString(),
Countries = (from prop in description.Properties()
where prop.Name != "msg"
select new NewCountry
{
id = prop.Value["id"].ToString(),
name = prop.Value["name"].ToString()
}).ToList()
}
};
Console.Write(root);
}

Related

How to deserialize an object and pass it to a response model

i have a json string that i deserialize as follows.
using (var streamReader = new StreamReader(httpResponsePayment.GetResponseStream()))
{
var data = streamReader.ReadToEnd();
result = JsonConvert.DeserializeObject<TestResponse>(data);
}
the data object looks as follows
"{\"responseCode\":2402,\"responseMessage\":\"hello\",\"amount\":0,\"acquirer\":{\"account\":{\"Number\":\"4587-54884-784848\"},\"Tag\":\"TF1234569775548494\"}}"
i pass this object to my TestResponse class
public class TestResponse
{
public string responseCode { get; set; }
public string responseMessage { get; set; }
public int amount { get; set; }
}
i can pass the above 3 objects correctly. I dont know how to pass the acquirer object to the TestResponse
acquirer = new
{
account= new
{
Number="4587-54884-784848"
},
Tag= "TF1234569775548494"
}
i tried doing something like this
public class TestResponse
{
public string responseCode { get; set; }
public string responseMessage { get; set; }
public int amount { get; set; }
List<Acquirers> acquirer =new List<Acquirers>();
}
public class Acquirers
{
public string Tag { get; set; }
}
also tried
public class TestResponse
{
public string responseCode { get; set; }
public string responseMessage { get; set; }
public int amount { get; set; }
public string Number {get;set;} //returns null
public string Tag {get;set;} // returns null
}
can someone please guide me
class Program
{
static void Main(string[] args)
{
var json = "{\"responseCode\":2402,\"responseMessage\":\"hello\",\"amount\":0,\"acquirer\":{\"account\":{\"Number\":\"4587-54884-784848\"},\"Tag\":\"TF1234569775548494\"}}";
var result = JsonConvert.DeserializeObject<Root>(json);
}
}
public class Account
{
public string Number { get; set; }
}
public class Acquirer
{
public Account account { get; set; }
public string Tag { get; set; }
}
public class Root
{
public int responseCode { get; set; }
public string responseMessage { get; set; }
public int amount { get; set; }
public Acquirer acquirer { get; set; }
}
you can using this link = https://json2csharp.com/
for convert model

Map JSON to C# Class when attribute names have spaces and reserved words

I am consuming a REST API service. In the service response JSON, there are attribute names that include spaces and reserved words. I'm trying to map it to a C# class, but I can't assign attribute names that are the same as the field names.
Currently, the mapping only succeeds when the JSON attribute and C# class name of a field matches exactly, otherwise the value comes in as null.
Below is the JSON returned from the service:
{
"value": [ {
"accountNo": "JKBXXXXXXXXXVNX1",
"mainSalesPerson": "XXXXX",
"accountName": "XXXXXX",
"ledgerBalance": "-2,298.70",
"T+3": "0.00",
"T+4": "0.00",
"T+5 and Above": "2,298.70",
"riskRatedPortfolioValue": "109,057.50",
"exposure": "106,758.80",
"costToFirm": "",
"incomeToFirm": "14.59",
"costToIncome(%)": "",
"exposure(%)": "2.11",
"O/S Balance": "-2,298.70"
}],
"success": true
}
I have used the following mapping class:
public class CountObject
{
public string value { get; set; }
public string success { get; set; }
}
public class RiskManagementQueryValueObject
{
public string accountNo { get; set; }
public string mainSalesPerson { get; set; }
public string accountName { get; set; }
public string ledgerBalance { get; set; }
[SerializeAs(Name = "T+3")]
public string T3 { get; set; }
[SerializeAs(Name = "T+4")]
public string T4 { get; set; }
[SerializeAs(Name = "T+5 and Above")]
public string T5_and_Above { get; set; }
public string riskRatedPortfolioValue { get; set; }
public string exposure { get; set; }
public string costToFirm { get; set; }
public string incomeToFirm { get; set; }
[SerializeAs(Name = "costToIncome(%)")]
public string costToIncome { get; set; }
[SerializeAs(Name = "exposure(%)")]
public string exposure_per { get; set; }
[SerializeAs(Name = "O/S Balance")]
public string OS_Balance { get; set; }
}
public class RiskManagementQueryHeadertObject
{
public List<RiskManagementQueryValueObject> value { get; set; }
public bool success { get; set; }
}
And this how I talk to the service:
public List<RiskManagementQueryValueObject> getOverdues()
{
List<RiskManagementQueryValueObject> overdues = new List<RiskManagementQueryValueObject>();
var count = 0.0;
try
{
var restProxy = new RESTProxy();
var request = restProxy.initRestRequest("/cam/riskmanagement/1/query/count", Method.POST, new { requestCriteriaMap = new { currency = "LKR" } });
CountObject data = restProxy.Execute<CountObject>(request);
if (data.success.ToString().ToLower() != "true")
return null;
//get the page count
var pageCount = Math.Truncate(count / 300) + 1;
for (int j = 0; j < pageCount; j++)
{
var request2 = restProxy.initRestRequest(string.Format("/cam/riskmanagement/1/query/{0}", (j + 1).ToString()), Method.POST, new { requestCriteriaMap = new { currency = "LKR" } });
RiskManagementQueryHeadertObject data2 = restProxy.Execute<RiskManagementQueryHeadertObject>(request2);
overdues.AddRange(data2.value);
}
}
catch (Exception)
{
overdues = null;
}
return overdues;
}
public class RESTProxy
{
string DEFAULT_HOST = "http://xxx.xxx.xxx.xxx:xxx/";
string DEFAULT_MODULE = "xxx-rest";
string DEFAULT_USER = "xxx:xxx:xxx";
string DEFAULT_PASS = "xxx";
public T Execute<T>(RestRequest request) where T : new()
{
var client = new RestClient(string.Concat(DEFAULT_HOST, DEFAULT_MODULE))
{
Authenticator = new DigestAuthenticator(DEFAULT_USER, DEFAULT_PASS, DEFAULT_HOST)
};
var response = client.Execute<T>(request);
if (response.ErrorException != null)
{
throw response.ErrorException;
}
return response.Data;
}
public RestRequest initRestRequest(string pRestResourceName, Method pRestServiceVerb, object pRestRequestBody)
{
var request = new RestRequest(pRestResourceName, pRestServiceVerb);
request.RequestFormat = DataFormat.Json;
if (pRestRequestBody != null)
{
request.AddBody(pRestRequestBody);
}
return request;
}
}
How can I resolve this and serialize all the fields into my class definition?
Using the JsonProperty attribute worked for me:
Example:
This C# class:
public class Product
{
[JsonProperty(PropertyName = "Name/ + 1")]
public string Name { get; set; }
}
maps to the following javascript object:
var input = {"Name/ + 1": "PostName"};
I solved the issue. I added [DeserializeAs(Name ="")] instead of [SerializeAs(Name ="")]. I just did this in my C# Map class:
public class RiskManagementQueryValueObject
{
public string accountNo { get; set; }
public string mainSalesPerson { get; set; }
public string accountName { get; set; }
public string ledgerBalance { get; set; }
[DeserializeAs(Name = "T+3")]
public string T3 { get; set; }
[DeserializeAs(Name = "T+4")]
public string T4 { get; set; }
[DeserializeAs(Name = "T+5 and Above")]
public string T5_and_Above { get; set; }
public string riskRatedPortfolioValue { get; set; }
public string exposure { get; set; }
public string costToFirm { get; set; }
public string incomeToFirm { get; set; }
[DeserializeAs(Name = "costToIncome(%)")]
public string costToIncome { get; set; }
[DeserializeAs(Name = "exposure(%)")]
public string exposure_per { get; set; }
[DeserializeAs(Name = "O/S Balance")]
public string OS_Balance { get; set; }
}

How to get Data into the model via elasticsearch get

public class News
{
public string author { get; set; }
public string title { get; set; }
public DateTime timestamp{ get; set; }
public string content { get; set; }
public bool forstudents { get; set; }
public List<link> links { get; set; }
public List<imgs> imgs { get; set; }
}
public class link
{
public string name { get; set; }
public string value { get; set; }
}
public class imgs
{
public string name { get; set; }
public string value { get; set; }
}
This is my Model Description then i connect to the Server
var _esServer = new ElasticSearchServer("http://localhost:9200");
var _esIndex = _esServer.GetIndex("campusoffice");
var news = _esIndex.Get<News>("/news", int.MaxValue);
and it should get everything right but
he doesnt map the name and the value in the list elements
{
"author": "soulseak",
"title": "Awsome",
"timestamp": 20130201,
"content": "Erster",
"forstudents": true,
"links": {
"myhome": "http://test.de"
},
"imgs": {
"myhome": "http://test.de"
}
}
the question is how to tell him what to put in name and value that myhome is in name and the url in value
You can do something like this:
public class User {
public User(string json) {
var jsonObject = Json.Decode(json);
MyName = (string)jsonObject.user.name;
MyTeamName = (string)jsonObject.user.teamname;
MyEmail = (string)jsonObject.user.email;
Players = (DynamicJsonArray) jsonObject.user.players;
}
public string MyName{ get; set; }
public string MyTeamName { get; set; }
public string MyEmail{ get; set; }
public Array Players { get; set; }
}
But would need to assign the values manually.
Example using your model (0 index based only, you would need to write a loop) but using a direct RestFul call:
var url = "http://localhost:9200/campusoffice/news";
var client = new WebClient();
var json = client.DownloadString(url);
var jsonObject = Json.Decode(json);
var links = (DynamicJsonArray) jsonObject.links;
var imgs = (DynamicJsonArray) jsonObject.imgs;
var news = new News
{ author = (string)jsonObject.author,
links = new List<link>() };
var aLink = new link { name = (string)links[0].myhome, value =
(string)imgs[0].myhome };
news.links.Add(aLink);
I typed this roughly without compiling/testing but should give you an idea.

Extract data from Json string

I got a string containing Json. It looks like this:
"status_code":200,
"status_txt":"OK",
"data":
{
"img_name":"D9Y3z.png",
"img_url":"http:\/\/s1.uploads.im\/D9Y3z.png",
"img_view":"http:\/\/uploads.im\/D9Y3z.png",
"img_width":"167",
"img_height":"288",
"img_attr":"width=\"167\" height=\"288\"",
"img_size":"36.1 KB",
"img_bytes":36981,
"thumb_url":"http:\/\/s1.uploads.im\/t\/D9Y3z.png",
"thumb_width":360,
"thumb_height":360,
"source":"http:\/\/www.google.com\/images\/srpr\/nav_logo66.png",
"resized":"0",
"delete_key":"df149b075ab68c38"
}
I am trying to get a hold of the "img_url". I have Json.NET installed and I´ve found similar questions here..
for example something like this:
JObject o = JObject.Parse("{'People':[{'Name':'Jeff'},{'Name':'Joe'}]}");
// get name token of first person and convert to a string
string name = (string)o.SelectToken("People[0].Name");
In my case I changed ("People[0].Name") to ("img_url"),("img_url[0]) etc..no luck
This is my code now:
public string tempJson { get; set; }
public ActionResult SaveUploadedFile(string test)
{
using (WebResponse wrs = wrq.GetResponse())
using (Stream stream = wrs.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
string json = reader.ReadToEnd();
tempJson = json;
}
}
Do I have to do something with the string before I can extract the value?
Thanks!
img_url is not a property of root object - it's a property of data object:
var obj = JObject.Parse(json);
var url = (string)obj["data"]["img_url"]; // http://s1.uploads.im/D9Y3z.png
Another option:
var url = (string)obj.SelectToken("data.img_url");
With help of this site
var obj = JsonConvert.DeserializeObject<RootObject>(json);
Console.WriteLine(obj.data.img_url);
public class Data
{
public string img_name { get; set; }
public string img_url { get; set; }
public string img_view { get; set; }
public string img_width { get; set; }
public string img_height { get; set; }
public string img_attr { get; set; }
public string img_size { get; set; }
public int img_bytes { get; set; }
public string thumb_url { get; set; }
public int thumb_width { get; set; }
public int thumb_height { get; set; }
public string source { get; set; }
public string resized { get; set; }
public string delete_key { get; set; }
}
public class RootObject
{
public int status_code { get; set; }
public string status_txt { get; set; }
public Data data { get; set; }
}
You can also do the same thing with the use of dynamic keyword (without declaring above classes)
dynamic obj = JsonConvert.DeserializeObject(json);
Console.WriteLine(obj.data.img_url);

EmitMapper's List Mapping Issue with Collections

The source class:
public class Post
{
public long ID { get; set; }
[Column(TypeName="nvarchar")]
[Required]
[StringLength(250)]
public string Name { get; set; }
[Column(TypeName="varchar")]
[StringLength(250)]
public string UrlName { get; set; }
[Column(TypeName="ntext")]
public string Excerpt { get; set; }
[Column(TypeName="ntext")]
[Required]
public string Content { get; set; }
public DateTime PostedTime { get; set; }
public DateTime? PublishedTime { get; set; }
public DateTime? LastUpdatedTime { get; set; }
public bool IsPublished { get; set; }
public virtual List<Category> Categories { get; set; }
public virtual List<Comment> Comments { get; set; }
public virtual List<Tag> Tags { get; set; }
}
the destination class
public class Post : Model
{
public long ID { get; set; }
public string Name { get; set; }
public string UrlName { get; set; }
public string Excerpt { get; set; }
public string Content { get; set; }
public DateTime PostedTime { get; set; }
public DateTime LastCommentedTime { get; set; }
public bool IsPublished { get; set; }
public List<Category> Category { get; set; }
public List<Comment> Comments { get; set; }
public List<Tag> Tags { get; set; }
}
I try using EmitMapper to map from each other; when mapping from source to desction, here is the code sample:
[TestMethod]
public void ShouleMapEntityToModel()
{
Post eP = new Post();
eP.ID = 2;
eP.Comments = new List<Comment>();
eP.Comments.Add(new Comment()
{
ID = 2,
Author = "derek"
});
var mP = eP.Map<Post, mBlog.Core.Models.Post>();
Assert.IsNotNull(mP);
Assert.AreEqual(1, mP.Comments.Count());
}
and I got an exception,
Test method mBlog.Test.EmitMapperTest.ShouleMapEntityToModel threw exception:
System.Exception: Constructor for types [] not found in System.Collections.Generic.IList`1[[mBlog.Core.Models.Post, mBlog.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]
I had the same problem, but I have found the solution. Don't user Lists for your destination object. If you use simple arrays in your mBlog.Core.Models.Post object you should get a nicely filled object. So your destination class should look like:
public class Post : Model
{
public long ID { get; set; }
public string Name { get; set; }
public string UrlName { get; set; }
public string Excerpt { get; set; }
public string Content { get; set; }
public DateTime PostedTime { get; set; }
public DateTime LastCommentedTime { get; set; }
public bool IsPublished { get; set; }
public Category[] Category { get; set; }
public Comment[] Comments { get; set; }
public Tag[] Tags { get; set; }
}
This answer shows how to handle IEnumerable to IEnumerable: EmitMapper and List
I believe that can be applied to this case too. Take a look:
This can be done creating a custom class, implementing the interface "ICustomConverterProvider" and adding a ConvertGeneric to the "DefaultMapConfig".
Looking on the source code of EmitMapper, i found a class named "ArraysConverterProvider", which is the default generic converter from ICollections to Arrays.
Adapting the code from this class to work with IEnumerable
collections:
class GenericIEnumerableConverterProvider : ICustomConverterProvider
{
public CustomConverterDescriptor GetCustomConverterDescr(
Type from,
Type to,
MapConfigBaseImpl mappingConfig)
{
var tFromTypeArgs = DefaultCustomConverterProvider.GetGenericArguments(from);
var tToTypeArgs = DefaultCustomConverterProvider.GetGenericArguments(to);
if (tFromTypeArgs == null || tToTypeArgs == null || tFromTypeArgs.Length != 1 || tToTypeArgs.Length != 1)
{
return null;
}
var tFrom = tFromTypeArgs[0];
var tTo = tToTypeArgs[0];
if (tFrom == tTo && (tFrom.IsValueType || mappingConfig.GetRootMappingOperation(tFrom, tTo).ShallowCopy))
{
return new CustomConverterDescriptor
{
ConversionMethodName = "Convert",
ConverterImplementation = typeof(GenericIEnumerableConverter_OneTypes<>),
ConverterClassTypeArguments = new[] { tFrom }
};
}
return new CustomConverterDescriptor
{
ConversionMethodName = "Convert",
ConverterImplementation = typeof(GenericIEnumerableConverter_DifferentTypes<,>),
ConverterClassTypeArguments = new[] { tFrom, tTo }
};
}
}
class GenericIEnumerableConverter_DifferentTypes<TFrom, TTo> : ICustomConverter
{
private Func<TFrom, TTo> _converter;
public IEnumerable<TTo> Convert(IEnumerable<TFrom> from, object state)
{
if (from == null)
{
return null;
}
TTo[] result = new TTo[from.Count()];
int idx = 0;
foreach (var f in from)
{
result[idx++] = _converter(f);
}
return result;
}
public void Initialize(Type from, Type to, MapConfigBaseImpl mappingConfig)
{
var staticConverters = mappingConfig.GetStaticConvertersManager() ?? StaticConvertersManager.DefaultInstance;
var staticConverterMethod = staticConverters.GetStaticConverter(typeof(TFrom), typeof(TTo));
if (staticConverterMethod != null)
{
_converter = (Func<TFrom, TTo>)Delegate.CreateDelegate(
typeof(Func<TFrom, TTo>),
null,
staticConverterMethod
);
}
else
{
_subMapper = ObjectMapperManager.DefaultInstance.GetMapperImpl(typeof(TFrom), typeof(TTo), mappingConfig);
_converter = ConverterBySubmapper;
}
}
ObjectsMapperBaseImpl _subMapper;
private TTo ConverterBySubmapper(TFrom from)
{
return (TTo)_subMapper.Map(from);
}
}
class GenericIEnumerableConverter_OneTypes<T>
{
public IEnumerable<T> Convert(IEnumerable<T> from, object state)
{
if (from == null)
{
return null;
}
return from;
}
}
This code is just a copy with a minimum of adaptation as possible and
can be applyed to objects with many levels of hierarchy.
You can use the above code with the following command:
new DefaultMapConfig().ConvertGeneric(
typeof(IEnumerable<>),
typeof(IEnumerable<>),
new GenericIEnumerableConverterProvider());
This saved my day and I hope to save yours too! hehehe

Categories