C# ForecastIOPortable lib in WPF application with Timer - c#

I'm trying to get weather information using ForecastIOPortable library.
I have a method that works without problems in Console application, same in WPF application.
ForecastApi api = new ForecastApi("XXXX");
var forecast = api.GetWeatherDataAsync(XXXX, XXXX);
var results = forecast.Result;
int tempC = (int)(5.0 / 9.0 * (results.Currently.Temperature - 32));
Problem shows when I try to call that method with tick of timer, program freezes and VS doesn't show information about exception.
When I checked breakpoints, I get information that results doesn't change and all time has value=null.
What is the reason of problem and how to deal with it?

You are using an async process so you will you will be getting the a Task rather than the result.
In a console app you generally have to .Wait() for the task to resolve before the result will be populated. You would be better to test using a WPF application where you can await the GetWeatherDataAsync method.
Probably the best way to handle it is to wrap the timer in a class and pass in the various bits.
You can try this
public class ForecastApiAsyncTimer : IDisposable
{
private ForecastApi _api;
private Timer _timer;
public ForecastApiAsyncTimer(Timer timer, ForecastApi forecastApi)
{
if (timer == null)
throw new ArgumentNullException("timer");
if (forecastApi == null)
throw new ArgumentNullException("forecastApi");
_api = forecastApi;
_timer = timer;
_timer.Elapsed += _timer_Elapsed;
}
public ForecastApiAsyncTimer(double interval, ForecastApi forecastApi)
{
if (forecastApi == null)
throw new ArgumentNullException("forecastApi");
_api = forecastApi;
_timer = new Timer(interval);
_timer.Elapsed += _timer_Elapsed;
}
public void Start()
{
_timer.Start();
}
public void Stop()
{
_timer.Stop();
}
protected async virtual Task<int> TimerElapsedTask()
{
var forecast = await _api.GetWeatherDataAsync(40.7505045d, -73.9934387d);
int tempC = (int)(5.0 / 9.0 * (forecast.Currently.Temperature - 32));
return tempC;
}
async void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
int result = await TimerElapsedTask();
// do something with result.
}
~ForecastApiAsyncTimer()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposing || _timer == null)
return;
_timer.Dispose();
_timer = null;
}
}
Example usage 1.
static void Main(string[] args)
{
string apiKey = "yourApiKey";
ForecastApi api = new ForecastApi(apiKey);
using (var forecastTimer = new ForecastApiAsyncTimer(5000, api))
{
forecastTimer.Start();
while (!Console.KeyAvailable)
{
}
}
}
Example usage 2:
static void Main(string[] args)
{
string apiKey = "yourApiKey";
ForecastApi api = new ForecastApi(apiKey);
Timer timer = new Timer(5000);
var forecastTimer = new ForecastApiAsyncTimer(timer, api);
forecastTimer.Start();
while (!Console.KeyAvailable)
{
}
}

Related

Is it possible to inject services inside a Timer in ASP.NET Core?

