William Walseth
William Walseth

Reputation: 2923

How to Merge 2 JSON strings C#

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

Answers (2)

Alen Smith
Alen Smith

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

  1. Imagine you got data as plan string from your database
  2. De-Serialize it down to a 'dynamic' object. A dynamic object can have any structure and datatype
  3. Once you de-serialize it to a dynamic variable, You can attach the instance to your server response and sent to client. It will be in an object form when it reaches the client

Here'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;

UPDATE AFTER COMMENTS

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

enter image description here

Upvotes: 1

Blindy
Blindy

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

Related Questions