StringAsTempFile cleans up in a wider range of circumstances (not relying on finalizer running). Helps with #7 but still doesn't cover all cases.

This commit is contained in:
SteveSandersonMS
2016-11-30 15:04:08 +00:00
parent 9001c191c1
commit 2cffab14f6
2 changed files with 48 additions and 3 deletions

View File

@@ -9,6 +9,8 @@ namespace Microsoft.AspNetCore.NodeServices
public sealed class StringAsTempFile : IDisposable public sealed class StringAsTempFile : IDisposable
{ {
private bool _disposedValue; private bool _disposedValue;
private bool _hasDeletedTempFile;
private object _fileDeletionLock = new object();
/// <summary> /// <summary>
/// Create a new instance of <see cref="StringAsTempFile"/>. /// Create a new instance of <see cref="StringAsTempFile"/>.
@@ -18,6 +20,18 @@ namespace Microsoft.AspNetCore.NodeServices
{ {
FileName = Path.GetTempFileName(); FileName = Path.GetTempFileName();
File.WriteAllText(FileName, content); File.WriteAllText(FileName, content);
// Because .NET finalizers don't reliably run when the process is terminating, also
// add event handlers for other shutdown scenarios.
#if NET451
AppDomain.CurrentDomain.ProcessExit += HandleProcessExit;
AppDomain.CurrentDomain.DomainUnload += HandleProcessExit;
#else
// Note that this still doesn't capture SIGKILL (at least on macOS) - there doesn't
// appear to be a way of doing that. So in that case, the temporary file will be
// left behind.
System.Runtime.Loader.AssemblyLoadContext.Default.Unloading += HandleAssemblyUnloading;
#endif
} }
/// <summary> /// <summary>
@@ -40,15 +54,45 @@ namespace Microsoft.AspNetCore.NodeServices
{ {
if (disposing) if (disposing)
{ {
// Would dispose managed state here, if there was any // Dispose managed state
#if NET451
AppDomain.CurrentDomain.ProcessExit -= HandleProcessExit;
AppDomain.CurrentDomain.DomainUnload -= HandleProcessExit;
#else
System.Runtime.Loader.AssemblyLoadContext.Default.Unloading -= HandleAssemblyUnloading;
#endif
} }
File.Delete(FileName); EnsureTempFileDeleted();
_disposedValue = true; _disposedValue = true;
} }
} }
private void EnsureTempFileDeleted()
{
lock (_fileDeletionLock)
{
if (!_hasDeletedTempFile)
{
File.Delete(FileName);
_hasDeletedTempFile = true;
}
}
}
#if NET451
private void HandleProcessExit(object sender, EventArgs args)
{
EnsureTempFileDeleted();
}
#else
private void HandleAssemblyUnloading(System.Runtime.Loader.AssemblyLoadContext context)
{
EnsureTempFileDeleted();
}
#endif
/// <summary> /// <summary>
/// Implements the finalization part of the IDisposable pattern by calling Dispose(false). /// Implements the finalization part of the IDisposable pattern by calling Dispose(false).
/// </summary> /// </summary>

View File

@@ -31,7 +31,8 @@
"netstandard1.6": { "netstandard1.6": {
"dependencies": { "dependencies": {
"System.Diagnostics.Process": "4.3.0", "System.Diagnostics.Process": "4.3.0",
"System.IO.FileSystem.Watcher": "4.3.0" "System.IO.FileSystem.Watcher": "4.3.0",
"System.Runtime.Loader": "4.3.0"
} }
} }
}, },