Newtonsoft.Json : Cant get JSON data to convert into C# Object - c#

Call to a REST based API returns me data in JSON format(stored in variable strJSONStringFromAPI).
{
"id": "551",
"name": "Dev D",
"work": [
{
"employer": {
"name": "Microsoft Corporation"
},
"position": {
"name": "Software Development"
}
}
],
"gender": "male"}
I have created following classes corresponding to above JSON data
public class Employer
{
private string _name;
public string name
{
get { return _name; }
set { _name = value; }
}
}
public class Position
{
private string _name;
public string name
{
get { return _name; }
set { _name = value; }
}
}
public class Work
{
private Employer _employer;
private Position _position;
public Employer employer
{
get { return _employer; }
set { _employer = value; }
}
public Position position
{
get { return _position; }
set { _position = value; }
}
}
public class UserInfo
{
private string _id;
private string _name;
private Work[] _wk;
public string id
{
get { return _id; }
set { _id = value; }
}
public string name
{
get { return _name; }
set { _name = value; }
}
public Work[] work
{
get { return _wk; }
set { _wk = value; }
}
}
Now i have method GetUserInfo which should return object UserInfo as shown below
Public UserInfo GetUserDetails()
{
UserInfo user = New UserInfo();
user = Newtonsoft.Json.JsonConvert.DeserializeObject<UserInfo>(strJSONStringFromAPI);
return user;
}
later i will access the values as
label1.text = user.ID ;
label2.text = user.name;
As of now i am getting all properties of above user object as NULL (user.ID = null etc etc)
I know i am missing something very important here..can someone help me what else needs to be done in in Employer , Position and Work classes so that i get proper values (eg user.ID = "551" etc)

Your Work class above will not compile.
public class Work
{
private Employer _employer;
private Position _position;
public Employer employer
{
get { return _employer; }
set { _employer = value; }
}
public Position position
{
get { return _employer; }
set { _employer = value; }
}
}
The Position property can't use _employer.
Tested your code with that corrected, it does work as expected. Here's a simple test using a HTTP Handler:
<%# WebHandler Language="C#" Class="JsonDotnet" %>
using System;
using System.IO;
using System.Web;
using Newtonsoft.Json;
public class JsonDotnet : IHttpHandler {
public void ProcessRequest (HttpContext context) {
string json = context.Server.MapPath(
"~/app_data/json-test.txt"
);
UserInfo user = Newtonsoft.Json.JsonConvert
.DeserializeObject<UserInfo>(
File.ReadAllText(json)
);
context.Response.Write(user.id + "<br>");
context.Response.Write(user.name + "<br>");
context.Response.Write(user.work[0].employer.name + "<br>");
}
public bool IsReusable {
get { return false; }
}
public class Employer {
public string name { get; set;}
}
public class Position {
public string name { get; set;}
}
public class Work {
public Employer employer { get; set;}
public Position position { get; set;}
}
public class UserInfo {
public string id { get; set;}
public string name { get; set;}
public Work[] work { get; set;}
}
}
Don't forget to put your json string in ~/app_data/json-test.txt.
Are you sure strJSONStringFromAPI is exactly the same as the string you specified in your first code snippet above?

Your private variable should be public when you deserialize the json object and all name should be same in both in json object as well as in classes

Related

object data null after get request in Dotnet webapi project

