diff --git a/FollowingFileStream.APIdoc/docfx.json b/FollowingFileStream.APIdoc/docfx.json
index 269d171..868ac7e 100644
--- a/FollowingFileStream.APIdoc/docfx.json
+++ b/FollowingFileStream.APIdoc/docfx.json
@@ -17,7 +17,7 @@
"disableGitFeatures": false,
"disableDefaultFilter": false,
"properties": {
- "TargetFramework": "netstandard2.0"
+ "TargetFramework": "netstandard2.1"
}
}
],
diff --git a/FollowingFileStream.ConsoleTestTool/FollowingFileStream.ConsoleTestTool.csproj b/FollowingFileStream.ConsoleTestTool/FollowingFileStream.ConsoleTestTool.csproj
index c35198b..23d755e 100644
--- a/FollowingFileStream.ConsoleTestTool/FollowingFileStream.ConsoleTestTool.csproj
+++ b/FollowingFileStream.ConsoleTestTool/FollowingFileStream.ConsoleTestTool.csproj
@@ -6,7 +6,7 @@
Exe
- netcoreapp2.2
+ netcoreapp3.0;netcoreapp2.2
7.1
false
diff --git a/FollowingFileStream.Tests/FollowingFileStream.Tests.csproj b/FollowingFileStream.Tests/FollowingFileStream.Tests.csproj
index 793ab8a..21cdc27 100644
--- a/FollowingFileStream.Tests/FollowingFileStream.Tests.csproj
+++ b/FollowingFileStream.Tests/FollowingFileStream.Tests.csproj
@@ -1,6 +1,6 @@
- netcoreapp2.2
+ netcoreapp3.0;netcoreapp2.2
false
diff --git a/FollowingFileStream/AsyncStream.cs b/FollowingFileStream/AsyncStream.cs
index dcb12c8..134f7b3 100644
--- a/FollowingFileStream/AsyncStream.cs
+++ b/FollowingFileStream/AsyncStream.cs
@@ -9,6 +9,7 @@ namespace Manandre.IO
///
///
///
+ #pragma warning disable S3881
public abstract class AsyncStream : Stream
{
#if !NETSTANDARD1_3
@@ -286,8 +287,28 @@ public sealed override void Write(byte[] buffer, int offset, int count)
///
public abstract override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);
- private bool disposed = false;
+#if NETSTANDARD2_1
+ ///
+ /// Asynchronously releases the unmanaged resources used by the FollowingFileStream and optionally
+ /// releases the managed resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ ///
+ protected virtual ValueTask DisposeAsync(bool disposing) => default;
+
+ ///
+ /// Asynchronously releases all resources used by the AsyncStream.
+ ///
+ public sealed override ValueTask DisposeAsync() => DisposeAsync(true);
+ ///
+ /// Releases the unmanaged resources used by the FollowingFileStream and optionally
+ /// releases the managed resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ ///
+ protected sealed override void Dispose(bool disposing) => DisposeAsync(disposing).GetAwaiter().GetResult();
+#else
///
/// Releases the unmanaged resources used by the FollowingFileStream and optionally
/// releases the managed resources.
@@ -296,14 +317,10 @@ public sealed override void Write(byte[] buffer, int offset, int count)
///
protected override void Dispose(bool disposing)
{
- if (disposed)
- return;
-
- disposed = true;
// Call stream class implementation.
base.Dispose(disposing);
}
-
+#endif
///
/// Synchronized version of an async stream
///
@@ -400,26 +417,6 @@ public override int WriteTimeout
}
}
- protected override void Dispose(bool disposing)
- {
- try
- {
- // Explicitly pick up a potentially methodimpl'ed Dispose
- if (disposing)
- {
- cts.Cancel();
- using (locker.Lock())
- {
- ((IDisposable)_stream).Dispose();
- }
- }
- }
- finally
- {
- base.Dispose(disposing);
- }
- }
-
public override long Seek(long offset, SeekOrigin origin)
{
using (locker.Lock(cts.Token))
@@ -481,9 +478,64 @@ public override async Task FlushAsync(CancellationToken cancellationToken)
cancellationToken.ThrowIfCancellationRequested();
}
}
+
+ private bool disposed = false;
+
+#if NETSTANDARD2_1
+ protected override async ValueTask DisposeAsync(bool disposing)
+ {
+ if (disposed)
+ return;
+
+ try
+ {
+ // Explicitly pick up a potentially methodimpl'ed DisposeAsync
+ if (disposing)
+ {
+ cts.Cancel();
+ using (await locker.LockAsync())
+ {
+ await ((IAsyncDisposable)_stream).DisposeAsync();
+ }
+ }
+ }
+ finally
+ {
+ disposed = true;
+ await base.DisposeAsync(disposing);
+ }
+ }
+#else
+ protected override void Dispose(bool disposing)
+ {
+ if (disposed)
+ return;
+
+ try
+ {
+ // Explicitly pick up a potentially methodimpl'ed Dispose
+ if (disposing)
+ {
+ cts.Cancel();
+ using (locker.Lock())
+ {
+ ((IDisposable)_stream).Dispose();
+ }
+
+ }
+ }
+ finally
+ {
+ disposed = true;
+ base.Dispose(disposing);
+ }
+ }
+#endif
}
}
+ #pragma warning restore S3881
+
///
/// AsyncStream class extensions
///
diff --git a/FollowingFileStream/FollowingFileStream.cs b/FollowingFileStream/FollowingFileStream.cs
index c1d6153..d5a3b59 100644
--- a/FollowingFileStream/FollowingFileStream.cs
+++ b/FollowingFileStream/FollowingFileStream.cs
@@ -63,7 +63,9 @@ public class FollowingFileStream : AsyncStream
///
public FollowingFileStream(string path)
{
+#pragma warning disable S2930
fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
+#pragma warning restore S2930
}
///
@@ -120,7 +122,9 @@ public FollowingFileStream(string path)
///
public FollowingFileStream(string path, int bufferSize, bool useAsync)
{
+#pragma warning disable S2930
fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize, useAsync);
+#pragma warning restore S2930
}
#endregion
@@ -324,8 +328,36 @@ private bool IsFileLockedForWriting()
return false;
}
- bool disposed = false;
+ private bool disposed = false;
+#if NETSTANDARD2_1
+ ///
+ /// Releases the unmanaged resources used by the FollowingFileStream and optionally
+ /// releases the managed resources.
+ ///
+ /// true to release both managed and unmanaged resources; false to release only unmanaged resources.
+ ///
+ protected override async ValueTask DisposeAsync(bool disposing)
+ {
+ if (disposed)
+ return;
+
+ try
+ {
+ if (disposing)
+ {
+ cts.Cancel();
+ await fileStream.DisposeAsync();
+ }
+ }
+ finally
+ {
+ disposed = true;
+ // Call stream class implementation.
+ base.Dispose(disposing);
+ }
+ }
+#else
///
/// Releases the unmanaged resources used by the FollowingFileStream and optionally
/// releases the managed resources.
@@ -347,7 +379,7 @@ protected override void Dispose(bool disposing)
// Call stream class implementation.
base.Dispose(disposing);
}
-
+#endif
///
/// Clears buffers for this stream and causes any buffered data to be written to the file.
///
diff --git a/FollowingFileStream/FollowingFileStream.csproj b/FollowingFileStream/FollowingFileStream.csproj
index 51ed82b..32c443d 100644
--- a/FollowingFileStream/FollowingFileStream.csproj
+++ b/FollowingFileStream/FollowingFileStream.csproj
@@ -1,7 +1,7 @@
Library
- netstandard2.0;netstandard1.3
+ netstandard2.1;netstandard2.0;netstandard1.3
bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index cac8b84..8bb09ad 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -36,6 +36,16 @@ jobs:
projectVersion: '$(Build.BuildId)'
extraProperties: 'sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/coverage/coverage.opencover.xml'
+ - task: UseDotNet@2
+ displayName: 'Use dotnet sdk 2.x'
+ inputs:
+ version: 2.x
+
+ - task: UseDotNet@2
+ displayName: 'Use dotnet sdk 3.x'
+ inputs:
+ version: 3.x
+
- task: DotNetCoreCLI@2
displayName: Restore
inputs:
@@ -158,6 +168,16 @@ jobs:
command: 'install'
installPackageId: 'wkhtmltopdf'
+ - task: UseDotNet@2
+ displayName: 'Use dotnet sdk 2.x'
+ inputs:
+ version: 2.x
+
+ - task: UseDotNet@2
+ displayName: 'Use dotnet sdk 3.x'
+ inputs:
+ version: 3.x
+
# First restore to resolve external dependencies
- task: DotNetCoreCLI@2
displayName: Restore
@@ -191,4 +211,4 @@ jobs:
inputs:
PathtoPublish: '$(Build.SourcesDirectory)/FollowingFileStream.APIdoc/_site_pdf/FollowingFileStream.APIdoc_pdf.pdf'
ArtifactName: 'apidoc_pdf'
- publishLocation: 'Container'
\ No newline at end of file
+ publishLocation: 'Container'