Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion FollowingFileStream.APIdoc/docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"disableGitFeatures": false,
"disableDefaultFilter": false,
"properties": {
"TargetFramework": "netstandard2.0"
"TargetFramework": "netstandard2.1"
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFrameworks>netcoreapp3.0;netcoreapp2.2</TargetFrameworks>
<LangVersion>7.1</LangVersion>
<IsPackable>false</IsPackable>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion FollowingFileStream.Tests/FollowingFileStream.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<TargetFrameworks>netcoreapp3.0;netcoreapp2.2</TargetFrameworks>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
Expand Down
104 changes: 78 additions & 26 deletions FollowingFileStream/AsyncStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ namespace Manandre.IO
/// <summary>
///
/// </summary>
#pragma warning disable S3881
public abstract class AsyncStream : Stream
{
#if !NETSTANDARD1_3
Expand Down Expand Up @@ -286,8 +287,28 @@ public sealed override void Write(byte[] buffer, int offset, int count)
/// </exception>
public abstract override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken);

private bool disposed = false;
#if NETSTANDARD2_1
/// <summary>
/// Asynchronously releases the unmanaged resources used by the FollowingFileStream and optionally
/// releases the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.
///</param>
protected virtual ValueTask DisposeAsync(bool disposing) => default;

/// <summary>
/// Asynchronously releases all resources used by the AsyncStream.
/// </summary>
public sealed override ValueTask DisposeAsync() => DisposeAsync(true);

/// <summary>
/// Releases the unmanaged resources used by the FollowingFileStream and optionally
/// releases the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.
///</param>
protected sealed override void Dispose(bool disposing) => DisposeAsync(disposing).GetAwaiter().GetResult();
#else
/// <summary>
/// Releases the unmanaged resources used by the FollowingFileStream and optionally
/// releases the managed resources.
Expand All @@ -296,14 +317,10 @@ public sealed override void Write(byte[] buffer, int offset, int count)
///</param>
protected override void Dispose(bool disposing)
{
if (disposed)
return;

disposed = true;
// Call stream class implementation.
base.Dispose(disposing);
}

#endif
/// <summary>
/// Synchronized version of an async stream
/// </summary>
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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

/// <summary>
/// AsyncStream class extensions
/// </summary>
Expand Down
36 changes: 34 additions & 2 deletions FollowingFileStream/FollowingFileStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ public class FollowingFileStream : AsyncStream
/// </exception>
public FollowingFileStream(string path)
{
#pragma warning disable S2930
fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
#pragma warning restore S2930
}

/// <summary>
Expand Down Expand Up @@ -120,7 +122,9 @@ public FollowingFileStream(string path)
/// </exception>
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

Expand Down Expand Up @@ -324,8 +328,36 @@ private bool IsFileLockedForWriting()
return false;
}

bool disposed = false;
private bool disposed = false;

#if NETSTANDARD2_1
/// <summary>
/// Releases the unmanaged resources used by the FollowingFileStream and optionally
/// releases the managed resources.
/// </summary>
/// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.
///</param>
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
/// <summary>
/// Releases the unmanaged resources used by the FollowingFileStream and optionally
/// releases the managed resources.
Expand All @@ -347,7 +379,7 @@ protected override void Dispose(bool disposing)
// Call stream class implementation.
base.Dispose(disposing);
}

#endif
/// <summary>
/// Clears buffers for this stream and causes any buffered data to be written to the file.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion FollowingFileStream/FollowingFileStream.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Library</OutputType>
<TargetFrameworks>netstandard2.0;netstandard1.3</TargetFrameworks>
<TargetFrameworks>netstandard2.1;netstandard2.0;netstandard1.3</TargetFrameworks>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup>
Expand Down
22 changes: 21 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -191,4 +211,4 @@ jobs:
inputs:
PathtoPublish: '$(Build.SourcesDirectory)/FollowingFileStream.APIdoc/_site_pdf/FollowingFileStream.APIdoc_pdf.pdf'
ArtifactName: 'apidoc_pdf'
publishLocation: 'Container'
publishLocation: 'Container'