I have created two model classes Organisation.cs and Employee.cs
public class Organisation
{
private static string organisationName="FALCON";
private int employeeCount=2;
private string ceoName;
private List<string> departmentNames;
[JsonIgnore]
private List<Employee> employees;
private List<Address> addesses;
private bool isCeoChangeAvailable= true;
public string OrganisationName
{
get {return organisationName;}
set {organisationName = value;}
}
public int EmployeeCount
{
get {return employeeCount;}
set { employeeCount = value; }
}
public string CeoName
{
get { return ceoName; }
set { ceoName = value; }
}
public List<string> Departments
{
get { return departmentNames; }
set { departmentNames = value; }
}
[IgnoreDataMember]
public List<Employee> Employees
{
get {return employees; }
set {employees=value; }
}
public List<Address> OfficeAdresses
{
get {return addesses; }
set { addesses = value; }
}
public bool IsCeoChange
{
get{ return isCeoChangeAvailable; }
set { isCeoChangeAvailable = value; }
}
public Organisation(string ceoName,List<string> departments,List<Address> addresses)
{
this.CeoName = ceoName;
this.Departments = departments;
this.OfficeAdresses = addresses;
}
public Organisation() { }
}
and an employee class
public class Employee
{
private Guid employeeId;
private string name;
private string departmentName;
private bool isManager;
private int salary;
public Guid Id
{
get
{ return employeeId;}
set
{ employeeId = value;}
}
public string Name
{
get
{ return name;}
set
{ name = value;}
}
public bool IsManager
{
get
{ return isManager;}
set
{ isManager = value;}
}
public string DepartmentName
{
get { return departmentName;}
set { departmentName = value;}
}
public int Salary
{
get { return salary; }
set { salary = value; } }
public Employee()
{
}
}
have a two controllers for Employee and Organisation, I am trying to post Organisation data and storing it in a variable.
In my organisaiton controller I have this method
public IActionResult PostOrganisationData(Organisation organisation)
{
_organisationData.PostOrganisationDetails(organisation);
return Created(HttpContext.Request.Scheme + "://" + HttpContext.Request.Host + HttpContext.Request.Path + "/" + organisation.OrganisationName, organisation);
}
In my datalayer have a class MockEmployeeData which implements IOrganisationData interface
here is the code where I am constructing the Organisation object and assigning it to an instance of Organisation object. During the request The organisation object holds the assigned data. Here is the code
private Organisation organisation = new Organisation();
public Organisation PostOrganisationDetails(Organisation organisation)
{
Organisation organisationObject = new Organisation(organisation.CeoName, organisation.Departments, organisation.OfficeAdresses);
organisation = organisationObject;
return organisation;
}
When I call the Get action method which gets the organisation details from the controller the previously assigned object has properties with null. Here is the get method
[HttpGet]
[Route("api/[controller]")]
public IActionResult GetOrganisationDetails()
{
var organisationData=_organisationData.GetOrganisationData();
return Ok(organisationData);
}
public Organisation GetOrganisationData()
{
Organisation organisationObject = new Organisation();
organisationObject = organisation;
return organisationObject;
}
Here in this method I,m assigning the variable which holds the previously assigned data from post request and getting back the object where all properties have gone null now.Please help me solve this
You need to make your properties in your Organisation model class to nullable. Now you can do this by either manually making each property nullable in your class:
public class Organisation
{
public string? OrganisationName
{
get {return organisationName;}
set {organisationName = value;}
}
public int? EmployeeCount
{
get {return employeeCount;}
set { employeeCount = value; }
}
public string? CeoName
{
get { return ceoName; }
set { ceoName = value; }
}
public List<string?> Departments
{
get { return departmentNames; }
set { departmentNames = value; }
}
....so on
Or you can globally enable this property by editing your csproj file which contains your project properties:
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<!--<Nullable>enable</Nullable>-->
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

Assign string[] array field to another array field of same type c#

I have two classes defined in my solution
public class Registration {
[...]
public list<Account> Accounts {get; set;}
}
public class Account {
[...]
public string Code { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
In the web service that I am consuming, the following class definitions are available
public partial class VendReg {
[...]
private Payment_Details[] requestDetailsField;
[System.Xml.Serialization.XmlArrayItemAttribute(IsNullable=false)]
public Payment_Details[] RequestDetails {
get {
return this.requestDetailsField;
}
set {
this.requestDetailsField = value;
}
}
}
public partial class Payment_Details {
private string bk_CodeField;
private string bk_NameField;
private string bk_AddressField;
public string Bk_Code {
get {
return this.bk_CodeField;
}
set {
this.bk_CodeField = value;
}
}
public string Bk_Name {
get {
return this.bk_NameField;
}
set {
this.bk_NameField = value;
}
}
public string Bk_Address {
get {
return this.bk_AddressField;
}
set {
this.bk_AddressField = value;
}
}
}
I want to assign Account to Request Details which is an array of Payment_Details. I tried this code below
vendReg.RequestDetails = registration.Accounts.Cast<Payment_Details>().ToArray();
I got invalid cast exception: Unable to cast object of type 'Account' to type 'Payment_Details'
Please guide on what I am not doing right
You need to convert this yourself (or you can look into things like Automapper)
vendReg.RequestDetails = registration.Accounts.Select(acc =>
new Payment_Details {
Bk_Code = acc.Code,
Bk_Name = acc.Name,
Bk_Address = acc.Address
}).ToArray();

DataContractJsonSerializer: Deserialize to different type based on JSON property

I'm using DataContractJsonSerializer to deserialize JSON from a Webservice.
[{"id":2947,"type":"PdfDocument","name":"test.pdf"},
{"id":2945,"type":"ImageDocument","name":"test.jpg", "color": "green"}]
Based on their type, JSON entities can have different properties (for example a color). Currently i use a single model Document for deserialization and PagedCollectionViews to filter what i need to show in the UI.
public class Document : EntityBase
{
private string name;
private string type;
private string color;
public Document()
{
}
[DataMember(Name = "name")]
public string Name
{
get
{
return this.name;
}
set
{
if (this.name != value)
{
this.name = value;
this.OnPropertyChanged("Name");
}
}
}
[DataMember(Name = "type")]
public string Type
{
get
{
return this.type;
}
set
{
if (this.type != value)
{
this.type = value;
this.OnPropertyChanged("Type");
}
}
}
[DataMember(Name = "color")]
public string Color
{
get
{
return this.color;
}
set
{
if (this.color != value)
{
this.color= value;
this.OnPropertyChanged("Color");
}
}
}
}
public class DocumentsViewModel : ViewModelBase
{
public ObservableCollection<Document> Documents { get; set; }
public PagedCollectionView ImageDocuments;
public PrintProjectDetailsViewModel()
{
this.Documents = new ObservableCollection<Document>();
this.ImageDocuments = new PagedCollectionView(Documents);
this.ImageDocuments.Filter = (o) => ((Document)o).Type == "ImageDocument";
}
}
However, that feels "smelly" to me. Is it possible to automatically deserialize to a subclass of Document depending of the JSON value of type?

Issue in getting complex object in Web API Post

I'm making ajax POST call to my web API and posting a JSON. Below is my code
C# class:
public class Employee:EmployeeBase
{
private string _EId;
private string _EName;
private string _Designation;
private EmployeeBase[] _Expirence;
public string EId
{
get { return _EId; }
set { _EId = value; }
}
public string EName
{
get { return _EName; }
set { _EName = value; }
}
public string Designation
{
get { return _Designation; }
set { _Designation = value; }
}
public Expirence[] MyExpirence
{
get { return _Expirence; }
set { _Expirence = value; }
}
}
public class EmployeeBase
{
private string _Id;
private string _Company;
private string _Years;
public string Id
{
get { return _Id; }
set { _Id = value; }
}
public string Company
{
get { return _Company; }
set { _Company = value; }
}
public string Years
{
get { return _Years; }
set { _Years = value; }
}
}
Controller:
[HttpPost]
public ActionResult SaveAssociatDisassociateCameras(Employee zone)
{
}
Sample JSON:
Sample 1 :
{
"Id":"E100",
"Name":"TestEmployee",
"Designation":"Test Engineer",
"MyExpirence":[
{
"Id":"01",
"Company":"Company1",
"Years":"10"
}
]
}
Sample 2 :
{
"Id":"E100",
"Name":"TestEmployee",
"Designation":"Test Engineer",
"MyExpirence":[
{
"Id":"01",
"Company":"Company1",
"Years":"10"
}
],
"DummyArray":[
]
}
Now the issue is when I post Sample 1 JSON is getting properly posted to controller. But in controller MyExpirence array is null. But I'm getting values for EId,EName etc. Only MyExpirence array is null.
In other hand if I post Sample 2 adding a dummy array to the JSON I'm getting proper values. In this case I'm getting proper value for EId,EName and even for MyExpirence array.
I cant understand why I'm getting null for MyExpirence in Sample 1. And I'm not okay with the Sample 2 solution. I want a correct way of doing this.
Your code won't compile: _Expirence is different to MyExpirence property. Fix it like in next sample
public class Employee:EmployeeBase
{
private string _EId;
private string _EName;
private string _Designation;
private EmployeeBase[] _Expirence;
public string EId
{
get { return _EId; }
set { _EId = value; }
}
public string EName
{
get { return _EName; }
set { _EName = value; }
}
public string Designation
{
get { return _Designation; }
set { _Designation = value; }
}
public Expirence[] MyExpirence
{
get { return _Expirence; }
set { _Expirence = value; }
}
}

How to use the Same Class on Client as on the Service?

How can I pass an entire defined class through a WCF service? I have the class defined on both the service and client side. I keep getting an error:
Best overloaded method match has some invalid arguments.
The whole class was copied from the client-side to the service-side.
Client side calling:
TransferProxy.PutTransferOnService(Transfer);
Defined on service:
[OperationContract]
bool PutTransferOnService(TypeTransfer Transfer);
I don't want to access individual items on the class from the client, I just want to move the WHOLE populated object through and do processing on the server side.
[DataContract]
public class TypeTransfer
{
private string userID;
private string transferNum;
private DateTime effectiveDate;
private int unitCount;
private int skuCount;
private string reason;
private string localStatus;
private string destStatus;
private string carrier;
private string sourceStore;
private string destinationStore;
private string inSeal;
private string outSeal;
[DataMember]
private List<TypeSOQ> correspondingSOQ = new List<TypeSOQ>();
[DataMember]
private List<TypeProductList> ProductList = new List<TypeProductList>();
public TypeTransfer() { }
// Function adds single item to transfer object
public void AddItem(int ProductID, string SKU, string PrimarySKU, string SCC, string ProductDescription, int TransferQty)
{
ProductList.Add(new TypeProductList
{
productID = ProductID,
sku = SKU,
primaryUPC = PrimarySKU,
scc = SCC,
description = ProductDescription,
transferQty = TransferQty
});
}
// Add SOQ to transfer object (can support multiple SOQ's)
public void AddSOQ(TypeSOQ soq)
{
correspondingSOQ.Add(soq);
}
// Function returns number of skus in Product List
public int GetSKUTotal()
{
return ProductList.Count();
}
// Function returns total number of items in transfer
public int GetItemTotal()
{
int itemtotal = 0;
for (int i = 0; i < ProductList.Count(); i++)
{
itemtotal += ProductList[i].transferQty;
}
return itemtotal;
}
// Return entire SOQ list
public List<TypeSOQ> GetSOQs()
{
return correspondingSOQ;
}
// Returns full product list in transfer object
public List<TypeProductList> GetProductList()
{
return ProductList;
}
[DataMember]
public string UserID
{
get { return userID; }
set { userID = value; }
}
[DataMember]
public string TransferNum
{
get { return transferNum; }
set { transferNum = value; }
}
[DataMember]
public DateTime EffectiveDate
{
get { return effectiveDate; }
set { effectiveDate = value; }
}
[DataMember]
public int UnitCount
{
get { return unitCount; }
set { unitCount = value; }
}
[DataMember]
public string Reason
{
get { return reason; }
set { reason = value; }
}
[DataMember]
public string LocalStatus
{
get { return localStatus; }
set { localStatus = value; }
}
[DataMember]
public string DestStatus
{
get { return destStatus; }
set { destStatus = value; }
}
[DataMember]
public string Carrier
{
get { return carrier; }
set { carrier = value; }
}
[DataMember]
public string SourceStore
{
get { return sourceStore; }
set { sourceStore = value; }
}
[DataMember]
public string DestStore
{
get { return destinationStore; }
set { destinationStore = value; }
}
[DataMember]
public string InSeal
{
get { return inSeal; }
set { inSeal = value; }
}
[DataMember]
public string OutSeal
{
get { return outSeal; }
set { outSeal = value; }
}
[DataMember]
public int SKUCount
{
get { return skuCount; }
set { skuCount = value; }
}
}
You said - The whole class was copied from the client-side to the service-side.
You don't need to copy your class to server side. just define your class in a separate library and give reference of that same library to both client and server.

Categories