Лучшее использование службы Windows для повторения вызова программы

2

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

Мои вопросы таковы.

  • Каков наилучший способ повторить вызов программы в службе С# windows. Я думаю об использовании простого таймера? С чего начать и остановить таймер? это в самом сервисе или в программе, на которой работает моя служба?

  • Какой код должен быть включен в службу Windows для следующей функции


protected override void OnStart(string[] args)
{
//timer?
// MyProgram mp = new MyProgram();
}

Должен ли я просто запустить приложение с новым экземпляром, например, выше, или мне нужно добавить больше вещей?

Как я уже сказал, это мой первый раз для использования служб Windows.

EDIT:
Спасибо за ответы на все вопросы. Конечно, есть много разных способов сделать это, но я нашел, что лучший способ для меня - это один знак в качестве решения.

Спасибо за любую помощь!

Теги:
windows-services
service

3 ответа

3
Лучший ответ

Здесь шаблон, который вы можете использовать, обрабатывает проблемы с повторной попыткой с использованием таймера.

public partial class Service : ServiceBase{

    System.Timers.Timer timer;


 public Service()
    {

    timer = new System.Timers.Timer();
    //When autoreset is True there are reentrancy problme 
    timer.AutoReset = false;


    timer.Elapsed += new System.Timers.ElapsedEventHandler(DoStuff);
}

 protected override void OnStart(string[] args)
 {

     timer.Interval = 1;
     timer.Start();

    }

 private void DoStuff(object sender, System.Timers.ElapsedEventArgs e)
 {

    Collection stuff = GetData();
    LastChecked = DateTime.Now;

    foreach (Object item in stuff)
    {
          item.Dosomthing(); //Do somthing should only be called once
     }     


    TimeSpan ts = DateTime.Now.Subtract(LastChecked);
    TimeSpan MaxWaitTime = TimeSpan.FromMinutes(5);


    if (MaxWaitTime.Subtract(ts).CompareTo(TimeSpan.Zero) > -1)
        timer.Interval = MaxWaitTime.Subtract(ts).Milliseconds;
    else
        timer.Interval = 1;

    timer.Start();





 }

OnContinue OnPause и OnStop мелодично просты в разработке.

    protected override void OnPause()
    {

        base.OnPause();
        this.timer.Stop();



    }

    protected override void OnContinue()
    {
        base.OnContinue();
        this.timer.Interval = 1;
        this.timer.Start();

    }

    protected override void OnStop()
    {
        base.OnStop();
        this.timer.Stop();
    }
  • 0
    Это именно то, что я пытаюсь сделать. Спасибо.
5

Я использую AutoResetEvent с таймаутом:

while(!autoResetEvent.WaitOne(MY_MILLISECOND_WAIT))
{
     // do something
}

И когда я хочу остановиться, я просто устанавливаю autoResetEvent.

Таймер вреден для нескольких причин: Reentry.

OnStart(string[] args) создаст autoResetEvent.


Вот моя реализация его как PollingWorker:

public class PollingWorker : IDisposable
{

    private const int DEFAULT_INTERVAL_MS = 1000; // 1 second 
    private const int WAIT_INTERVAL = 20; // MS
    private Thread _labourer = null;
    private int _pollingIntervalMS = DEFAULT_INTERVAL_MS;
    private ParameterizedThreadStart _work = null;
    private bool _working = false;
    private object _state = new object();
    private AutoResetEvent _resetTimer = new AutoResetEvent(false);
    private bool _itsTimeToQuite = false;
    private bool _poked = false;
    private bool _isCurrentlyWorking = false;


    public string Name
    {
        get { return _labourer.Name; }
        set { _labourer.Name = value; }
    }

    public PollingWorker(int intervalMS, ParameterizedThreadStart work, object state):
        this(intervalMS, work, state, Guid.NewGuid().ToString())
    {

    }

    public PollingWorker(int intervalMS, ParameterizedThreadStart work, object state, string name)
    {
        _pollingIntervalMS = intervalMS;
        _labourer = new Thread(new ThreadStart(TryDoingSomeWork));
        _labourer.Name = name;
        _work = work;
    }

    public int PollingIntervalMS
    {
        get { return _pollingIntervalMS; }
        set 
        {
            _pollingIntervalMS = value; 
        }
    }

    public void StartWork()
    {
        StartWork(true);
    }

    public void StartWork(bool initialWait)
    {
        _working = true;
        _poked = !initialWait;
        _labourer.Start();
    }


    public void PauseWork()
    {
        _working = false;
    }

    public void Quit()
    {
        Quit(int.MaxValue);
    }

    public void Quit(int maximumWaitToFinishCurrentWorkMS)
    {
        int totalWait = 0;
        _itsTimeToQuite = true;
        _working = false;
        _resetTimer.Set();
        while (_isCurrentlyWorking && Thread.CurrentThread.Name != _labourer.Name) // in case Quit is called from Work 
        {
            Thread.Sleep(WAIT_INTERVAL);
            totalWait += WAIT_INTERVAL;
            if(totalWait>maximumWaitToFinishCurrentWorkMS)
                break;
        }
        Dispose();
    }

    // poke to wake up !
    public void Poke()
    {
        try
        {
            // if you call set on the same thread while it is not on waitOne
            // it does not work 
            if (Thread.CurrentThread.Name == this.Name)
                //_resetTimer.Set();
                _poked = true;
            else
                _resetTimer.Set();
        }
        catch
        { 
            // ignore any error with poking 
        }

    }

    private void TryDoingSomeWork()
    {
        while (!_itsTimeToQuite)
        {
            //Debug.WriteLine(string.Format("{0:ss fff}\t{1}\t{2}\t{3}", DateTime.Now, this.Name, string.Empty, string.Empty));
            if (!_poked) 
                _resetTimer.WaitOne(_pollingIntervalMS, false);

            _poked = false;

            // timed-out which means timer pulse, so do some work 
            if (_working)
            {
                _isCurrentlyWorking = true;
                _work(_state);
                _isCurrentlyWorking = false;
            }       
        }

    }

    public object State
    {
        get { return _state; }
        set 
        {
            lock (_state)
            {
                _state = value;                 
            }
        }
    }


    public bool Working
    {
        get { return _working; }
    }


    #region IDisposable Members

    public void Dispose()
    {
        try
        {
            _resetTimer.Close();
            _labourer.Abort();
        }
        catch
        { 
            // dont want to raise errors now 
            // so ignore especially threadabortexception!!
        }
    }

    #endregion
}
  • 0
    У меня сейчас нет голосов, но я с @Aliostad .
  • 0
    Благодаря @decyclone, я использовал этот подход в нескольких сервисах и классах и фактически абстрагировался в PollingWorker codeproject.com/KB/biztalk/Excellence.aspx
Показать ещё 1 комментарий
1

Создайте нить или что-то еще, не нужно таймера! В OnStart вы запускаете поток, а в OnStop вы можете остановить поток.

  • 0
    но я хочу позвонить, скажем, каждые 24 часа? Не означает ли это, что мне нужен таймер по крайней мере в моей основной программе?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню