Search code examples
c#asp.net-web-apijsonstreampushstreamcontent

JSON object creation PushStreamContent


I have asp.net web api and has a HTTPResponseMessage and the api method name GetPersonDataStream, which actually stream each person object as a json. So when I see the result the actual Data has been constructed like two seperate object's with no comma in between the two objects are it isn't constructed as I required.

Actual streamed data : {"Name":"Ram","Age":30}{"Name":"Sam","Age":32}.

But I want this to streamed as a proper JSON as:

{"response": [ {"Name":"Ram","Age":30}, {"Name":"Sam","Age":32} ]}

Is there a way we can achieve it. Below is the code I use to stream the data because the number of records will be in millions and i don't want to create all the objects at once and then streaming it, because that may be lead to Syste.OutOfMemory Exception . So is there a way we could edit/construct the object before streaming it. If yes, how can i achieve it.

CODE:

    [HttpGet]
    [Route("GetPersonDataStream")]
    public HttpResponseMessage GetPersonDataStream()
    {
        List<Person> ps = new List<Person>();
        Person p1 = new Person();
        p1.Name = "Ram";
        p1.Age = 30;

        Person p2 = new Person();
        p2.Name = "Sam";
        p2.Age = 32;

        ps.Add(p1);
        ps.Add(p2);

        var response = this.Request.CreateResponse(HttpStatusCode.OK);

        response.Content =
            new PushStreamContent((stream, content, context) =>
            {
                foreach (var item in ps)
                {
                    //var result = _clmmgr.GetApprovedCCRDetail(item.ccr_id, liccrDetails);
                    var serializer = new JsonSerializer();
                    using (var writer = new StreamWriter(stream))
                    {
                        serializer.Serialize(writer, item);
                        stream.Flush();
                    }
                }
            });

        return response;
    }

    public class Person
    {
        public string Name {get;set;}
        public int Age { get; set; }
    }

Solution

  • With JSON.NET and it's JsonTextWriter, you can wrap all the items in a JSON object with an array and still stream the result without building everything in memory first.

    response.Content =
        new PushStreamContent((stream, content, context) =>
        {
            using (var sw = new StreamWriter(stream))
            using (var jsonWriter = new JsonTextWriter(sw))
            {
                jsonWriter.WriteStartObject();
                {
                    jsonWriter.WritePropertyName("response");
                    jsonWriter.WriteStartArray();
                    {
                        foreach (var item in ps)
                        {
                            var jObject = JObject.FromObject(item);
                            jObject.WriteTo(jsonWriter);
                        }
                    }
                    jsonWriter.WriteEndArray();
                }
                jsonWriter.WriteEndObject();
            }
        });