2013-05-07 64 views
1

我已經實現了一個使用SqlDependency等待SQL數據庫中的更改的SqlListener類。在我的業務流程中,我需要等待數據庫中出現一條記錄。當找到請求的記錄時,SqlListener觸發一個事件。這工作正常。我可以通過輸入一個While循環使其工作,並等待直到檢測到返回的事件。但這不是理想的設計。這讓處理器變得徒勞無功。等待來自SqlListener的事件

我想以更聰明的方式等待事件。我閱讀了很多有關使用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; 
} 

回答

0

在事實上,解決方案比我想象的更簡單。當我重新提出我的問題並再次搜索時,我發現了它。在我的問題中已經提到的ManualResetEvent結果是最簡單的解決方法。

我所要做的就是添加的ManualResetEvent並將其設置爲等待;-)

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(); 
    } 
0

代替使用While,您可以使用Timer和事件。喜歡的東西:

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); 
    } 

我想我能找到更好的類的名字,但你會得到的想法;)

+0

謝謝你的關心,但是你的建議使我困惑。這真的是我的問題的解決方案嗎?我的絆腳石是以「同步方式」等待事件。我知道我可以添加一個定時器來等待而不是while循環,但是定時器結果和事件結果仍然會在事件處理程序WaitListenerDone中出現。這將如何幫助我繼續進行主要方法的連續工作流? – 2013-05-13 08:00:44