Formatting JSON response - c#

====Summary====
I need some help trying to format my JSON response. I'm using ASP.Net with a Model and a Controller.
====Information====
I am working on a web api in ASP.Net. I have a SQL backend in which I fetch some data and put it into a DataTable. My DataTable looks like this:
+----+-------+-------+
| ID | Title | Users |
+----+-------+-------+
| 1 | Test | user1 |
| 1 | Test | user2 |
+----+-------+-------+
NOTE: One record can have multiple users which is why ID is "1" for both rows ("ID" is not the unique ID of the actual SQL table row but rather a foreign key...anyway, I digress... )
I have created a Model in C# that looks like this:
public class Record
{
public int ID { get; set; }
public string Title {get; set;}
public string Users {get; set;}
}
Finally my Controller looks like this
DataBaseHelper db = new DataBaseHelper();
public IEnumerable Get_Record(string id)
{
// Get DataTable
DataTable dt = new DataTable();
dt = db.GetRecord(id);
foreach (DataRow row in dt.Rows)
{
yield return new Record
{
ID = row.Field("ID"),
Title = row.Field("Title"),
Users = row.Field("Users")
};
}
}
When I call the API I get this:
[
-{
ID: 1,
Title: "Test",
Users: "user1"
},
-{
ID: 1,
Title: "Test",
Users: "user2"
}
]
====QUESTION====
How would I get the JSON response to look something sort of like this (if possible):
{
"Response":
[
{
ID: 1,
Title: "Test",
Users:
[
{name: "user1"},
{name: "user2"}
]
}
]
}
If that is not possible then this would be great as well:
"Response":
[
{
ID: 1,
Title: "Test",
Users: "user1"
},
{
ID: 1,
Title: "Test",
Users: "user2"
}
]

To expand upon #Shahrooz Jefri's answer, you can return an HttpResponseMessage which will allow you to return an anonymous object, but to get the result formatted as required, you will need to modify the Get_Record method:
public HttpResponseMessage Get_Record(string id)
{
// Get DataTable
DataTable dt = new DataTable();
dt = db.GetRecord(id);
var records = dt.Rows.Select(r => new Record()
{
ID = row.Field("ID"),
Title = row.Field("Title"),
Users = row.Field("Users")
});
return this.Request.CreateResponse(HttpStatusCode.OK,
new
{
Response = new
{
ID = records.First().ID,
Title = records.First().Title,
Users = records.Select(r => r.Users)
}
});
}
With this approach, we first transform the results from a call to db.GetRecord into an IEnumerable<Record> of your your Record object.
From there, we can shape an anonymous object to match your formatting requirements. Note that in my answer I have not applied any error checking; you should, as the case where db.GetRecord returns no results will cause an exception when we populate the ID and Title fields of the response object due to calls to records.First().

You can return your own format with anonymous Object.
Please See this:
public HttpResponseMessage Get()
{
return this.Request.CreateResponse(
HttpStatusCode.OK,
new { Message = "Hello", Value = 123 });
}

