Search code examples
c#asp.netfilestream

Using FileStream as a instance of a file. Passing between methods and working on the File


I am working with a file handling system that is to return a file to the user on prompt. The call goes to a endpoint MVC controller that calls a function in a helper class that returns a FileStream. The endpoint then returns the file with the ActionResult

File(FileStream, Mime.Type, FileName);

I am having issues in the helper class where I create and process the file.

My goals are:

1.Create the file

2.Write its contents

3.Run a third party program on the file (with a Process using a .exe file)

And to Log the results on most actions.

What I am trying to do is create a FileStream that creates the file and then pass the FileStream between methods to do different work like writing reading and running the 3rd party program. I am also using static file classes (System.IO.File) to logg to a logfile

Previously i just created the file and passed its path around and created new stream objects or used static classes to read/write to it but it felt kind of ugly. I feel using a object as a resource is more in line with object oriented programming.

Is my thinking here just wrong and working like this is just prone to errors?

Code;

private DataEntity db { get; }

    public string FolderPath { get; set; } //Directory for files created and log file
    public string LogPath { get; set; } //Logfile path

public FileStream CreateFile(int Id, bool signFile)
    {
        FileType fileObject = db.FileTypes.FirstOrDefault(li => li.ID == Id);
        string fileName = Path.Combine(FolderPath, fileObject.Name.Replace(" ", string.Empty) + ".lic");

        using (FileStream file = new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite, 4096, FileOptions.DeleteOnClose))
        {
            WriteFile(fileObject , file); //Method to create the file in directory

            SignOrFormatFile(fileObject , file, signFile); //Method to process the file with 3rd party .exe

            try
            {
                file.Flush();
                return file;
            }
            catch (Exception)
            {
                return null;
            }
        }
    }

public void WriteFile(FileObject file, FileStream fileStream)
    {
        fileStream.Flush();
        using (StreamWriter fileWriter = new StreamWriter(fileStream)) //Crashes here File is in use by other process
        {
            string header = fileObject.Headers; modules = fileObject.Modules;string footer = fileObject.Footer;



            fileWriter.WriteLine(header + modules + footer);
            fileWriter.Flush();
        } //the file disapears from directory when the streamWriter exits using scope
        string fileContent = System.IO.File.ReadAllText(file.Name); //Example of logging
        System.IO.File.AppendAllText(LogPath, "-----------\nData:\n\n" + fileContent);
    }

My problems in code are what the comments describe.

The streamWriter cant open the file as it thinks the file is used by another process.

The StreamWriter Removes the file when it exits scope.


Solution

  • fileStream.Flush();

    using (StreamWriter fileWriter = new StreamWriter(fileStream)) //Crashes here File is in use by other process

    There is really no need to flush the file here, since nothing is written yet. That flush is the only reason I can think of why creating the streamWriter would fail.

    //the file disapears from directory when the streamWriter exits using scope

    StreamWriter will take ownership of the stream, and dispose it when it is disposed. Since you asked for the file to be removed on close, this is expected behavior. If you want to opt out of this behavior you should use the constructor that takes a leaveopen parameter

    System.IO.File.ReadAllText(file.Name)

    Why are you reading what you just wrote? Just write the information to the log at the same time you write it to the file. You should be able to rely on the framework classes doing what they should do.

    SignOrFormatFile(fileObject , file, signFile);

    You may need to flush the file after it has been written. I'm unsure if streamwriter will flush when it is disposed. I would not be certain that this succeeds, it may depend on how the third party handles shared files. It is probably worth a try, but you may need to rewrite your method to close the file and then call the third party program.

    return file;

    Since the filestream is in a 'using' block, as it should, the file will be disposed. So your returned filestream object will be unusable. It is unclear what you intend to do with the result. I would have suggested returning a FileInfo object instead, but since you delete the file when it is closed, that would be valid either.