Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle properly temporary files?

Tags:

c#

Problem: I have a web api which expose a method UploadFile, which will upload a file from a client to a specific directory of the server. The piece of code that handle the request and do the upload is the following:

var boundary = MultipartRequestHelper.GetBoundary(MediaTypeHeaderValue.Parse(Request.ContentType), _defaultFormOptions.MultipartBoundaryLengthLimit);

var reader = new MultipartReader(boundary, HttpContext.Request.Body);

try
{
    // Read the form data.
    var section = await reader.ReadNextSectionAsync();

    // This illustrates how to get the file names.
    while (section != null)
    {
        var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out ContentDispositionHeaderValue contentDisposition);
        if (hasContentDispositionHeader)
        {

            if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
            {
                targetFilePath = Path.Combine(root, contentDisposition.FileName.ToString());
                using (var targetStream = System.IO.File.Create(targetFilePath))
                {
                    await section.Body.CopyToAsync(targetStream);

                    //_logger.LogInformation($"Copied the uploaded file '{targetFilePath}'");
                }
            }

I always calledthis method using the following statement:

bool res = await importClient.UploadFileAsync(filePath);

where UploadFileAsync (which is on the client) build the request in this way:

var requestContent = new MultipartFormDataContent();
var array = File.ReadAllBytes(filePath);
var fileContent = new ByteArrayContent(array);
fileContent.Headers.ContentType =  MediaTypeHeaderValue.Parse("application/octet-stream");
requestContent.Add(fileContent, "file", Path.GetFileName(filePath));

As you can see, this method expect a file name/path to work, this means that the file must "exist" somewhere in the client machine. I've used this method without any problem until now. I have a very specific case in which i need to upload something needed on the server that the user don't want to save on his client.

Possible solutions:

  • The first thing that i thought was to manually create a file in the client, and after the upload delete it. However I'm not very happy with this solution cause i need to handle everything manually

  • I can use the System.IO.Path.GetTempFileName() method, which will create a file in the temporary directory, but i'm not quite sure how the cancellation of the files is handled

  • I can use the TempFileCollection, but it seems more or less a mix of the previous point. I can technically create this collection in a using statement to get rid of it when the upload is done

I'm inexperienced about these topics, so I'm not sure which solution could fit best this scenario

My requirements are that i need to be 100% sure that the file is deleted after the upload is done, and i would like the solution to be "async friendly", i.e. i need the whole process to keep going without problems.

EDIT: I see a little bit of confusion. My problem is not how to handle the files on the server. That part is not a problem. I need to handle "temporary" files on the client.

like image 668
Daniele Sartori Avatar asked Sep 03 '19 11:09

Daniele Sartori


People also ask

Is it OK to delete temp files?

If you're running low on storage space, you should consider deleting the temp files. You can either delete some or all of the temp files. Deleting them will free up space that you can use for other files and data. Keep in mind that you may not be able to delete temp files while the respective program is still running.


Video Answer


2 Answers

Once you write something on the disk you can't be 100% that you will able to delete it. Moreover, even if you delete the file, you can't be sure that file can't be recovered.

So you have to ask why I need to delete the file. If it contains some secret, keep it in memory. If you can't fit the file into memory, write it encrypted on the disk and keep only key in the memory.

If you relax 100% to 99%, I would go for creating a file with Path.GetTempFileName and deleting it in finally block.

If 99% is not enough but 99.98% is, I would store names of created temporary files in persistent storage and regularly check if they are deleted.

like image 153
Jakub Šturc Avatar answered Sep 23 '22 12:09

Jakub Šturc


For completition i'm writing the solution i used based on the suggestions i received here. Also the filename written as i did grant that statistically you won't have 2 temporary file with the same name

 try
 {
     string file = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".xml";
     tempFile = Path.GetFileName(file);
     using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write, FileShare.None))
     {
         XmlSerializer serializer = new XmlSerializer(typeof(FileTemplate));
         serializer.Serialize(fs, w.Template);
     }

 }
 catch(Exception ex)
 {

     logger.Error(ex.Message);
     //...
 }
 finally
 {
     //.... do stuff
     File.Delete(tempFile );
 }
like image 42
Daniele Sartori Avatar answered Sep 25 '22 12:09

Daniele Sartori