2012-04-17 2 views
0

Я пытаюсь получить данные из баз данных MSSQL и PostrgeSQL, чтобы регулярно заполнять их в базу данных MySQL (каждый час).C# Таймер для заполнения базы данных

Основываясь на проведенном мной исследовании, я хотел бы использовать таймер C# для этого. Однако я не совсем понимаю, как работает таймер. Я объявляю его в Page_Load, устанавливаю обработчик прошедшего события и вызываю метод из обработчика события.

protected void Page_Load(object sender, EventArgs e) 
{ 
    int duration = 100 * 60 * 5; //milliseconds * seconds * minutes 

    // Create a timer with a two second interval. 
    System.Timers.Timer timer = new System.Timers.Timer(duration); 

    // Hook up the Elapsed event for the timer. 
    timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); 

    timer.Enabled = true; 
} 

void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
{ 
    cf(); 
} 

Это работает, но ...

Проблема заключается в том, что таким образом таймер инициализируемого каждый раз, когда страница загружена. Как создать таймер, который инициализируется только один раз и работает с этого момента без повторной инициализации. Кроме того, как мне обрабатывать ситуацию, если таймер или метод терпят неудачу - выбрасывает исключение или сервер идет вниз? Как перезапустить таймер?

Любое понимание поможет! Заранее спасибо!

+0

Вам нужно сделать это в веб-проекте, кажется, неправильно делать такую ​​работу на веб-странице? Почему бы вам не создать приложение-приложение или консольное приложение? –

+0

Это веб-приложение. –

ответ

2

Вы не хотите делать это на веб-странице ASP.NET. Таймер ASP.NET предназначен для действий, которые происходят в течение всего жизненного цикла страницы, прежде чем перемещаться.

Если вы хотите сделать длинную текущую работу, как это (т.е. задачу один раз в час 24/7) вы бы гораздо лучше либо:

  • используя всегда на службу Windows с системой .Timer или
  • с использованием запланированной задачи Windows с расписанием 1 в час, которое запускает консольное приложение.

Другой вариант, так как вы задача, кажется, в значительной степени связана с передачей данных базы данных будет использовать что-то вроде SSIS или другого альтернативного ETL Tool (Extract-Transform-Load)

+0

Я не знаком ни с одним из них. Я не владею сервером, приложение размещено в другом месте. Что бы вы рекомендовали использовать в этом случае? –

+1

ОК. Вы не можете владеть сервером, но у вас есть возможность помещать на него приложения, отличные от веб-приложений. Если вы могли бы написать свой код в консольное приложение, которое просто выполнит ваш код в его методе 'main', а затем попросит администратора сервера настроить для вас запланированную задачу. –

+0

Лучший способ - использовать службу Windows, которую предлагает Eoin, но в вашем случае (вам нужно простое и быстрое решение). Я предложил ниже для инициализации таймера в global.asax. –

0

Инициализировать таймер Global .asax. Метод OnApplicationStart .. http://msdn.microsoft.com/en-us/library/1xaas8a2(v=vs.71).aspx

Аналогичный подход был описан здесь: http://www.west-wind.com/weblog/posts/2007/May/10/Forcing-an-ASPNET-Application-to-stay-alive

+0

Не делайте этого. в то время как он может работать. Веб-приложение не является подходящим проектом для такого рода задач. –

+0

Я бы сработал наверняка. Лучшее место было бы отделено фоном рабочего процесса (aka windows service). –

+0

Eoin, в чем главный недостаток этого подхода? –

0

Первая вещь, которую Вы могли бы хотеть, чтобы переместить вы Initializer в были вы объявляете все другие переменные. Затем вы можете загрузить на своей странице функцию, которая устанавливает интервал времени на время, необходимое для перехода к следующему часу. Вот что я сделал.

private void SetTimer() 
    { 
     timer1.Stop(); 
     var timeOfDay = DateTime.Now.TimeOfDay; 
     var nextFullHour = TimeSpan.FromHours(Math.Ceiling(timeOfDay.TotalHours)); 
     var delta = (nextFullHour - timeOfDay).TotalMilliseconds; 
     timer1.Interval = (int)delta; 
     timer1.Start(); 
    } 

