JsonReader and resetting the input stream

Oct 29, 2009 at 10:06 AM

You sometimes want to read a JSON record and look for primarily values, then decide to fully parse it. This requires to be able to reset the current stream to the start.

            using (JsonReader jsonReader = new JsonTextReader(stream)
            {
                while (jsonReader.Read())
                { //.... }

                // Reset the reader to the begining:
                stream.BaseStream.Position = 0; // Will fail! 
                stream.DiscardBufferedData();


            using (JsonReader jsonReader = new JsonTextReader(stream)

                while (jsonReader.Read())
{ //.... }

However this will fail because stream is disposed when jsonReader closes. This can be implemented with the help of a JsonReaderSettings class which would mimic the XmlReaderSettings class with its property  'CloseInput' regulating if the stream should be closed or not (by default CloseInput is set to true, the the default behavior remains the same).

Here's a sketch of how JsonTextReader.cs would look like:

    public class JsonReaderSettings
    {
        public bool CloseInput { get; set; }
        
        public JsonReaderSettings()
        {
            this.CloseInput = true; // Default value
        }


A constructor with a JsonReaderSettings argument:
    private JsonReaderSettings _settings = new JsonReaderSettings();
    public JsonTextReader(TextReader reader, JsonReaderSettings settings)
    {
        if (reader == null)
            throw new ArgumentNullException("reader");

        _reader = reader;
        _buffer = new StringBuffer(4096);
        _currentLineNumber = 1;

        _settings = settings;
    }

And the test on the Close() method:

    public override void Close()
    {
      base.Close();

      #region ericdes: Implement setting.CloseInput
      if (_reader != null)
      {
          if (_settings.CloseInput)
            _reader.Close();
      }
      #endregion

      if (_buffer != null)
        _buffer.Clear();
    }

How we can use this new code:

            JsonReaderSettings jsonReaderSettings = new JsonReaderSettings();
            jsonReaderSettings.CloseInput = false; // Necessary because disposing the jsonReader closes the stream input.

            using (JsonReader jsonReader = new JsonTextReader(stream, jsonReaderSettings))
            {
                while (jsonReader.Read())
                { // .... }

                // Reset the reader to the begining, for future use:
                stream.BaseStream.Position = 0; 
                stream.DiscardBufferedData();

            using (XmlReader xmlReader = XmlReader.Create(stream)) // this is the same stream, set back to its beginning.
            {
                while (xmlReader.Read())
                { // .... }


Eric Desgranges
Tela-Group
http://tela-group.com

 

Coordinator
Oct 31, 2009 at 8:52 AM
Edited Oct 31, 2009 at 9:16 AM

Why don't you just not wrap the reader in a using statement - close won't be called on JsonReader.

Nov 2, 2009 at 6:20 AM
Edited Nov 2, 2009 at 6:21 AM

In my particular design both stream readings are in a different method. And your comment is valid, I could just dispose the Json readers and stream manually. And this also made me realize about a possible issue of leaving the stream open if I decide not to read further after the primarily reading. This has to be taken care manually. So we are left with some manual disposings with both options, using the 'using' statement or not. Unless I'm missing something, I'm still wondering why Microsoft with its XmlReader decided to go with the close input flag.

Eric.

Coordinator
Nov 2, 2009 at 7:28 AM

I would guess they wanted to give ultimate control over how an XmlReader behaved through settings rather than code. Useful once in a blue moon.