Reputation: 2923
I'm building a service to return HTML, a couple strings and JSON data into a JSON structure returned to the browser.
The JSON data is generic, and is generated directly from SQL Server. It could have any number of fields, so I don't have any sort of object to serialize in advance.
Here's my code (as small as I can make it)
[DataContract]
internal class message {
[DataMember]
public string html;
[DataMember]
public string status;
[DataMember]
public string title;
[DataMember]
public string data;
}
public static string Serialize(TType instance) {
var serializer = new DataContractJsonSerializer(typeof(TType));
using (var stream = new MemoryStream()) {
serializer.WriteObject(stream, instance);
return Encoding.UTF8.GetString(stream.ToArray());
}
}
message msg = new message();
msg.html = "<h1>Hello</h1><p>World</p>";
msg.title = "Test";
msg.status = "Success";
msg.data = "{['id':1,'name':'William']['id':2,'name':'Dylan']}'"; // NOTE JSON constructed elsewhere
string json = JSONSerializer<message>.Serialize(msg);
This outputs data as a string, for example
{
"data": "{['id':1,'name':'William'],['id':2,'name':'Dylan']}'",
"html": "<h1>Hello<\/h1><p>World<\/p>",
"status": "Success",
"title": "Test"
}
However, I want "data" to the array of objects that I provided.
{
"data": {
['id': 1, 'name': 'William'],['id': 2, 'name': 'Dylan']
},
"html": "<h1>Hello<\/h1><p>World<\/p>",
"status": "Success",
"title": "Test"
}
Some of the options I'm considering
Ideally, I'd like to find an "official" way to do this that avoids the risk of mal-formed JSON.
-- UPDATE Following Sangeeth's suggestion to use "dynamic" objects. Here's an updated sample, while it does return 2 objects, the are empty.
// NOTE JSON now valid.
string strJSON = "[ { \"id\": 1, \"name\": \"William\" }, { \"id\": 2, \"name\": \"Dylan\" } ] ";
// NOTE: data shows 2 empty objects here.
dynamic data = JSONSerializer<dynamic>.DeSerialize(strJSON);
message msg = new message();
msg.html = "<h1>Hello</h1><p>World</p>";
msg.title = "Test";
msg.status = "Success";
msg.data = data;
string json = JSONSerializer<message>.Serialize(msg);
Console.Write(json);
Outputs two empty objects.
{"data":[{},{}],"html":"<h1>Hello<\/h1><p>World<\/p>","status":"Success","title":"Test"}
Upvotes: 0
Views: 2197
Reputation: 1512
If I got your point, You don't have a concreate class to serialize or de-serilize your data because it is dynamic.
Then what I can suggest is to use the C#'s built in support for 'dynamic
' types. Once you convert a JSON string to dynamic, It became an instance of dynamic and will be considered as an object. This object you can pass to your browser
plan string
from your databasedynamic
' object. A dynamic object can have any structure and datatypeHere's an example
A. Deserialize to dynamic
dynamic results = JsonConvert.DeserializeObject<dynamic>(YOUR_JSON);
B. Add one more item to your response class/contract
[DataContract]
internal class message {
[DataMember]
public dynamic data;
}
C. Return to client
message msg = new message();
msg.data = results;
Try this
using Newtonsoft.Json;
public class Program
{
public static void Main(string[] args)
{
// NOTE JSON now valid.
string strJSON = "[ { \"id\": 1, \"name\": \"William\" }, { \"id\": 2, \"name\": \"Dylan\" } ] ";
dynamic results = JsonConvert.DeserializeObject<dynamic>(strJSON);
var msg = new Message();
msg.Html = "<h1>Hello</h1><p>World</p>";
msg.Title = "Test";
msg.Status = "Success";
msg.Data = results;
string output = JsonConvert.SerializeObject(msg);
Console.WriteLine(output);
Console.ReadLine();
}
public class Message
{
public string Html { get; set; }
public string Title { get; set; }
public string Status { get; set; }
public dynamic Data { get; set; }
}
}
Output
Upvotes: 1
Reputation: 67380
but I don't want to double memory, the data could have thousands of rows
Any kind of re-serializing would create a new string object. In fact, to feed your child JSON to the master one correctly, first you'd need to de-serialize it, so it's actually closer to three times.
So what you'll need to do is get over the fear of creating malformed JSON by hand, and stream your pieces correctly:
[HttpGet]
public async Task Get()
{
Response.ContentType = "application/json";
StreamWriter sw;
await using ((sw = new StreamWriter(Response.Body)).ConfigureAwait(false))
{
// compose your JSON here using sw.WriteLineAsync
await sw.FlushAsync().ConfigureAwait(false);
}
}
Upvotes: 0