Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Using IDisposable to clean up temp files

I have a FileUploader class that can optionally be given a zip file which it extracts to a temporary location and returns the file paths.

From what I understood, implementing the IDisposable interface on the FileUploader class and using the Dispose method to remove all temp files would make the class clean itself up as soon as its reference fell out of context?

This doesnt seem to be the case though - can anyone explain how I might go about what Im trying to achieve?

UPDATE
To clarify, my code is:

    public ActionResult ImportFile()
    {
        FileUploader uploader = new FileUploader(ControllerContext, "file"); // where "file" is the posted form's file element

        uploader.SaveOrExtractFilesToTempLocation();

        foreach (string file in uploader.files)
        {
            try
            {
                 // do some stuff
            }
            catch (Exception err)
            {
                 // let the user know
            }
        }
        return View();
    }

Im trying to get the FileUploader to delete all temp files after the ImportFile() method has completed

like image 788
Jimbo Avatar asked Nov 05 '10 11:11

Jimbo


3 Answers

"fell out of context" is unclear; you would have to be doing:

using(var file = new FileUploader(...)) {
    // do the work here
}

Without using, there is no special handling. This then gets translated by the compiler into something like:

var file = new FileUploader(...);
IDisposable tmp = file;
try {
    // do the work here
} finally {
    if(tmp != null) tmp.Dispose();
}

and it is this that causes the deterministic cleanup.

like image 70
Marc Gravell Avatar answered Sep 30 '22 17:09

Marc Gravell


You'll need to implement IDisposable correctly. Like the class below.

using System.IO;

/// <summary>
/// Represents a temporary storage on file system.
/// </summary>
public sealed partial class TempStorage
     : IDisposable
{
    #region Constructor

    private TempStorage()
    {
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="TempStorage"/> class.
    /// </summary>
    /// <param name="path">The path to use as temp storage.</param>
    public TempStorage(string path)
    {
        this.Path = path;
        this.Clear();
        this.Create();
    }

    #endregion

    #region Properties

    private string Path
    {
        get;
        set;
    }

    #endregion

    #region Methods

    private void Create()
    {
        try
        {
            if (!Directory.Exists(this.Path))
            {
                Directory.CreateDirectory(this.Path);
            }
        }
        catch (IOException)
        {
        }
    }

    public void Clear()
    {
        try
        {
            if (Directory.Exists(this.Path))
            {
                Directory.Delete(this.Path, true);
            }
        }
        catch (IOException)
        {
        }
    }

    #endregion

    #region IDisposable

    /// <summary>
    /// An indicator whether this object is beeing actively disposed or not.
    /// </summary>
    private bool disposed;

    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    /// <summary>
    /// Throws an exception if something is tried to be done with an already disposed object.
    /// </summary>
    /// <remarks>
    /// All public methods of the class must first call this.
    /// </remarks>
    public void ThrowIfDisposed()
    {
        if (this.disposed)
        {
            throw new ObjectDisposedException(this.GetType().Name);
        }
    }

    /// <summary>
    /// Releases managed resources upon dispose.
    /// </summary>
    /// <remarks>
    /// All managed resources must be released in this
    /// method, so after disposing this object no other
    /// object is beeing referenced by it anymore.
    /// </remarks>
    private void ReleaseManagedResources()
    {
        this.Clear();
    }

    /// <summary>
    /// Releases unmanaged resources upon dispose.
    /// </summary>
    /// <remarks>
    /// All unmanaged resources must be released in this
    /// method, so after disposing this object no other
    /// object is beeing referenced by it anymore.
    /// </remarks>
    private void ReleaseUnmanagedResources()
    {
    }

    private void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            /* Release unmanaged ressources */
            this.ReleaseUnmanagedResources();

            if (disposing)
            {
                /* Release managed ressources */
                this.ReleaseManagedResources();
            }

            /* Set indicator that this object is disposed */
            this.disposed = true;
        }
    }

    #endregion
}

Then use the class inside a using-block in your main-method like this:

using(TempStorage myStorage = new TempStorage("C:\temp")
{
    // rest of the main method here...
}
like image 26
Oliver Friedrich Avatar answered Sep 30 '22 16:09

Oliver Friedrich


Dispose is only automatic if you wrap the context with the using keyword:

using (FileUploader uploader = new FileUploader(...))
    uploader.UploadFiles();
like image 25
Tim Robinson Avatar answered Sep 30 '22 16:09

Tim Robinson