diff --git a/CHANGELOG.md b/CHANGELOG.md
index c36208dc3..82eb41f30 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
Release Notes
====
+# 12-30-2024
+DotNext.IO 5.17.1
+* Fixed `EndOfStreamException` caused by async read from `PoolingBufferedStream`
+
# 12-29-2024
This release is aimed to improve AOT compatibility. All the examples in the repo are now AOT compatible.
DotNext 5.17.0
diff --git a/README.md b/README.md
index 9cf9fed9b..b74fba780 100644
--- a/README.md
+++ b/README.md
@@ -66,7 +66,7 @@ This release is aimed to improve AOT compatibility. All the examples in the repo
DotNext.Threading 5.17.0
* Improved AOT support
-DotNext.IO 5.17.0
+DotNext.IO 5.17.1
* Reduced memory consumption for applications that use `FileReader` and `FileWriter` classes. These classes are now implemented by using lazy buffer pattern. It means that the different instances can reuse the same buffer taken from the pool
* Fixed [255](https://github.com/dotnet/dotNext/issues/255)
* `PoolingBufferedStream` is introduced to replace classic [BufferedStream](https://learn.microsoft.com/en-us/dotnet/api/system.io.bufferedstream). This class supports memory pooling and implements lazy buffer pattern
diff --git a/src/DotNext.IO/DotNext.IO.csproj b/src/DotNext.IO/DotNext.IO.csproj
index 4bda5105b..6d38e5a76 100644
--- a/src/DotNext.IO/DotNext.IO.csproj
+++ b/src/DotNext.IO/DotNext.IO.csproj
@@ -11,7 +11,7 @@
.NET Foundation and Contributors
.NEXT Family of Libraries
- 5.17.0
+ 5.17.1
DotNext.IO
MIT
diff --git a/src/DotNext.IO/IO/PoolingBufferedStream.cs b/src/DotNext.IO/IO/PoolingBufferedStream.cs
index 4013f348a..97cec0186 100644
--- a/src/DotNext.IO/IO/PoolingBufferedStream.cs
+++ b/src/DotNext.IO/IO/PoolingBufferedStream.cs
@@ -477,7 +477,7 @@ public override ValueTask ReadAsync(Memory data, CancellationToken to
{
task = ValueTask.FromException(new NotSupportedException());
}
- else if (buffer.IsEmpty)
+ else if (data.IsEmpty)
{
task = new(result: 0);
}
diff --git a/src/DotNext.Tests/IO/PoolingBufferedStreamTests.cs b/src/DotNext.Tests/IO/PoolingBufferedStreamTests.cs
index 6747a9b96..331e3d0c5 100644
--- a/src/DotNext.Tests/IO/PoolingBufferedStreamTests.cs
+++ b/src/DotNext.Tests/IO/PoolingBufferedStreamTests.cs
@@ -341,4 +341,36 @@ public static void ResetBuffer()
bufferedStream.Reset();
False(bufferedStream.HasBufferedDataToWrite);
}
+
+ [Fact]
+ public static void ReadFromFile()
+ {
+ var expected = RandomBytes(4096);
+ using var handle = File.OpenHandle(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), FileMode.CreateNew, FileAccess.ReadWrite,
+ options: FileOptions.DeleteOnClose);
+ RandomAccess.Write(handle, expected, fileOffset: 0L);
+ RandomAccess.FlushToDisk(handle);
+
+ using var bufferedStream = new PoolingBufferedStream(handle.AsUnbufferedStream(FileAccess.Read)) { MaxBufferSize = 128 };
+ var actual = new byte[expected.Length];
+ bufferedStream.ReadExactly(actual);
+
+ Equal(expected, actual);
+ }
+
+ [Fact]
+ public static async Task ReadFromFileAsync()
+ {
+ var expected = RandomBytes(4096);
+ using var handle = File.OpenHandle(Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()), FileMode.CreateNew, FileAccess.ReadWrite,
+ options: FileOptions.DeleteOnClose | FileOptions.Asynchronous);
+ await RandomAccess.WriteAsync(handle, expected, fileOffset: 0L);
+ RandomAccess.FlushToDisk(handle);
+
+ await using var bufferedStream = new PoolingBufferedStream(handle.AsUnbufferedStream(FileAccess.Read)) { MaxBufferSize = 128 };
+ var actual = new byte[expected.Length];
+ await bufferedStream.ReadExactlyAsync(actual);
+
+ Equal(expected, actual);
+ }
}
\ No newline at end of file
diff --git a/src/examples/HyParViewPeer/Program.cs b/src/examples/HyParViewPeer/Program.cs
index ee214c4bd..612238c73 100644
--- a/src/examples/HyParViewPeer/Program.cs
+++ b/src/examples/HyParViewPeer/Program.cs
@@ -132,8 +132,8 @@ static Task PrintNeighborsAsync(HttpContext context)
file sealed class RumorSender : Disposable, IRumorSender
{
- internal const string SenderAddressHeader = "X-Sender-Address";
- internal const string SenderIdHeader = "X-Rumor-ID";
+ private const string SenderAddressHeader = "X-Sender-Address";
+ private const string SenderIdHeader = "X-Rumor-ID";
internal const string RumorResource = "/rumor";
internal const string BroadcastResource = "/broadcast";