.NET FileSystemWatcher не запускает события Created и ConnectionStateChanged асинхронно - PullRequest
0 голосов
/ 11 января 2019

У меня есть событие fileSystemWatcher.Created, которое должно запускаться независимо от моего события fileSystemWatcher.ConnectionStateChanged. Я думаю, что это может быть проблема с многопоточностью, но я попробовал все различные асинхронные изменения, о которых мог подумать ... безрезультатно. Может ли кто-нибудь помочь?

Проблема: Если я скопирую много файлов (100 файлов) в каталог, на который настроен мой наблюдатель файловой системы, я увижу, что мой метод HandleFileEvent запускается. Пока метод HandleFileEvent срабатывает, метод HandleConnectStateChanged не будет запускаться.

Настройка: HandleFileEvent вызывает метод, который, в свою очередь, использует ADO.NET для выполнения хранимой процедуры и вставки файла данных fileName в базу данных. Точно так же метод HandleConnectStateChanged вызывает метод, который использует ADO.NET для запуска хранимой процедуры, чтобы обновить БД со значением даты для последней проверки соединения для каталога, на который указывает FileSystemWatcher.

Мне нужно обработать файлы, входящие в каталог (создано), я анализирую имя файла и передаю его в метод для использования в SqlConnection.

public class FileProcessor
{


    private void HandleFileEvent(object sender, FileSystemEventArgs e)
    {
        CallHandleFileEvent(sender, e);
    }
    private async void CallHandleFileEvent(object sender, FileSystemEventArgs e)
    {
        PartData partData = FileNameParser.ParseFileName(e.Name);
        Log("Event received: {0} Path: {1}", e.ChangeType, e.FullPath);

        Task.Run(() => SqlDataAccess.InsertOrUpdatePartDataInDatabase(partData));
        EventLogger.Log($"Handling file event for partData: {partData.SerialNumber} and the current thread is {Thread.CurrentThread.ManagedThreadId}");
    }


    private void HandleConnectStateChanged(object sender, ConnectionStateChangedEventArgs e)
    {
        CallHandleConnectStateChanged(sender, e);
    }

    private async void CallHandleConnectStateChanged(object sender, ConnectionStateChangedEventArgs e)
    {
        string connectionState = e.ConnectionState.ToString();
        if (connectionState == "Reconnected" || connectionState == "Connected")
        {
            EventLogger.Log($"Attempting to execute UpdateSystemDataLastAccessedAsync for : " +
                            $"{ConfigurationManager.AppSettings["SystemInstanceType"]} - " +
                            $"{ConfigurationManager.AppSettings["SystemInstanceTitle"]} - " +
                            $"{ConfigurationManager.AppSettings["SystemInstanceArea"]}" +
                            $" on thread {Thread.CurrentThread.ManagedThreadId} with a connection state of {e.ConnectionState}");

            Task.Run(() => SqlDataAccess.UpdateSystemDataLastAccessedAsync());

            EventLogger.Log($"Successfully executed UpdateSystemDataLastAccessedAsync for : " +
                            $"{ConfigurationManager.AppSettings["SystemInstanceType"]} - " +
                            $"{ConfigurationManager.AppSettings["SystemInstanceTitle"]} - " +
                            $"{ConfigurationManager.AppSettings["SystemInstanceArea"]}" + 
                            $" on thread {Thread.CurrentThread.ManagedThreadId} with a connection state of {e.ConnectionState}");
        }
    }

    private static void HandleRenameEvent(object sender, RenamedEventArgs e)
    {
        Log("Event received: {0} Path: {1} OldPath: {2}", e.ChangeType, e.FullPath, e.OldFullPath);
    }

    private static void HandleErrorEvent(object sender, ErrorEventArgs e)
    {
        var exception = e.GetException();

        Log("Error received: {0} ({1})", exception.Message, exception.GetType());
    }


