在x秒后触发事件,但在执行前也取消它

时间:2016-06-28 11:11:26

标签: c# asp.net asp.net-mvc asp.net-web-api asp.net-web-api2

我正在开发一个Web API(效果很好)。少了什么东西? 以下是Get操作的示例代码:

public IEnumerable<xxxx> Get()
{           
    IEnumerable<xxxx> yyyy = new List<xxxx>();
    //get yyyy from database
    timer = new Timer();
    timer.AutoReset = true;
    timer.Enabled = true;
    timer.Interval = 5000; //miliseconds
    timer.Elapsed += timer_Elapsed;
    timer.Start();
    return yyyy;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    //code to be executed when timer elapses...
}

因此,一旦收到请求,将初始化计时器并以5秒的间隔触发Elapsed事件。在下一个后续请求中,这将继续....

预期的行为是:

  1. 初始化请求-1
  2. 初始化计时器-1
  3. 如果在5秒内收到来自同一客户端的其他请求,则计时器不得触发已发生的事件。
  4. 如果在5秒内没有收到来自同一客户端的请求,则应该经过计时器并触发事件。
  5. 此外,计时器与客户无关。

    以下是与此相关的进一步业务情景.... 我正在开发一个Web API,它将在打开时被电子设备使用。只要电源可用,设备就会继续发送它的ON状态。一旦用户关闭交换机,对服务器的请求就会停止。

    无论设备是ON还是OFF,这些状态都会更新到数据库中。现在更棘手的部分是确定何时关闭设备(很复杂,因为如果设备停止发送任何请求,服务器不知道任何事情)。因此,对于每个设备,都有一个单独的计时器。

2 个答案:

答案 0 :(得分:0)

首先,谢谢@Patrick Hofman指导我并开箱即用...... 我在其中实现了一个具有静态属性的类。

public class DeviceContainer
{
    public static List<DevTimer> timers=new List<DevTimer>();
}
public class DevTimer:Timer
{
    public string Identifier {get; set;}
    public bool IsInUse{get; set;}
}

然后在上面的代码中(问题),我做了以下更改:

public IEnumerable<xxxx> Get(string Id)
{        
    //Check if timer exists in
    if(!DeviceContainer.timers.Any(s=>s.Identifier.Equals(Id)))
    {
         //Create new object of timer, assign identifier =Id, 
         //set interval and initialize it. add it to collection as
         var timer = new DevTimer();
         timer.AutoReset = true;
         timer.Enabled = true;
         timer.Interval = 5000; //miliseconds
         timer.Elapsed += timer_Elapsed;
         timer.IsInUse=true;
         timer.Identifier=Id;             
         DeviceContainer.timers.Add(timer);
         timer.Start();
    }
    else
    {
         //Code to stop the existing timer and start it again.
         var _timer=DeviceContainer.timers.FirstOrDefault(s=>s.Identifier.Equals(Id)) 
                      as DevTimer;
         _timer.Stop();
         _timer.Start();
    }        

}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
    //code that will turn off the device in DB
}

我没有发布整个代码,因为这不是目的。

答案 1 :(得分:0)

我会使用微软的Reactive Framework。

以下是代码:

IEnumerable<xxxx> yyyy = new List<xxxx>();

Subject<Unit> clientRequestArrived = new Subject<Unit>();

IDisposable subscription =
    clientRequestArrived
        .Select(_ => Observable.Interval(TimeSpan.FromSeconds(5.0)))
        .Switch()
        .Subscribe(_ =>
        {
            //code to be executed when timer elapses...
            //directly access `yyyy` here
        });

您需要做的就是每次用户请求进入时调用clientRequestArrived.OnNext(Unit.Default);,这对于此代码重置计时器就足够了。

如果您想完全停止计时器,只需拨打subscription.Dispose()