2

I have an MVC3 web app via which users upload text files to the APP Data/Upload folder on a server. The requirement is to transfer these newly uploaded files to a folder on another server through FTP. I used a FileSystemWatcher in a Console Application which monitors this Upload folder. When a file is created fully, I transfer this newly generated file to the FTP folder.

My concern is that if multiple instances/users upload the file from the web application, how would my console application handle that scenario? For instance, do I need to have a queue and process the files on a different thread using for example the FileProcesser below?

public class FileProcessor
{
    private readonly Queue<string> files = new Queue<string>();
    private Thread thread;
    private readonly EventWaitHandle waitHandle = new AutoResetEvent(true);
    private static readonly object lockObject = new object();

    private volatile bool shouldStop = false;

    #region Helper methods

    private static bool IsFileUploadComplete(string path)
    {
        try
        {
            using (File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None))
            {
                return true;
            }
        }
        catch (IOException)
        {
            return false;
        }
    }

    private void ProcessFile(string path)
    {
        // Check if Result file has been completely created / uploaded
        int maximumProcessRetries = 5;
        int delayBeforeRetry = 5000; //in milliseconds, 5 seconds

        int attempts = 0;

        while (true)
        {
            if (IsFileUploadComplete(path))
            {
                //1. Open in existing IE process on Instrument Workstation
                var p = new System.Diagnostics.Process();
                var s = new System.Diagnostics.ProcessStartInfo(Settings1.Default.RSLSM_URL);
                s.UseShellExecute = true;
                s.WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal;
                p.StartInfo = s;
                p.Start();

                //2. Open in new IE process on Instrument workstation
                //System.Diagnostics.Process.Start("IEXPLORE.EXE", "www.yahoo.com");

                break;
            }
            attempts += 1;
            if (attempts >= maximumProcessRetries)
            {
                // Log error and send out notifications to RSLMS Database or Email RSLMS Admin group?
                break;
            }
            Thread.Sleep(delayBeforeRetry);
        }

        // Add any logic after the file has been processed
        //File.Delete(path);
    }

    private void Work()
    {
        while (!shouldStop)
        {
            string path = String.Empty;
            lock (lockObject)
            {
                if (files.Count > 0)
                {
                    path = files.Dequeue();
                }
            }

            if (!String.IsNullOrEmpty(path))
            {
                // Process the file
                ProcessFile(path);
            }
            else
            {
                // If no files are left to process then wait
                waitHandle.WaitOne();
            }
        }
    }

    #endregion

    #region Methods

    public void EnqueueFile(string path)
    {
        // Queue the file
        lock (lockObject)
        {
            files.Enqueue(path);
        }

        // Initialize and start the worker thread when the first file is queued
        // or when it has been stopped and thus terminated.
        if (thread == null || shouldStop)
        {
            thread = new Thread(new ThreadStart(Work));
            thread.Start();
        }
        // If the thread is waiting then start it
        else if (thread.ThreadState == ThreadState.WaitSleepJoin)
        {
            waitHandle.Set();
        }
    }

    public void StopProcessing()
    {
        shouldStop = true;
    }

    #endregion
}
4

1 に答える 1

1

Your FileSystemWatcher is off running on its own thread and notifies your server code that something has happened (in your case a file was created).

In the event args passed to your code it provides a list of files that were created and you process through that list of files. Any events raised during your process running will either be run on another thread or queued up depending on your locking strategy.

Generally, though, when I get an event I get a list of all files from Directory.GetFiles and process that list. It guarantees that I don't lose any files from the Watcher events.

If this is going to run in production, you'll want to get rid of that console application and make your process run as a Windows Service. A console application is too fragile and can be terminated by anyone that walks up to that console.

于 2012-11-01T22:05:44.440 に答える