    public void Watch(string[] args)
    {
        var checkConnectionInterval = TimeSpan.FromSeconds(Double.Parse(ConfigurationManager.AppSettings["CheckConnectionInterval"])); // Make this a low value for testing!
        var directory = ConfigurationManager.AppSettings["WatchDirectory"];
        var pattern = "*.*";

        var fileSystemWatcher = new NetFileSystemWatcher(checkConnectionInterval, directory, pattern);
        EventLogger.Log("Starting the watcher method");
        // These are the settings we used in our code
        fileSystemWatcher.IncludeSubdirectories = false;
        fileSystemWatcher.NotifyFilter = NotifyFilters.FileName;

        //Subscribe to all events.
        fileSystemWatcher.Created += HandleFileEvent;
        fileSystemWatcher.Error += HandleErrorEvent;

        //Enable the NetFileSystemWatcher events.
        fileSystemWatcher.EnableRaisingEvents = true;

        EventLogger.Log("stopped the watcher method");
    }
    public void ConnectionWatcher(string[] args)
    {
        var checkConnectionInterval = TimeSpan.FromSeconds(Double.Parse(ConfigurationManager.AppSettings["CheckConnectionInterval"])); // Make this a low value for testing!
        var directory = ConfigurationManager.AppSettings["WatchDirectory"];
        var pattern = "*.*";

        var fileSystemWatcher = new NetFileSystemWatcher(checkConnectionInterval, directory, pattern);
        EventLogger.Log("Starting the watcher method");
        // These are the settings we used in our code
        fileSystemWatcher.IncludeSubdirectories = false;
        fileSystemWatcher.NotifyFilter = NotifyFilters.FileName;

        fileSystemWatcher.Error += HandleErrorEvent;
        fileSystemWatcher.ConnectionStateChanged += HandleConnectStateChanged;

        //Enable the NetFileSystemWatcher events.
        fileSystemWatcher.EnableRaisingEvents = true;

        EventLogger.Log("stopped the watcher method");
    }

    public static void Stop()
    {
        // onstop code here
    }

    }
}

Этот класс содержит два моих метода ADO для запуска хранимых процедур

public class SqlDataAccess
{
    private static Logger logger = LogManager.GetCurrentClassLogger();

    public static void InsertOrUpdatePartDataInDatabase(PartData partData)
    {
        try
        {
            string connectionString = ConfigurationManager.ConnectionStrings["QMonitorDB"].ToString();
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                EventLogger.Log($"Attempting to execute InsertOrUpdatePartDataInDatabase for serial number: " +
                                $"{partData.SerialNumber} on " +
                                $"{ConfigurationManager.AppSettings["SystemInstanceType"]} - " +
                                $"{ConfigurationManager.AppSettings["SystemInstanceTitle"]} - " +
                                $"{ConfigurationManager.AppSettings["SystemInstanceArea"]}");

                SqlCommand cmd = new SqlCommand("Insert_Or_Update_PartData", conn)
                {
                    CommandType = CommandType.StoredProcedure
                };
                cmd.Parameters.AddWithValue("@applicationInstanceType", ConfigurationManager.AppSettings["ApplicationInstanceType"]);
                cmd.Parameters.AddWithValue("@pdaSerialNumber", partData.SerialNumber);
                cmd.Parameters.AddWithValue("@pdaPartType", partData.PartType);
                cmd.Parameters.AddWithValue("@pdaOperationID", partData.Operation);
                cmd.Parameters.AddWithValue("@pdaTimestamp", (!string.IsNullOrWhiteSpace(partData.TimeStamp) ? partData.TimeStamp : null));
                cmd.Parameters.AddWithValue("@pdaComponent", partData.Component);
                cmd.Parameters.AddWithValue("@pdaFeederSystem", partData.FeederSystemTitle);
                cmd.Parameters.AddWithValue("@pdaFileName", partData.FileName);
                cmd.Parameters.AddWithValue("@pdaStatus", partData.PartStatus);
                conn.Open();
                cmd.ExecuteNonQuery();
                EventLogger.Log($"successfully Executed InsertOrUpdatePartDataInDatabase for serial number: " +
                    $"{partData.SerialNumber} on " +
                    $"{ConfigurationManager.AppSettings["SystemInstanceType"]} - " +
                    $"{ConfigurationManager.AppSettings["SystemInstanceTitle"]} - " +
                    $"{ConfigurationManager.AppSettings["SystemInstanceArea"]}");
            }
        }
        catch (Exception e)
        {
            EventLogger.Log("Error inserting or updating part data into database. Exception: " + e);
            logger.Info($"Unable to insert or update part data in database. Error Message: {e}");
        }
    }

    public static void UpdateSystemDataLastAccessedAsync()
    {
        try
        {
            string connectionString = ConfigurationManager.ConnectionStrings["QMonitorDB"].ToString();
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                EventLogger.Log($"Attempting to execute UpdateSystemDataLastAccessed for " + 
                                $"{ConfigurationManager.AppSettings["SystemInstanceType"]} - " +
                                $"{ConfigurationManager.AppSettings["SystemInstanceTitle"]} - " +
                                $"{ConfigurationManager.AppSettings["SystemInstanceArea"]}");

                SqlCommand cmd = new SqlCommand("Insert_Or_Update_LastAccessed", conn)
                {
                    CommandType = CommandType.StoredProcedure
                };
                cmd.Parameters.AddWithValue("@sdaInstanceType", ConfigurationManager.AppSettings["SystemInstanceType"]);
                cmd.Parameters.AddWithValue("@sdaInstanceName", ConfigurationManager.AppSettings["SystemInstanceTitle"]);
                cmd.Parameters.AddWithValue("@sdaInstanceArea", ConfigurationManager.AppSettings["SystemInstanceArea"]);
                conn.Open();
                cmd.ExecuteNonQuery();
                EventLogger.Log($"Successfully executed UpdateSystemDataLastAccessed for " +
                                $"{ConfigurationManager.AppSettings["SystemInstanceType"]} - " +
                                $"{ConfigurationManager.AppSettings["SystemInstanceTitle"]} - " +
                                $"{ConfigurationManager.AppSettings["SystemInstanceArea"]}");
            }
        }
        catch (Exception e)
        {
            EventLogger.Log("Error updating/inserting system last access in database. Exception: " + e);
            logger.Info($"Unable to update system data into database. Error Message: {e}");
        }
    }
}