Well, What I have experienced so far, creating a generic response will be the best practice for your case. For instance, you may have a class something like this.
public enum Status
{
OK = 1,
ERROR = -1,
}
public class ResponseDTO
{
public static ResponseDTO CreateDynamicResponse(object content)
{
return new ResponseDTO {Status = Status.OK, Content = content};
}
public static ResponseDTO CreateDynamicResponseFromException(RovlerBaseException ex)
{
return new ResponseDTO
{
Status = Status.ERROR,
Message = ex.Message,
};
}
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Status Status;
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public object Content { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Message { get; set; }
}
After the execution of action I create an ActionFilterAttribute in order to check if there is an error on response that action just returned. Then I user CreateDynamicResponse or CreateDynamicResponseFromException with respect to the status of returned object.

Related

Using ElemMatch with FilterDefiniton by MongoDB Drive

I'm trying to search for a time interval by ElemMatch in C#. My fields of interest consist of simple objects or an arrays of objects, like the following:
{
"ID": "123456789",
"field1": {
"item1": "string",
"item2": 123
}
"field2": [
{
"item11": 11.11,
"myDatetime": {
ts: 2022-10-23T23:14:55
}
},
{
"item11": 12.22,
"myDatetime": {
ts: 2022-08-23T23:14:55
}
}
]
}
and my model is like:
public record MongoCollection
{
public string ID { get; init; }
public object field1 { get; init; }
public List<object> field2 { get; init; }
}
I'm trying to deploy ElemMatch this way:
var filter = Builders<MongoCollection>.Filter.ElemMatch("field1",
Builders<MongoCollection>.Filter.And(
Builders<MongoCollection>.Filter.Gte("myDatetime.ts", fromDate),
Builders<MongoCollection>.Filter.Lte("myDatetime.ts", tillDate))
);
The error that I receive on this part of code is:
Unable to cast object of type 'MongoDB.Bson.Serialization.Serializers.ObjectSerializer' to type 'MongoDB.Bson.Serialization.IBsonSerializer
I also tried this approach:
var field = new StringFieldDefinition<MongoCollection, List<object>>("field1");
And
FieldDefinition<MongoCollection,List<object>> field = "field1";
And I put the field in ElemMatch like this:
var filter = Builders<MongoCollection>.Filter.ElemMatch(field,
Builders<MongoCollection>.Filter.And(
Builders<MongoCollection>.Filter.Gte("myDatetime.ts", fromDate),
Builders<MongoCollection>.Filter.Lte("myDatetime.ts", tillDate))
);
and I received the same error.
How can I solve it?
You should refer to field2 but not field1.
As in the MongoCollection class the item in field2 is object type, the filter for the nested object should be in object type by using Builders<object>.
var filter = Builders<MongoCollection>.Filter.ElemMatch("field2",
Builders<object>.Filter.And(
Builders<object>.Filter.Gte("myDatetime.ts", fromDate),
Builders<object>.Filter.Lte("myDatetime.ts", tillDate))
);

Want to create one list with one Id and multiple ProviderId values like

I want to create one list with one Id and multiple ProviderId values like
Id ProviderId
1 "val1"
1 "val2"
I have a model class as per below :
public class Model
{
[JsonProperty]
public string Id { get; set; }
[JsonProperty]
public List<PrefDictionary> ProviderId { get; set; }
}
Now I have created one list as per below :
List<PrefDictionary> PrefData = data.Select(p => new PrefDictionary()
{
_1 = p.PrefDictionary._1,
_2 = p.PrefDictionary._2
}).ToList();
Here in data I am getting whole json format data and one node is like this below for PrefDictionary.
data = {
Id : 1,
PrefDictionary{
1: "Val1",
2: "Val2"
}}
Now then I have created one more list as per below :
List<Model> PP = data.Select(p => new Model()
{
Id = p.Id,
ProviderId = PrefData.Select(x => new PrefDictionary()
{
_1 = x._1,
_2 = x._2
}).ToList(),
}).ToList();
}
But the problem is I am getting empty in second column list in first I am getting Id but not getting any value in second column.
I'm not 100% I understand JSON format you are expecting. However, if you want a list of providers - each with a list of preferences - then I think you'll need another class to get this to serialize properly:
public class Model
{
[JsonProperty]
public List<Providers> providers { get; set; }
}
public class Providers
{
[JsonProperty]
public string Id { get; set; }
[JsonProperty]
public List<PrefDictionary> ProviderId { get; set; }
}
This should give you the JSON output:
{
"Providers": [
{
"ID": 1,
"PrefDictionary": [
{
"Val1": "",
"Val2": ""
}
]
},
{
"ID": 2,
"PrefDictionary": [
{
"Val1": "",
"Val2": ""
}
]
}
]
}
I suspect the problem could be the way how you deserialize your data object.
Based on your code, I've created the result that contains the PrefDirectonary.
.
However, one thing I did for the data variable was to make an object like this,
PrefDictionary pd = new PrefDictionary
{
_1 = "Value1",
_2 = "Value2"
};
List<TestObject> data = new List<TestObject>() {
new TestObject
{
Id = "1",
PrefDictionary = pd
}
};
It will be helpful to show us how you deserialize the JSON data object.