предоставленный ваш сценарий может быть немного иным, но это может вам помочь.

1

Другие ответы касаются этого; Я ударю его по голове: Таймеры в ASP.NET - плохая идея.

Причина, связанная с жизненным циклом ASP.NET. Очень мало того, что экземпляр класса страницы (ваш код) создается для каждой загрузки страницы. После того, как результирующая страница будет выводиться как HTML в браузер клиента, экземпляр страницы оставляет видимость и уничтожается. Это означает, что ваш таймер, настроенный на запуск через час, будет ДЛИННЫМ, прежде чем его событие «Тик» будет когда-либо срабатывать; класс страницы может сохраняться в памяти менее чем за секунду для простых страниц.

Вы можете обойти это в некоторых случаях, сохранив Таймер в сеансе, который сохраняется до тех пор, пока соединение пользователя с сайтом происходит. Тем не менее, сеансы обычно тайм-аут намного раньше часа (15 минут - общий стандарт, сайты с большим количеством частных данных, например, онлайн-банкинг, тайм-аут так же быстро, как 5 минут).

Итак, повторяю, не используйте Таймеры в коде ASP.NET. Вместо этого вы можете использовать Таймер в службе Windows, запущенной на веб-сервере (или сервере приложений), который будет выполнять эти данные каждый час. Он может быть предоставлен информацией веб-приложением, например, с подключением пользователей, возможно, путем доступа к базе данных, используемой ASP.NET для аутентификации/авторизации учетных записей пользователей.

Если это просто веб-приложение, делающее обновление данных, я бы сохранил на странице скрытое поле или переменную JavaScript, указывающую на следующий раз, когда данные должны быть вытащены. Установите время ожидания JavaScript() для того времени, когда загружается документ, который запускает вызов AJAX на сервер для запуска обработчика событий, который обновляет MySql с данными из двух других БД. Всегда проверяйте, действительно ли это обновление данных должно происходить в вашем коде (возможно, сохраняя одно и то же значение в Session или ViewState), в противном случае тривиально превратить код вашей собственной страницы в механизм DoS с помощью подключаемого модуля, такого как FireBug или Chrome - в редакторе кода. Вы также можете запустить одно и то же событие из Page_Load, если прошло время обновления, охватывая себя в случаях, когда пользователь отключил JavaScript; обновление страницы пользователем приведет к появлению последних данных, если настало время сделать это.

+0

Спасибо! Я думаю, что я буду использовать консольное приложение и попытаюсь, чтобы мой хостер установил запланированную задачу. Основная проблема заключается в том, что я не хочу, чтобы обновление запускалось при участии пользователя (я не хочу, чтобы пользователь посещал страницу для обновления db). –

+1

... Тогда вы не хотите, чтобы эта логика находилась где-то рядом с вашим веб-слоем; использовать запланированную задачу или службу, поддерживающую таймер. – KeithS

+0

@ KeithS хорошо повторный. –

0

Один из вариантов, предполагающий, что вы ограничены отсутствием доступа к консольным приложениям или службам Windows или локальной системе для планирования задачи, выполните следующие действия. Мое решение для имитируемого таймера, когда нет таймеров.

Также вам нужно будет предположить, что таймер не должен срабатывать точно в час.

  1. Добавить таблицу в вашу базу данных, в которой зарегистрирован последний раз, когда была запущена работа по таймеру.
  2. После того, как страница закончила загрузку, проверьте, не было ли часа с момента последнего запуска вашего задания таймера.
  3. Если прошло более часа, выполните задание времени в этой точке.
  4. Когда задание времени начинает регистрироваться в базе данных, в которой оно было запущено, что предотвращает запуск другого задания.

Имейте в виду, что это очень пугающий способ моделирования таймера, когда у вас нет других параметров.

Смежные вопросы