Вот мой Program.cs, который запускает службу и создает два экземпляра FileProcessor, один для обработки событий изменения состояния соединения, другой для обработки событий fileWatching.

 internal class Program
{
    public static void Main(string[] args)
    {
        EventLog eventLogger = new EventLog();
        eventLogger.Source = "QMonitor-FileMonitor service";
        if (!Environment.UserInteractive)
        {
            // running as service
            using (var service = new Service())
            {
                try
                {
                    ServiceBase.Run(service);
                }
                catch (Exception ex)
                {
                    eventLogger.WriteEntry(ex.Message);
                }
            }
        }
        else
        {
            // running as console app
            //FileProcessor.Watch(args);

            FileProcessor.Stop();
        }
    }
}

public class Service : ServiceBase
{
    public EventLog eventLogger = new EventLog();
    public const string ServiceTitle = "QMonitor-FileMonitor";

    public Service()
    {
        this.CanPauseAndContinue = true;
        this.AutoLog = false;

        eventLogger.Source = ServiceTitle;
        eventLogger.Log = "Application";
    }

    protected override void OnStart(string[] args)
    {
        //Uncomment/comment below to enable/disable service debugging on-start
        //Debugger.Launch();
        try
        {
            EventLogger.Log($"Starting the QMonitor watcher service for: {ConfigurationHelper.GetServiceNameAppConfig("ServiceInstanceTitle", "SystemInstanceTitle", "SystemInstanceArea")}");
            FileProcessor fileProcessor = new FileProcessor();
            FileProcessor connectionFileProcessor = new FileProcessor();
            fileProcessor.Watch(args);
            connectionFileProcessor.ConnectionWatcher(args);
            EventLogger.Log($"Started the QMonitor watcher service for: {ConfigurationHelper.GetServiceNameAppConfig("ServiceInstanceTitle", "SystemInstanceTitle", "SystemInstanceArea")}");
        }
        catch (Exception ex)
        {
            eventLogger.WriteEntry(ex.Message, EventLogEntryType.Error);
        }
        eventLogger.WriteEntry("Exiting the onStart");

    }

    protected override void OnStop()
    {
        eventLogger.WriteEntry("Called on onStop");
        FileProcessor.Stop();
        eventLogger.WriteEntry("onStop completed");
    }
}

Это должно быть асинхронно, запускать и забывать (я не жду никакой информации, возвращаемой из БД).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...