OData v4 Query To Filter Results In A Complex Object

I developed a .NET Core v5 WebAPI and Integrated OData v4.
Everything works if I return a normal list of students from my controller and perform OData queries.
But my API has a standard response structure for success and failure. Everything comes only inside data property.
{
"status": "SUCCESS",
"data": [
{
"name": "Student A",
"age": 10
},
{
"name": "Student B",
"age": 11
},
{
"name": "Student C",
"age": 12
},
{
"name": "Student D",
"age": 13
}
]
}
What can be the OData URL Query to fetch Students with age > 11. This is what I tried
https://localhost:44351/api/v2/Students/GetAll?$filter=data/age gt 11
But it throws me this error
This is my endpoint.
Also I've configured OData only for search, filter, order and count. Expand is not something I'm considering now
[HttpGet]
[MapToApiVersion("2.0")]
[Route("Success")]
[EnableQuery]
public IActionResult Success20()
{
var listOfData = new List<Student>();
listOfData.Add(new Student { Name = "Student A", Age = 10 });
listOfData.Add(new Student { Name = "Student B", Age = 11 });
listOfData.Add(new Student { Name = "Student C", Age = 12 });
listOfData.Add(new Student { Name = "Student D", Age = 13 });
return Ok(new SuccessResponse<List<Student>>
{
Data = listOfData
});
}
And this is my standard response for Sucess
public class Response
{
protected ResponseStatus ResponseStatus { get; set; }
public string Status { get; set; }
}
public class SuccessResponse<T> : Response
{
public T Data { get; set; }
public SuccessResponse()
{
ResponseStatus = ResponseStatus.SUCCESS;
Status = ResponseStatus.SUCCESS.ToString();
}
}
According to your response structure, I suppose you are returning an Anonymous Type in the API controller, code as below, right?
[EnableQuery]
public IActionResult Get()
{
var result = _db.Students.ToList();
return Ok(new { status = "success", data = result });
}
As far as I know, the OData is not designed to work with anonymous types (if using the above code, it will show the error you are meeting). So, to solve the error, you could create ResponseModel which contains the status and data, then return it to client and filter data.
Code like this:
public class ResponseModel
{
[Key]
public string status { get; set; }
public List<Student> data { get; set; }
}
API controller:
[EnableQuery]
public IActionResult Get()
{
var result = _db.Students.ToList();
//return Ok(new { status = "success", data = result });
return Ok(new ResponseModel { status="success", data = result});
}
Then, change the EntitySet model in the GetEdmModel() method:
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<ResponseModel>("Students");
return builder.GetEdmModel();
}
After that, we could filter data using url: https://localhost:44387/odata/Students?$expand=data($filter= age gt 11)
The result as below:
I found the solution.
The reason it was due to the exclution of Expand on OData.
I've added Expand() referring to #ZhiLv's answer
And the query was working now.

How to create hierarchy in json string from string array?

