等待来自SqlListener的事件

时间:2013-05-07 14:57:40

标签: c# events wait

我已经实现了一个SqlListener类,它使用SqlDependency来等待SQL数据库中的更改。在我的业务工作流程中的某一点,我需要等待数据库中出现的记录。找到请求的记录时,SqlListener会触发事件。这很好用。我可以通过输入While循环使其工作,并等到我检测到返回的事件。但这不是理想的设计。它使处理器旋转很多徒劳。

我想以更聪明的方式等待活动。我阅读了很多关于使用Task,NotificationDelegate,ManualResetEvent等的建议....但我无法将它们全部整合在一起。

简化示例可能会使其更容易理解。这是我当前的设置有效。但如果可能的话,我想摆脱丑陋的while循环。

private const int MaxWaitTime = 5;
private SqlListener<RecordType> _recordListener;
private RecordType _record;

/// <summary>
/// Request a record and wait until it is found.
/// </summary>
public RecordType GetRecordAwait(int requestedId)
{
    // Initiate listening for record
    _recordListener = new SqlListener<RecordType>();
    _recordListener.SqlModified += SqlListener_SqlModified;
    _recordListener.StartListening(requestedId);

    // Wait until record is found
    var startTime = DateTime.Now;
    while (_record == null && 
                 DateTime.Now.Subtract(startTime).TotalSeconds < MaxWaitTime)
    {
        Thread.Sleep(1);
    }
    // Stop listening
    _recordListener.SqlModified -= SqlListener_SqlModified;
    _recordListener.Dispose();
    _recordListener = null;

    // Return record
    return _record;
}

private void SqlListener_SqlModified(object sender, SqlModifiedArgs args)
{
    _record = (RecordType)args.Record;
}

2 个答案:

答案 0 :(得分:0)

您可以选择Timer和事件,而不是使用While。类似的东西:

public class ListenerWaiting
{
    public ListenerWaiting(int waitingTimeSeconds)
    {
        _waitSeconds = waitingTimeSeconds;
    }

    private int _waitSeconds;
    private System.Timers.Timer _timer;
    private Listener _listener;

    public event EventHandler<string> ListenerDone;

    public void Listen(int listeningPeriodSeconds)
    {
        _listener = new Listener(listeningPeriodSeconds * 1000);
        _listener.ListenerCompleted += ListenerListenerCompleted;
        _timer = new System.Timers.Timer(_waitSeconds * 1000) {Enabled = true};
        _timer.Elapsed += TimerElapsed;
    }

    void ListenerListenerCompleted(object sender, string e)
    {
        StopTimer();
        StopListener();
        if (ListenerDone != null)
            ListenerDone(this, "Waiting success! Message was: " + e);
    }

    void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        StopTimer();
        StopListener();
        if (ListenerDone != null)
            ListenerDone(this, "Waited longer than set, aborted waiting...");
    }

    private void StopTimer()
    {
        _timer.Stop();
        _timer.Elapsed -= TimerElapsed;
        _timer = null;
    }

    private void StopListener()
    {
        _listener.ListenerCompleted -= ListenerListenerCompleted;
        _listener = null;
    }
}

public class Listener
{
    private System.Timers.Timer _timer;
    private string _listeningPeriodSeconds;
    public event EventHandler<string> ListenerCompleted;

    public Listener(int listeningPeriodSeconds)
    {
        _listeningPeriodSeconds = listeningPeriodSeconds.ToString();
        _timer = new System.Timers.Timer(listeningPeriodSeconds) { Enabled = true };
        _timer.Elapsed += TimerElapsed;
    }

    private void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        _timer.Elapsed -= TimerElapsed;
        _timer = null;
        if (ListenerCompleted != null)
            ListenerCompleted(this, _listeningPeriodSeconds);
    }

}

...然后用:

消费它
    static void Main(string[] args)
    {
        var wait = new ListenerWaiting(5);
        wait.ListenerDone += WaitListenerDone;

        wait.Listen(3);

        Console.ReadLine();
    }

    static void WaitListenerDone(object sender, string e)
    {
        Console.WriteLine(e);
    }

我想我可以为课程找到更好的名字,但你会明白这一点;)

答案 1 :(得分:0)

事实上,解决方案比我最初想的更简单。当我改述我的问题并再次搜索时,我找到了它。在我的问题中已经提到的ManualResetEvent被证明是最简单的解决方法。

我所要做的就是添加一个ManualResetEvent并将其设置为wait; - )

    private const int MaxWaitTime = 5000;
    private SqlListener<RecordType> _recordListener;
    private RecordType _record;
    private readonly ManualResetEvent _recordWaiter = new ManualResetEvent(false);


    /// <summary>
    /// Request a record and wait until it is found.
    /// </summary>
    public RecordType GetRecordAwait(int requestedId)
    {
        // Initiate listening for record
        _recordListener = new SqlListener<RecordType>();
        _recordListener.SqlModified += SqlListener_SqlModified;
        _recordListener.StartListening(requestedId);

        // Wait synchronously until record is found
        _recordWaiter.WaitOne(MaxWaitTime);

        // Stop listening
        _recordListener.SqlModified -= SqlListener_SqlModified;
        _recordListener.Dispose();
        _recordListener = null;

        // Return record
        return _record;
    }

    private void SqlListener_SqlModified(object sender, SqlModifiedArgs args)
    {
        _record = (RecordType)args.Record;
        _recordWaiter.Set();
    }