2

我有一个 MVC3 Web 应用程序,用户通过该应用程序将文本文件上传到服务器上的 APP Data/Upload 文件夹。要求是将这些新上传的文件通过 FTP 传输到另一台服务器上的文件夹中。我在监视此上传文件夹的控制台应用程序中使用了 FileSystemWatcher。完全创建文件后,我将这个新生成的文件传输到 FTP 文件夹。

我担心的是,如果多个实例/用户从 Web 应用程序上传文件,我的控制台应用程序将如何处理这种情况?例如,我是否需要有一个队列并使用例如FileProcesser下面的方法在不同的线程上处理文件?

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

您的 FileSystemWatcher 已在其自己的线程上运行,并通知您的服务器代码发生了某些事情(在您的情况下创建了一个文件)。

如果事件 args 传递给您的代码,它会提供已创建的文件列表,您可以通过该文件列表进行处理。在您的进程运行期间引发的任何事件都将在另一个线程上运行或排队,具体取决于您的锁定策略。

不过,一般来说,当我收到一个事件时,我会从 Directory.GetFiles 中获取所有文件的列表并处理该列表。它保证我不会从 Watcher 事件中丢失任何文件。

如果这要在生产环境中运行,您将希望摆脱该控制台应用程序并让您的进程作为 Windows 服务运行。控制台应用程序太脆弱了,任何人都可以走到该控制台前终止它。

于 2012-11-01T22:05:44.440 回答