Search code examples
c#file-ioasync-awaittaskstreamreader

Accessing the same files from multiple tasks


I have many files on disk that I need to read and deserialize, If i try to access these files using a streamreader from multiple tasks I get the following exception:

System.ObjectDisposedException: Cannot access a disposed object
System.Runtime.InteropServices.SafeHandle.DangerousReleaseInternal(bool dispose)SafeHandle.cs:193
System.Runtime.InteropServices.SafeHandle.DangerousRelease()SafeHandle.cs:142
System.IO.FileStream.Dispose(bool disposing)FileStream.cs:913
System.IO.IsolatedStorage.IsolatedStorageFileStream.Dispose(bool disposing)IsolatedStorageFileStream.cs:250
System.IO.Stream.Close()stream.cs:248
 System.IO.StreamReader.Dispose(bool disposing)streamreader.cs:296
System.IO.TextReader.Dispose()textreader.cs:78
System.IO.TextReader.Dispose()(wrapper remoting-invoke-with-check)
.FileServices.StreamReaderWrapper.Dispose()
.FileServices.IsolatedSerializer.<DeserializeAsync>d__9<T>.MoveNext()

Here is the code:

public async Task<T> DeserializeAsync<T>(string path)
{
    T result = default(T);
    if (!_fileRepository.FileManager.FileExists(path)) { return result; }

    using (var streamReader = _streamReader.GetNew(_fileRepository.FileManager.OpenFile(
            path, FileMode.Open, FileAccess.Read, FileShare.Read)))
    {
        var contents = await streamReader.ReadToEndAsync();
        result = _jsonSerializer.DeserializeFromString<T>(contents, Encoding.UTF8);
        streamReader.Dispose();
    }
    return result;
}

What am I doing wrong here?

    /// <summary>
/// Wrapper to allow testing with StreamReader
/// </summary>
public class StreamReaderWrapper : IStreamReader
{
    private StreamReader _streamReader;

    public void Dispose()
    {
        if (_streamReader != null)
        {
            _streamReader.Dispose();
            _streamReader = null;
        }
    }

    public IStreamReader GetNew(Stream stream)
    {
        Dispose();
        _streamReader = new StreamReader(stream);
        return this;
    }

    public string ReadToEnd()
    {
       return _streamReader.ReadToEnd();
    }

    public Task<string> ReadToEndAsync()
    {
        return _streamReader.ReadToEndAsync();
    }
}

Solution

  • You are calling Dispose twice. The using statement will dispose your streamReader variable automatically after exiting the code block. But you are also explicitly calling streamReader.Dispose();

    Also, your StreamReaderWrapper.GetNew() should just return a new instance of the wrapper, otherwise threads will step on each other's toes