I am trying to generate json string for the hierarchy like below:
Company(select * from Company)
Department(select * from Department)
Employee(select * from Employee)
Each of the above query will return fields like below:
Company Fields - (Id,Name,Location)
Department Fields - (Id,Name,CompanyId)
Employee Fields - (Id,Name,DepartmentId)
Now I am trying to generate JSON string for above entities like below:
Expected output:
{
"Id": "",
"Name": "",
"Location": "",
"Department":
{
"Id": "",
"Name": "",
"CompanyId": "",
"Employee" :
{
"Id": "",
"Name": "",
"DepartmentId": "",
}
}
}
Code:
public string GetData(Child model,List<Parent> parents)
{
var fields = new List<string[]>();
if (parents != null)
{
foreach (var parent in parents)
{
var columns = GetColumns(parent); //returns string[] of columns
fields.Add(columns);
}
}
fields.Add(GetColumns(model));
string json = JsonConvert.SerializeObject(fields.ToDictionary(key => key, v => string.Empty),
Formatting.Indented);
return json;
}
Now when I don't have any parents and want to generate json string for only child then below code is working fine:
string json = JsonConvert.SerializeObject(fields.ToDictionary(key => key, v => string.Empty),Formatting.Indented)
Output :
{
"Id": "",
"Name": "",
"Location": "",
}
But now I want to generate JSON for my hierarchy with any such inbuilt way.
I know I can loop,append and create json string but I want to do this in better way like I have done for my child.
Update:
public class Child
{
public string Name { get; set; } // Contains Employee
//Other properties and info related to process sql query and connection string
}
public class Parent
{
public string Name { get; set; } // Contains Company,Department.
public string SqlQuery { get; set; } // query related to Company and Department.
//Other properties and info related to connection string
}
I created a class that holds the Information similarly to what you proposed, in a child-parent structure. I also added a custom little Parser that works recursively. Maybe that's what you need and/or what gives you the ideas you need to fix your problem.
I also altered the output a little bit, by adding the angled brackets ( "[ ]" ). I think that's what you will need with multiple children. At least that's what the JSON validator tells me that I posted below. If you don't need/ want them, just remove them in the parser.
I don't think you can use the parser you used in your example without having some form of extra fields like I showed in my previous answer, since those parsers usually go for property names as fields and I guess you don't want to create classes dynamically during runtime.
I also don't think that it is possible for you to create a dynamic depth of your parent-child-child-child...-relationship with Lists, Arrays or Dictionaries, because those structures have a set depth as soon as they are declared.
Class:
public class MyJsonObject
{
public List<string> Columns = new List<string>();
public string ChildName;
public List<MyJsonObject> Children = new List<MyJsonObject>();
}
Parser:
class JsonParser
{
public static string Parse(MyJsonObject jsonObject)
{
string parse = "{";
parse += string.Join(",", jsonObject.Columns.Select(column => $"\"{column}\": \"\""));
if (!string.IsNullOrEmpty(jsonObject.ChildName))
{
parse += $",\"{jsonObject.ChildName}\":";
parse += $"[{string.Join(",", jsonObject.Children.Select(Parse))}]";
}
parse += "}";
return parse;
}
}
Usage:
class Program
{
static void Main(string[] args)
{
MyJsonObject company = new MyJsonObject();
company.ChildName = "Department";
company.Columns.Add("Id");
company.Columns.Add("Name");
company.Columns.Add("Location");
MyJsonObject department = new MyJsonObject();
department.ChildName = "Employee";
department.Columns.Add("Id");
department.Columns.Add("Name");
department.Columns.Add("CompanyId");
MyJsonObject employee1 = new MyJsonObject();
employee1.Columns.Add("Id");
employee1.Columns.Add("Name");
employee1.Columns.Add("DepartmentId");
MyJsonObject employee2 = new MyJsonObject();
employee2.Columns.Add("Id");
employee2.Columns.Add("Name");
employee2.Columns.Add("DepartmentId");
company.Children.Add(department);
department.Children.Add(employee1);
department.Children.Add(employee2);
var json = JsonParser.Parse(company);
}
}
Output and Link to JSON-Validator:
https://jsonformatter.curiousconcept.com/
{
"Id":"",
"Name":"",
"Location":"",
"Department":[
{
"Id":"",
"Name":"",
"CompanyId":"",
"Employee":[
{
"Id":"",
"Name":"",
"DepartmentId":""
},
{
"Id":"",
"Name":"",
"DepartmentId":""
}
]
}
]
}
Perhaps I'm missing something. If you create the classes you need in the heirachy, instantiate them with data and then serialize them, the structure will be created for you.
using System.Web.Script.Serialization;
public class Employee
{
public int Id {get; set; }
public string Name {get; set; }
public int DepartmentId {get; set; }
}
public class Department
{
public int Id {get; set; }
public string Name {get; set; }
public string CompanyId {get; set; }
public List<Employee> {get; set;}
}
public class Company {
public int Id {get; set; }
public string Name {get; set; }
public string Location {get; set; }
public List<Department> {get; set;}
}
var myCompany = new Company();
// add departments and employees
var json = new JavaScriptSerializer().Serialize(myCompany);
You can use dynamic:
//here your database
dynamic[] company = new object[] { new { Name = "Company1", DepartmentId = 1 }, new { Name = "Company2", DepartmentId = 2 } };
dynamic[] department = new object[] { new { DepartmentId = 1, Name = "Department1" }, new { DepartmentId = 2, Name = "Department2" } };
//select from database
var data = from c in company
join d in department on c.DepartmentId equals d.DepartmentId
select new {Name = c.Name, Department = d};
var serialized = JsonConvert.SerializeObject(data);
result:
[
{
"Name": "Company1",
"Department": {
"DepartmentId": 1,
"Name": "Department1"
}
},
{
"Name": "Company2",
"Department": {
"DepartmentId": 2,
"Name": "Department2"
}
}
]
Ok, lets try like this. First of all as i understand your preblem: u have arrays of properties of parents and child and u neet to convert it to json object.
The point is here:
public static ExpandoObject DicTobj(Dictionary<string, object> properties)
{
var eo = new ExpandoObject();
var eoColl = (ICollection<KeyValuePair<string, object>>)eo;
foreach (var childColumn in properties)
eoColl.Add(childColumn);
return eo;
}
U use dynamic and ExpandoObject to convert dictionary to object
The other code is trivial: u put all your objects to one using dynamic type
and serialize it.
The full code:
public static Child Child1 { get; set; } = new Child
{
Name = "Child1"
};
public static Parent Parent1 { get; set; } = new Parent
{
Name = "Parent1"
};
public static Parent Parent2 { get; set; } = new Parent
{
Name = "Parent2"
};
private static void Main(string[] args)
{
var result = GetData(Child1, new List<Parent> {Parent1, Parent2});
Console.WriteLine(result);
}
/// <summary>
/// This is the magic: convert dictionary of properties to object with preperties
/// </summary>
public static ExpandoObject DicTobj(Dictionary<string, object> properties)
{
var eo = new ExpandoObject();
var eoColl = (ICollection<KeyValuePair<string, object>>) eo;
foreach (var childColumn in properties)
eoColl.Add(childColumn);
return eo;
}
public static string GetData(Child model, List<Parent> parents)
{
var childColumns = GetColumns(model);
dynamic child = DicTobj(childColumns);
var parentsList = new List<object>();
foreach (var parent in parents)
{
var parentColumns = GetColumns(parent);
var parentObj = DicTobj(parentColumns);
parentsList.Add(parentObj);
}
child.Parents = parentsList;
return JsonConvert.SerializeObject(child);
}
/// <summary>
/// this is STUB method for example
/// I change return type from string[] to Dictionary[columnName,ColumnValue], becouse u need not only column names, but
/// with it values, i gues. If not, look commented example at the end of this method
/// </summary>
public static Dictionary<string, object> GetColumns(object model)
{
var result = new Dictionary<string, object>();
if (model == Child1)
{
result.Add("Id", "1");
result.Add("Name", "Child1");
result.Add("Location", "SomeLocation");
}
if (model == Parent1)
{
result.Add("Id", "2");
result.Add("Name", "Parent1");
result.Add("SomeProperty1", "SomeValue1");
}
if (model == Parent2)
{
result.Add("Id", "3");
result.Add("Name", "Parent1");
result.Add("SomeProperty3", "SomeValue2");
}
//if u have only columNames and dont need values u can do like this
//var columns = new[] {"Id", "Name", "SomeProperty1"};//this u get from DB
//return columns.ToDictionary(c => c, c => new object());
return result;
}
}
public class Child
{
public string Name { get; set; } // Contains Employee
//Other properties and info related to process sql query and connection string
}
public class Parent
{
public string Name { get; set; } // Contains Company,Department.
public string SqlQuery { get; set; } // query related to Company and Department.
//Other properties and info related to connection string
}
And result output:
{
"Id": "1",
"Name": "Child1",
"Location": "SomeLocation",
"Parents": [
{
"Id": "2",
"Name": "Parent1",
"SomeProperty1": "SomeValue1"
},
{
"Id": "3",
"Name": "Parent1",
"SomeProperty3": "SomeValue2"
}
]
}
You can pass any kind of object even if you don't have a fixed structure:
Newtonsoft.Json.JsonConvert.SerializeObject(new yourCustomObject)
By using this.
The best way to to get this result
- You have to create a new class which has the relation of all the class. Then use the
Newtonsoft.Json.JsonConvert.SerializeObject(new organization )
Let creates a new class named organization . Add the relation which you want to see in Json. Then convert into the JSON using JsonConvert.
Or you can use the following dynamic loop
//here your database<br/>
dynamic[] company = new object[] { new { Name = "Company1", DepartmentId = 1 }, new { Name = "Company2", DepartmentId = 2 } };
dynamic[] department = new object[] { new { DepartmentId = 1, Name = "Department1" }, new { DepartmentId = 2, Name = "Department2" } };
//select from database<br/>
var data = from c in company
join d in department on c.DepartmentId equals d.DepartmentId
select new {Name = c.Name, Department = d};
var serialized = JsonConvert.SerializeObject(data);