I am currently developing a multiplayer web game with timer using ASP.NET Core. For real time communication I am using SignalR. Everythning up to the moment had been working just fine.
The way I implemented the timer functionality was the following: I created a static dictionary where the key is the Id of the game and the value is the timer corresponding to the given game. Then I exposed public methods for managing the state of the dictionary:
public class TimerManager
{
private static readonly Dictionary<string, GameTimer> gameTimersByGameIds = new();
public void AttachTimerToGameState(GameTimer timer, string gameId)
{
if (!gameTimersByGameIds.ContainsKey(gameId))
{
gameTimersByGameIds.Add(gameId, timer);
return;
}
gameTimersByGameIds[gameId] = timer;
}
public GameTimer? GetTimer(string gameId)
{
if (!gameTimersByGameIds.ContainsKey(gameId))
{
return null;
}
return gameTimersByGameIds[gameId];
}
public GameTimer CreateTimer(GameState gameState)
{
if (gameState.RemainingSecondsByUserNames.Count == 0)
{
return ActivatorUtilities.CreateInstance<StandardTimer>(_serviceProvider, gameState);
}
else
{
return ActivatorUtilities.CreateInstance<ChessTimer>(_serviceProvider, gameState, _gamesService);
}
}
}
I created my own base GameTimer class which encapsulates a System.Timers.Timer inside of it:
public abstract class GameTimer
{
protected readonly System.Timers.Timer _timer = new();
public virtual void Reset()
{
_timer.AutoReset = true;
_timer.Interval = 1_000;
}
public virtual void Start()
{
_timer.Start();
}
public virtual void Dispose()
{
_timer.Dispose();
}
}
Then I inherited from the abstract GameTimer class to create different types of timers.
public class StandardTimer : GameTimer
public class ChessTimer : GameTimer
The problem is inside of the ChessTimer class:
public class ChessTimer : GameTimer
{
private readonly GameState _gameState;
private readonly IGameService _gameService;
private readonly IHubContext<GameHub, IGameClient> _hubContext;
private readonly IMatchmakingService _matchmakingService;
private readonly IGamesService _gamesService;
public ChessTimer(
GameState gameState,
IGamesService gamesService,
IGameService gameService,
IHubContext<GameHub, IGameClient> hubContext,
IMatchmakingService matchmakingService)
{
_gameState = gameState;
_gameService = gameService;
_hubContext = hubContext;
_matchmakingService = matchmakingService;
_gamesService = gamesService;
Reset();
_timer.Elapsed += async (sender, args) => await OnTimedEvent(sender, args);
}
public int SecondsRemaining { get; private set; }
public override void Reset()
{
string currentPlayerName = _gameState.CurrentTeam.CurrentPlayer.UserName;
SecondsRemaining = _gameState.RemainingSecondsByUserNames[currentPlayerName];
base.Reset();
}
private async Task OnTimedEvent(object? sender, ElapsedEventArgs args)
{
if (SecondsRemaining >= 0)
{
string currentPlayerUserName = _gameState.CurrentTeam.CurrentPlayer.UserName;
_gameState.RemainingSecondsByUserNames[currentPlayerUserName] = SecondsRemaining;
int minutes = SecondsRemaining / 60;
int seconds = SecondsRemaining % 60;
var viewModel = new UpdateGameTimerViewModel
{
Minutes = minutes,
Seconds = seconds,
};
foreach (Player player in _gameState.Players)
{
if (player.ConnectionId == null)
{
continue;
}
await _hubContext.Clients
.Client(player.ConnectionId)
.UpdateGameTimer(viewModel);
}
SecondsRemaining--;
return;
}
if (_gameState.RemainingSecondsByUserNames.All(x => x.Value <= 0))
{
_gameState.EndGame();
}
else
{
_gameState.NextTeam();
}
foreach (Player player in _gameState.Players)
{
_gameService.FillPlayerTiles(_gameState, player);
}
foreach (Player player in _gameState.Players)
{
if (player.ConnectionId == null)
{
continue;
}
var viewModel = _gameService.MapFromGameState(_gameState, player.UserName);
await _hubContext.Clients
.Client(player.ConnectionId)
.UpdateGameState(viewModel);
if (_gameState.IsGameOver)
{
_matchmakingService.RemoveUserFromGame(player.UserName);
await _hubContext.Groups
.RemoveFromGroupAsync(
player.ConnectionId, _gameState.GameId);
}
}
if (_gameState.IsGameOver)
{
_matchmakingService.RemoveGameState(_gameState.GameId);
await _gamesService!.SaveGameAsync(new SaveGameInputModel
{
GameId = _gameState.GameId,
Players = _gameState.Players
});
Dispose();
}
Reset();
}
}
Basically the way my OnTimedEvent method works is that it executes every second. Then checks whether the time of all players has run out. If it hasn't it updates the state of the game, otherwise is ends the game. After everything else is done, I try to save the game inside my database in order to enable the users to see summary about their played games. I am using a class called GamesService for this task. It uses UserManager internally to perform some work with the Users in the database.
if (_gameState.IsGameOver)
{
_matchmakingService.RemoveGameState(_gameState.GameId);
await _gamesService!.SaveGameAsync(new SaveGameInputModel
{
GameId = _gameState.GameId,
Players = _gameState.Players
});
Dispose();
}
Reset();
The problem is that when the game ends and the above code is executed it produces the following exception:
Unhandled exception. Unhandled exception. System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'UserManager`1'.
at Microsoft.AspNetCore.Identity.UserManager`1.ThrowIfDisposed()
at Microsoft.AspNetCore.Identity.UserManager`1.FindByNameAsync(String userName)
at SuperScrabble.Services.Data.Users.UsersService.GetByUserNameAsync(String userName) in C:\Users\georg\Source\Github\SuperScrabble\src\Server\Services\SuperScrabble.Services.Data\Users\UsersService.cs:line 64
at SuperScrabble.Services.Data.Games.GamesService.SaveGameAsync(SaveGameInputModel input) in C:\Users\georg\Source\Github\SuperScrabble\src\Server\Services\SuperScrabble.Services.Data\Games\GamesService.cs:line 52
at SuperScrabble.WebApi.Timers.ChessTimer.OnTimedEvent(Object sender, ElapsedEventArgs args) in C:\Users\georg\Source\Github\SuperScrabble\src\Server\WebApi\SuperScrabble.WebApi\Timers\ChessTimer.cs:line 120
at SuperScrabble.WebApi.Timers.ChessTimer.<.ctor>b__5_0(Object sender, ElapsedEventArgs args) in C:\Users\georg\Source\Github\SuperScrabble\src\Server\WebApi\SuperScrabble.WebApi\Timers\ChessTimer.cs:line 35
at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_1(Object state)
at System.Threading.QueueUserWorkItemCallback.<>c.<.cctor>b__6_0(QueueUserWorkItemCallback quwi)
at System.Threading.ExecutionContext.RunForThreadPoolUnsafe[TState](ExecutionContext executionContext, Action`1 callback, TState& state)
at System.Threading.QueueUserWorkItemCallback.Execute()
at System.Threading.ThreadPoolWorkQueue.Dispatch()
at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart()
at System.Threading.Thread.StartCallback()
It seems to me that the _gamesService object which I pass to the CreateInstance() method inside the TimerManager.CreateTimer() method is already disposed or that some of the services it uses internally are.
public GameTimer CreateTimer(GameState gameState)
{
if (gameState.RemainingSecondsByUserNames.Count == 0)
{
return ActivatorUtilities.CreateInstance<StandardTimer>(_serviceProvider, gameState);
}
else
{
return ActivatorUtilities.CreateInstance<ChessTimer>(_serviceProvider, gameState, _gamesService);
}
}
I am not sure if what I am trying to do is correct. I need to use service classes inside my timer classes to perform operations every time the timer ticks. However, I cannot use dependency injection and that's the reason why I use the ActivatorUtilities class to instantiate the object.
I create all timers from a method inside my SignalR hub class:
private async Task StartGameAsync()
{
var gameState = _matchmakingService.GetGameState(UserName);
string gameId = gameState.GameId;
foreach (Player player in gameState.Players)
{
await Groups.AddToGroupAsync(player.ConnectionId!, gameId);
}
var timer = _timerManager.CreateTimer(gameState);
Console.WriteLine(timer.GetType().Name);
_timerManager.AttachTimerToGameState(timer, gameId);
await Clients.Group(gameId).StartGame(gameId);
await UpdateGameStateAsync(gameState);
timer.Start();
}
So my question would be: Is it possible to find a work around of the problem?
If you need any more clarification please feel free to ask me anything. Any help would be greatly appreciated! Thanks

Why i can not start the windows service in thread?

I've code which starts depending whether the underlying application runs in console services instead of threads for the tasks. Here is a small cut of the main method:
//ANSAR BANK THREAD
Thread AnsarBankThread = new Thread(Ansar);
Console.WriteLine("Start The AnsarBankThread");
AnsarBankThread.Start();
//MELLAT BANK THREAD
Thread MellatBankThread = new Thread(Mellat);
Console.WriteLine("Start The MellatBankThread");
MellatBankThread.Start();
This is the code which will be executed:
static void Ansar()
{
var AnsarBank1 = new AnsarBank();
if (Environment.UserInteractive)
{
AnsarBank1.Start();
}
else
{
var servicesToRun = new ServiceBase[]{ AnsarBank1 };
ServiceBase.Run(servicesToRun);
}
}
static void Mellat()
{
var MellatBank1 = new MellatBank();
if (Environment.UserInteractive)
{
MellatBank1.Start();
}
else
{
var servicesToRun = new ServiceBase[]{ MellatBank1 };
ServiceBase.Run(servicesToRun);
}
}
and this is my AnsarBank service code:
protected override void OnStart(string[] args)
{
var timer = new System.Timers.Timer(5000); // fire every 30 second
timer.Elapsed += OnElapsedTime;
timer.Enabled = true;
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
File.WriteAllText(#"d:\Temp\Ansar.txt", "Ansar Bank Writer\n");
}
public void Start()
{
OnStart(new string[0]);
}
And this is my MellatBank Service:
protected override void OnStart(string[] args)
{
var timer = new System.Timers.Timer(5000); // fire every 30 second
timer.Elapsed += OnElapsedTime;
timer.Enabled = true;
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
File.WriteAllText(#"d:\Temp\MellatBank.txt", "Mellat Bank writer\n");
}
public void Start()
{
OnStart(new string[0]);
}
However, if I run the code there will be only the file Ansar.txt created and the file MellatBank.txt is missing!
Can someone encounter the problem in my code please? I would appreciate any help!
Chnage code to this:
System.Timers.Timer personalTimer = null;
public AnsarBank()
{
personalTimer = new System.Timers.Timer(5000);
InitializeComponent();
}
protected override void OnStart(string[] args)
{
//var timer = new System.Timers.Timer(5000); // fire every 30 second
personalTimer.Elapsed += OnElapsedTimeAnsar;
personalTimer.Enabled = true;
}
but so not work.
What's the problem?
1. Variable goes out of scope:
Thanks to #MatthewWatson: I also suggest moving the timer variable outside of the method right into the class. The timer object can be garbage collected directly because the garbage collector doesn't see that it's used any further.
Why thinks the gc that the variable isn't used anymore?
Simply because you created it in the method. It's local and because the class itself hasn't any reference to it there isn't any hint for the gc that it's needed further!
This should be true after I looked to this question.
Solution to this in sample code:
class SomeClass {
System.Timers.Timer personalTimer = null; //Timer is now garbage collected after the object of SomeClass goes out of scope!
SomeClass() {
personalTimer = new Syste.Timers.Timer(30000) // Now every 30 seconds!
}
protected override void OnStart(string[] args)
{
personalTimer.Elapsed += OnElapsedTime;
personalTimer.AutoReset = true; //Add this line to keep continuos activation
personalTimer.Enabled = true;
}
....
}
2.File access problems
After I tried your code I encountered exceptions because the path may not exist. So I changed the code to create a path before the creation of a file. Also I added checks whether file exists and if so that text will be applied to the file. The old solution replaced the file everytime. This works for me fine. I don't know what you've done with InitializeComponents(...) this seems to be gui stuff, so I don't know.
Change your code in the service classes to following please:
namespace WebService
{
partial class MellatBank : ServiceBase
{
System.Timers.Timer personalTimer = null;
public MellatBank()
{
personalTimer = new System.Timers.Timer(1000);
this.ServiceName = "MellatBankService";
}
protected override void OnStart(string[] args)
{
personalTimer.Elapsed += OnElapsedTimeMellat;
personalTimer.AutoReset = true; //Add this line to keep continuos activation
personalTimer.Enabled = true;
//var timer = new System.Timers.Timer(5000); // fire every 30 second
//personalTimer.Elapsed += OnElapsedTimeMellat;
//personalTimer.Enabled = true;
}
private void OnElapsedTimeMellat(object source, ElapsedEventArgs e)
{
try
{
if (!Directory.Exists(#"D:\Temp"))
Directory.CreateDirectory(#"D:\Temp\");
if (!File.Exists(#"D:\Temp\MellatBank.txt"))
{
var f = File.CreateText(#"D:\Temp\MellatBank.txt");
f.Write(#"D:\Temp\MellatBank.txt", "Mellat Bank writer\n");
f.Close();
}
else
{
var f = File.AppendText(#"D:\Temp\MellatBank.txt");
f.Write("Mellat Bank writer\n");
f.Close();
}
}
catch (System.Exception ex)
{
Console.Error.WriteLine("IO EXCEPTION: {0}", ex.ToString());
}
}
public void Start()
{
OnStart(new string[0]);
}
protected override void OnStop()
{
Console.Out.WriteLine("ended!");
// TODO: Add code here to perform any tear-down necessary to stop your service.
}
}
}
namespace WebService
{
partial class AnsarBank : ServiceBase
{
System.Timers.Timer personalTimer = null;
public AnsarBank()
{
personalTimer = new System.Timers.Timer(1000);
this.ServiceName = "AnsarBankService";
}
protected override void OnStart(string[] args)
{
personalTimer.Elapsed += OnElapsedTimeAnsar;
personalTimer.AutoReset = true; //Add this line to keep continuos activation
personalTimer.Enabled = true;
//var timer = new System.Timers.Timer(5000); // fire every 30 second
//personalTimer.Elapsed += OnElapsedTimeAnsar;
//personalTimer.Enabled = true;
}
private void OnElapsedTimeAnsar(object source, ElapsedEventArgs e)
{
try
{
if (!Directory.Exists(#"D:\Temp"))
Directory.CreateDirectory(#"D:\Temp\");
if (!File.Exists(#"D:\Temp\Ansar.txt"))
{
var f = File.CreateText(#"D:\Temp\Ansar.txt");
f.Write(#"D:\Temp\Ansar.txt", "Ansar Bank writer\n");
f.Close();
}
else
{
var f = File.AppendText(#"D:\Temp\Ansar.txt");
f.Write("Ansar Bank Writer\n");
f.Close();
}
}
catch (System.Exception ex)
{
Console.Error.WriteLine("IO EXCEPTION: {0}", ex.ToString());
}
}
public void Start()
{
OnStart(new string[0]);
}
protected override void OnStop()
{
Console.Out.WriteLine("ended!");
}
}
}
Edit:
After viewing your code I saw that your services only run as long as your application runs. So your services may have been stopped before they could write anything which would explain your problem too.
PS:
Asker please practice the basics of Object Oriented Programming (OOP) again if you don't know what class fields are.

Monitoring processes with while(true) loop

Is it possible to optimise my console application? It uses up to 60% of CPU because of while(true) loop.
The idea is to kill Microsoft managment console (services) process every time it starts up. And to start/stop services - use pswrd and console.
public static void Main(string[] args)
{
Thread consoleInput = new Thread(_consoleInput);
consoleInput.Start();
killProcess();
}
static void _consoleInput(){
getPassword();
sendServiceCommands();
}
static void killProcess(){
while(true){
try{
System.Diagnostics.Process[] myProcs = System.Diagnostics.Process.GetProcessesByName("mmc");
myProcs[0].Kill();
}
catch(Exception e){}
}
}
You need System.Threading.Timer. Something like this:
public class Killer
{
protected const int timerInterval = 1000; // define here interval between ticks
protected Timer timer = new Timer(timerInterval); // creating timer
public Killer()
{
timer.Elapsed += Timer_Elapsed;
}
public void Start()
{
timer.Start();
}
public void Stop()
{
timer.Stop();
}
public void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
System.Diagnostics.Process[] myProcs = System.Diagnostics.Process.GetProcessesByName("mmc");
myProcs[0].Kill();
}
catch {}
}
}
...
public static void Main(string[] args)
{
Killer killer = new Killer();
Thread consoleInput = new Thread(_consoleInput);
_consoleInput.Start();
killer.Start();
...
// whenever you want you may stop your killer
killer.Stop();
}

switching from different timers c#

I'm creating an Windowns phone 8 app(c#), its a countdown interval timer, so there is prepare time(10 sec), work time(20 sec), rest time(10 sec). I have these variables
`TimeSpan prepInterval = new TimeSpan(0, 0, 0, 10);
TimeSpan workInterval = new TimeSpan(0, 0, 0, 20);
TimeSpan restInterval = new TimeSpan(0, 0, 0, 10);`
I can't wrap my head around having them implementing them one after another when they hit 0. So when prepare time is done, the work timer is to start and when thats finised, the rest timer is to start.
If you would like to have some more broken down logic in all of this, maybe you can create some classes based on a simple interface, like the following:
interface ITimerAction
{
int Seconds { get; set; }
bool Started { get; }
bool Completed { get; }
void OnStart();
void OnComplete();
}
interface ITimerActionList
{
void Add(ITimerAction action);
void Work();
event EventHandler OnCompletedEvent;
}
This would then allow you to create an abstract TimerAction class, and TimerActionList
abstract class TimerAction : ITimerAction
{
public virtual int Seconds
{
get;
set;
}
public virtual bool Completed
{
get;
protected set;
}
public virtual bool Started
{
get;
protected set;
}
public abstract void OnStart();
public abstract void OnComplete();
}
class TimerActionList : ITimerActionList
{
public event EventHandler OnCompletedEvent;
private readonly IList<ITimerAction> actions = new List<ITimerAction>();
private bool working = false;
private Thread myThread;
public void Add(ITimerAction action)
{
if (working)
{
throw new InvalidOperationException("Cannot add new timers when work is already in progress");
}
actions.Add(action);
}
protected virtual void DoWork()
{
working = true;
int currentStep = 0, maxSteps = actions.Count;
while (currentStep < maxSteps)
{
ITimerAction action = actions[currentStep];
if (!action.Started)
{
action.OnStart();
}
if (action.Completed)
{
currentStep++;
continue;
}
if (action.Seconds == 0)
{
action.OnComplete();
continue;
}
action.Seconds--;
Thread.Sleep(1000);
}
Completed();
}
public void Work()
{
if (working)
{
throw new InvalidOperationException("Already running!");
}
working = true;
myThread = new Thread(DoWork);
myThread.Start();
}
protected virtual void Completed()
{
myThread = null;
working = false;
actions.Clear();
var local = OnCompletedEvent;
if (local != null)
{
local.Invoke(this, EventArgs.Empty);
}
}
}
You could then write the classes that inherit from the TimerAction class, that could handle an action before and after the timer ran through :)
class PrepareTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Preparing");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Prepare ready");
Completed = true;
}
}
class WorkTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Working");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Work ready");
Completed = true;
}
}
class CoolDownTimer : TimerAction
{
public override void OnStart()
{
Console.WriteLine("Cooling down");
Started = true;
}
public override void OnComplete()
{
Console.WriteLine("Cooldown ready");
Completed = true;
}
}
And then you could test the code as such
static void Main(string[] args)
{
bool done = false;
ITimerActionList mylist = new TimerActionList();
mylist.Add(new PrepareTimer { Seconds = 1 });
mylist.Add(new WorkTimer { Seconds = 2 });
mylist.Add(new CoolDownTimer { Seconds = 1 });
mylist.OnCompletedEvent += (sender, e) =>
{
done = true;
};
mylist.Work();
while (!done)
{
// timer is running
}
Console.WriteLine("Done!");
}
(Console program, but i guess that also goes to demonstrate?)
Here's an example based on deathismyfriend's and Hans Passant's suggestions:
var start = new DateTime();
var stage = 0;
var timer = new System.Timers.Timer(100);
timer.Elapsed += (s, e) =>
{
var elapsed = DateTime.Now - start;
int duration = stage == 1 ? 20 : 10;
if (elapsed.TotalSeconds > duration)
{
start = DateTime.Now;
stage++;
if (stage > 2)
timer.Stop();
}
};
start = DateTime.Now;
stage = 0;
timer.Start();

DispatcherTimer doesn't work in Console

I'm curious as to why dispatcher timer doesn't work in console mode. I created a simple alarm that does something when the timer reaches it's limit.
Can you use dispatcher timer with UnitTest or in Console mode?
DailyAlarm works when I run it in a form.
Here's my code to call the timer
[TestClass]
public class UnitTest1
{
bool runTest = true;
[TestMethod]
public void TestDailyAlarm()
{
DateTime alarmTime = new DateTime();
alarmTime= DateTime.Now;
alarmTime = alarmTime.AddSeconds(5);
// MessageBox.Show(alarmTime.ToString());
DailyAlarm alarm = new DailyAlarm(alarmTime);
alarm.DailyAlarmEvent += alarm_DailyAlarmEvent;
alarm.Start();
while (runTest)
{
System.Threading.Thread.Sleep(1000);
}
}
void alarm_DailyAlarmEvent(EventArgs e)
{
MessageBox.Show("Alarm On");
runTest = false;
}
}
Here's my timer code
public class DailyAlarm
{
#region Timer
DispatcherTimer timer;
#endregion
#region AlarmTime
DateTime _alarmTime;
#endregion
#region Event
public delegate void DailyAlarmHandler(EventArgs e);
public event DailyAlarmHandler DailyAlarmEvent;
#endregion
public DailyAlarm(System.DateTime alarmTime)
{
if (alarmTime < DateTime.Now)
{
alarmTime = alarmTime.AddDays(1);
}
_alarmTime = alarmTime;
TimeSpan timeRemaining = alarmTime.Subtract(DateTime.Now);
timer = new DispatcherTimer();
timer.Tick += AlarmEvent;
timer.Interval = timeRemaining;
}
public void Start()
{
timer.Start();
}
private void AlarmEvent(object sender, EventArgs e)
{
DailyAlarmEvent(null);
// Calculate next Alarm
_alarmTime = _alarmTime.AddDays(1);
TimeSpan timeRemaining = _alarmTime.Subtract(DateTime.Now);
Utilities.DispatcherTimer_ChangeInterval(ref timer, timeRemaining);
}
public void Stop()
{
if (timer != null)
timer.Stop();
}
}
The console and unit test environment by default don't have a dispatcher to run your dispatcher timer.
You can still use Dispatcher.CurrentDispatcher to create a Dispatcher to run your code.
There's an example of its usage at http://consultingblogs.emc.com/crispinparker/archive/2010/10/22/unit-testing-a-wpf-dispatchertimer-method.aspx
With this DispatcherHelper you can test your code with:
[TestMethod]
public void TestMethod1()
{
Action test = () =>
{
var dailyAlarm = new DailyAlarm(DateTime.Now.AddSeconds(5.0));
dailyAlarm.DailyAlarmEvent += dailyAlarm_DailyAlarmEvent;
dailyAlarm.Start();
};
DispatcherHelper.ExecuteOnDispatcherThread(test, 20);
}
void dailyAlarm_DailyAlarmEvent(EventArgs e)
{
// event invoked when DispatcherTimer expires
}
DispatcherTimer fires its Tick event on the UI thread. And you are running your code in a console mode. That's is the answer, I think!

Categories