Retrieve table to JSON, no matter how many columns in C#

I need to build a webservice that only receives a table name.
I was thinking in doing something like this:
public class Table
{
public string field{ get; set; }
public string value{ get; set; }
}
Because I don't know what table the user is going to request and how many columns they have.
I'm using a WCF web service and I want to retrieve the table in JSON format; so far I have something like this (a table with 3 columns):
[{"field":"ID","value":"124"},{"field":"DES","value":"AValue"},{"field":"CODE","value":"ACode"},{"field":"ID","value":"125"},{"field":"DES","value":"AnotherV"},{"field":"CODE","value":"AnotherCode"}]
As you can see it is difficult to know where a row ends
Is there a way to retrieve the data in a more legible way?
The model you provided actually models a single cell, not a table.
I suggest you use the following model:
public class Row : Dictionary<string,string>
{
}
public class Table : List<Row>
{
}
Then you can use it like this:
Table table = new Table
{
new Row
{
{"Name", "Adam"},
{"Age", "13"},
{"Location","USA"}
},
new Row
{
{"Name", "James"},
{"Age", "19"},
{"Location", "Europe"}
}
};
Here is an example of how to serialize this object to JSON:
var result = JsonConvert.SerializeObject(table);
This code uses JSON.NET to serialize the Table object into a string.
This will produce the following JSON:
[{"Name":"Adam","Age":"13","Location":"USA"},{"Name":"James","Age":"19","Location":"Europe"}]
If you're going to be modeling a Table, you need more granularity :
public class Column
{
public string Name { get; set; }
public string Value { get; set; }
}
public class Row
{
public List<Column> Columns { get; set; }
}
public class Table
{
public List<Row> Rows { get; set; }
}
Then to create data:
var data = new Table()
{
new Row()
{
new Column()
{
Name = "Name",
Value = "Adam"
},
new Column()
{
Name = "Age",
Value = "13"
},
new Column()
{
Name = "Location",
Value = "USA"
}
},
new Row()
{
new Column()
{
Name = "Name",
Value = "James"
},
new Column()
{
Name = "Age",
Value = "19"
},
new Column()
{
Name = "Location",
Value = "Europe"
}
}
}
This would then serialize to
[
{
{
"Name":"Name",
"Value":"Adam"
},
{
"Name":"Age",
"Value":"13"
},
{
"Name":"Location",
"Value":"USA"
}
},
{
{
"Name":"Name",
"Value":"James"
},
{
"Name":"Age",
"Value":"19"
},
{
"Name":"Location",
"Value":"Europe"
}
}
]
Yes this is more complex, however I prefer because it gives you strongly typed representations of the parts of a Table, but also allows relatively easy access to the data.
#Yacoub-Massad has a good start, and it will get you what you need for the serialization. But I would suggest going all the way because being able to serialize and deserialize to strongly type objects can help catch compile time errors as well as warn you when serialization fails (ie bad data)

Categories