C# rerun thread - c#

I want to rerun thread when it finish working. I have two programs. One in Windows Form and second in cmd. Windows Form program run program in cmd.
I tried use while(true) and if with: process.HasExited, .WaitForExit, .Join on thred, .IsBusy and rerun method on RunWorkerCompleted. But it's doesn't work.
BgWorker code (action on button click):
backgroundWorker1.RunWorkerAsync();
backgroundWorker1.DoWork += new DoWorkEventHandler(uruchomWatek);
Function whitch I want to rerun thread
private void uruchomWatek(object sender, DoWorkEventArgs e)
{
String polaczenieZDB = config.Default.adresDb + ";" + config.Default.nazwaDb + ";" + config.Default.login + ";" + config.Default.haslo;
//przygotowuję proces
Process pr = new Process();
ProcessStartInfo prs = new ProcessStartInfo();
//uruchamiam cmd
prs.FileName = "cmd";
// /c START uruchamia program w cmd, przekazuję tutaj prametry
prs.Arguments = " /c START " + " " + #sciezkaDoSlaveTextBox.Text + " " + ipAdresTextBox.Text + " "
+ numerPortuTextBox.Text + " " + polaczenieZDB + " " + pobierzZadaniaDoSpr();
pr.StartInfo = prs;
//uruchamiam proces w nowym wątku
ThreadStart ths = new ThreadStart(() => pr.Start());
Thread th = new Thread(ths);
th.IsBackground = true;
th.Start();
}

This class may help you through this purpose :
public class BackgroundThread : BackgroundWorker
{
public BackgroundThread()
{
this.WorkerSupportsCancellation = true;
}
protected override void OnDoWork(DoWorkEventArgs e)
{
try
{
base.OnDoWork(e);
}
catch (Exception exception)
{
//Log Exception
}
}
public void Run()
{
if (this.IsBusy)
return;
this.RunWorkerAsync();
}
public void Stop()
{
this.CancelAsync();
this.Dispose(true);
}
}
EDIT :
If you want to use your class as a timer and do the task in intervals the following class may comes really handy.
public class BackgroundTimer : BackgroundWorker
{
private ManualResetEvent intervalManualReset;
private enum ProcessStatus { Created, Running, JobCompleted, ExceptionOccured };
private ProcessStatus processStatus = new ProcessStatus();
public int Interval { get; set; }
public BackgroundTimer()
{
this.processStatus = ProcessStatus.Created;
this.WorkerSupportsCancellation = true;
this.Interval = 1000;
}
protected override void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)
{
base.OnRunWorkerCompleted(e);
if (processStatus == ProcessStatus.ExceptionOccured)
// Log ...
processStatus = ProcessStatus.JobCompleted;
}
protected override void OnDoWork(DoWorkEventArgs e)
{
while (!this.CancellationPending)
{
try
{
base.OnDoWork(e);
this.Sleep();
}
catch (Exception exception)
{
// Log ...
this.processStatus = ProcessStatus.ExceptionOccured;
this.Stop();
}
}
if (e != null)
e.Cancel = true;
}
public void Start()
{
this.processStatus = ProcessStatus.Running;
if (this.IsBusy)
return;
this.intervalManualReset = new ManualResetEvent(false);
this.RunWorkerAsync();
}
public void Stop()
{
this.CancelAsync();
this.WakeUp();
this.Dispose(true);
}
public void WakeUp()
{
if (this.intervalManualReset != null)
this.intervalManualReset.Set();
}
private void Sleep()
{
if (this.intervalManualReset != null)
{
this.intervalManualReset.Reset();
this.intervalManualReset.WaitOne(this.Interval);
}
}
public void Activate()
{
if (!this.IsBusy)
// Log ...
this.Start();
}
}
EDIT 2 :
Usage :
sendThread = new BackgroundThread();
sendThread.DoWork += sendThread_DoWork;
sendThread.Run();
void sendThread_DoWork(object sender, DoWorkEventArgs e)
{
...
}

Related

Is there a way to create a timeout to an attempt to connection with Xamarin.Forms?

I'm trying to develop a warning if I try to connect to a specific SSID and some waiting time has passed. I've tried with a Timer class but there is some issues with Task and Threads I can't resolve.
This is my Wifi class in Xamarin.Droid
public class Wifi : Iwifi
{
private Context context;
private static WifiManager _manager;
private MyReceiver _receiver;
public void Initialize()
{
context = Android.App.Application.Context;
_manager = (WifiManager)context.GetSystemService(Context.WifiService);
_receiver = new MyReceiver();
}
public void Register()
{
IntentFilter intents = new IntentFilter();
intents.AddAction(WifiManager.ScanResultAction);
intents.AddAction(WifiManager.NetworkStateChangedAction);
context.RegisterReceiver(_receiver, intents);
}
public void Unregister()
{
context.UnregisterReceiver(_receiver);
}
public void ScanWirelessDevices()
{
_manager.StartScan();
}
public string GetConnectionSSID()
{
return _manager.ConnectionInfo.SSID;
}
public void ConnectToSSID(string SSID, string pwd)
{
if (!_manager.IsWifiEnabled)
{
_manager.SetWifiEnabled(true);
}
WifiConfiguration wifiConfiguration = new WifiConfiguration();
wifiConfiguration.Ssid = '"' + SSID + '"';
if (pwd.Empty)
{
wifiConfiguration.AllowedKeyManagement.Set((int)KeyManagementType.None);
}
else
{
//Configuration for protected Network
}
var addNet = _manager.AddNetwork(wifiConfiguration);
if (addNet == -1)
{
_manager.Disconnect();
_manager.EnableNetwork(addNet, true);
_manager.Reconnect();
return;
}
var list = _manager.ConfiguredNetworks;
foreach (WifiConfiguration conf in list)
{
if (conf.Ssid.Equals('"' + SSID + '"'))
{
_manager.Disconnect();
_manager.EnableNetwork(conf.NetworkId, true);
_manager.Reconnect();
return;
}
}
}
public class MyReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action.Equals(WifiManager.ScanResultAvailableAction))
{
IList<ScanResult> scanResult = _manager.ScanResult;
App.Networks.NetworksList.Clear();
foreach (ScanResult result in scanResult)
{
App.Networks.NetworksList.Add(result.Ssid);
}
}
}
}
}
Then this is a part of App class in Xamarin.Forms
public partial class App: Application
{
private static ...
.
.
.
private static string _selectedSSID;
private static MainDetail _pageDetail;
public static IWifi WifiManager { get; } = DependencyService.Get<Iwifi>();
public static string SelectedSSID { get { return _selectedSSID; } set { _selectedSSID = value; } }
public static MainDetail PageDetail { get { return _pageDetail; } }
public App()
{
InitializeComponent();
WifiManager.Initialize();
WifiManager.Register();
InitViews();
MainPage = _mainPage;
Connectivity.ConnectivityChanged += NetworkEvents;
NetSearch();
}
.
.
.
public void NetSearch()
{
Task.Run(async () =>
{
while (true)
{
WifiManager.ScanWirelessDevices();
await Task.Delay(Utility.SCAN_WIFI_TIMER); //waiting 31000 milliseconds because of Scanning throttling
}
});
}
public void NetworkEvents(object sender, ConnectivityChangedEventArgs e)
{
MainMaster master = (MainMaster)_mainPage.Master;
if (e.NetworkAccess == NetworkAccess.Unknown)
{
Debug.WriteLine("Network Access Unknown " + e.ToString());
}
if (e.NetworkAccess == NetworkAccess.None)
{
Debug.WriteLine("Network Access None " + e.ToString());
}
if (e.NetworkAccess == NetworkAccess.Local)
{
Debug.WriteLine("Network Access Local " + e.ToString());
}
if (e.NetworkAccess == NetworkAccess.Internet)
{
if(selectedSSID == Wifimanager.GetConnectionInfo())
{
//WE CONNECTED!!
//Now I want to stop the Timeout Timer to attempt
}
}
if (e.NetworkAccess == NetworkAccess.ConstrainedInternet)
{
Debug.WriteLine("Network Access Constrainde Internet " + e.ToString());
}
}
}
And part of Detail page class in which I start the event of connection and where I want to start also the timeout timer
public partial class MainDetail : ContentPage
{
.
.
.
public void OnItemListClicked(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
ImageCell item = (ImageCell)e.SelectedItem;
App.SelectedSSID = item.Text;
App.WifiManager.ConnectToSSID(item.Text, "");
ActivityIndicator(true);
//Now the timer should start.
//And call PageDetail.ActivityIndicator(false) and warning the user if the timeout go to 0.
listView.SelectedItem = null;
}
}
I tried with the Timers Timer class but doesn't work.. any suggestion?
Ok I figured a solution! Instead of using Thread and Task, I used Device.StartTimer.
In the event on the DetailPage I wrote:
public void OnItemListClicked(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
{
return;
}
ImageCell item = (ImageCell)e.SelectedItem;
App.SelectedSSID = item.Text;
App.WifiManager.ConnectToSSID(item.Text, "");
ActivityIndicator(true);
Device.StartTimer(TimeSpan.FromSeconds(10), () => //Waiting 10 second then if we are not connected fire the event.
{
Device.BeginInvokeOnMainThread(() =>
{
if (App.IsLogout) //variable I use to check if I can do the logout or not
{
ActivityIndicator(false);
App.SelectedSSID = "";
//My message to users "Fail to connect"
}
});
return false;
});
listView.SelectedItem = null;
}

How to pass a parameter to a timer event

I am trying to implement a timer as per the below code. I want to pass a parameter to the timer event. I have used below anonymous function approach.
However this would only pass only the first parameter to the OnTimerElapsedEvent. Can someone please advise?
class Program
{
static void Main(string[] args)
{
ClassA obj = new ClassA();
Console.WriteLine("Start" + " " + System.DateTime.Now);
obj.SampleMethod("hello", 3000);
Thread.Sleep(4000);
obj.SampleMethod("world", 6000);
Console.ReadKey();
}
}
class ClassA
{
private System.Timers.Timer tTimer;
public void SampleMethod(string strParam, int iTimerInterval)
{
if (tTimer == null)
{
tTimer = new System.Timers.Timer();
tTimer.Elapsed += (sender, e) =>
OnTimerElapsedEvent(sender, e, strParam);
}
tTimer.Interval = iTimerInterval;
tTimer.Enabled = true;
tTimer.Start();
}
private void OnTimerElapsedEvent(object source, ElapsedEventArgs e, string strParam)
{
//use strParam value here
Console.WriteLine(strParam + " " + System.DateTime.Now);
if (strParam == "world")
{
tTimer.Stop();
tTimer.Enabled = false;
}
}
}
You can inherit the Timer class to provide a parameter in the constructor like below. Or you can inherit the Timer class and provide a property:
[TestClass]
public class TimerTester
{
[TestMethod]
public void TestYourTimer()
{
var timer1 = new TimerWithParameter("param1");
timer1.Interval = 1000;
timer1.ElapsedEvent += Timer_ElapsedEvent;
timer1.Start();
var timer2 = new TimerWithParameter("param2");
timer2.Interval = 1300;
timer2.ElapsedEvent += Timer_ElapsedEvent;
timer2.Start();
Thread.Sleep(5000);
}
private void Timer_ElapsedEvent(object source, ElapsedEventArgs e, string strParam)
{
Debug.WriteLine(strParam);
}
}
public delegate void ElapsedWithParameterDelegate(object source, ElapsedEventArgs e, string strParam);
public class TimerWithParameter:Timer
{
private readonly string _strParam;
public event ElapsedWithParameterDelegate ElapsedEvent;
public TimerWithParameter(string strParam)
{
_strParam = strParam;
this.Elapsed += TimerWithParameter_Elapsed;
}
private void TimerWithParameter_Elapsed(object sender, ElapsedEventArgs e)
{
ElapsedEvent?.Invoke(this, e, _strParam);
}
}

UWP sync communication serial device

I'm working on a C# UWP APP and I need to communicate with many devices using
an USB port as Serial Port. After that I will convert the communication to RS485 to communicate with the other devices. Until now, I have create a class that will make all comunications between my devices and I can sent a trama between my devices.
My problem at this point is that after sending some startup frames, the application changes the page and from that moment gives me the following exception in my ReadAsync method:
**
System.Exception occurred HResult=-2147023901 Message=The I/O
operation was canceled due to a module output or an application
request. (Exception from HRESULT: 0x800703E3) Source=mscorlib
StackTrace:
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task
task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task
task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at DrDeliver.CComm.d__31.MoveNext() InnerException:
**
Exception Picture
I already have this problem for a few days and I can't get over it.
I wonder if anyone can figure out where the problem is.
Another question I would like to ask is if anyone knows of any method that allows me to make this communication synchronously.
UPDATE 1
The entire class for communicatons:
public class CComm : IDisposable
{
EventLogDB _eldb = new EventLogDB();
ParameterDB _pdb = new ParameterDB();
cParameter _cParam = new cParameter();
DataReader _dataReaderObject = null;
private DispatcherTimer mTimer;
private int num;
public bool FlagComm { set; get; }
public static string InBuffer { set; get; }
public bool busyFlag = false;
public CancellationTokenSource _readCancellationTokenSource = new CancellationTokenSource();
private DeviceInformationCollection DeviceInformation { set; get; }
private static SerialDevice SerialPort { set; get; }
// Define a delegate
public delegate void CheckReadEventHandler(object source, EventArgs args);
// Define an event based on that delegate
public event CheckReadEventHandler CheckRead;
// Raise an event
protected virtual void OnChecRead()
{
CheckRead?.Invoke(this, EventArgs.Empty);
}
private async Task OpenComm()
{
try
{
busyFlag = true;
//_cParam = _pdb.getParameters();
string selectedPortId = null;
string aqs = SerialDevice.GetDeviceSelector();
DeviceInformation = await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(aqs);
foreach (var devInfo in DeviceInformation)
{
if (devInfo.Name == "USB-RS485 Cable")
{
selectedPortId = devInfo.Id;
}
}
if (selectedPortId != null)
{
SerialPort = await SerialDevice.FromIdAsync(selectedPortId);
if (SerialPort != null)
{
SerialPort.ReadTimeout = TimeSpan.FromMilliseconds(1500);
SerialPort.WriteTimeout = TimeSpan.FromMilliseconds(1000);
SerialPort.BaudRate = 9600;
SerialPort.Parity = SerialParity.None;
SerialPort.StopBits = SerialStopBitCount.One;
SerialPort.DataBits = 8;
FlagComm = true;
}
else
{
var status = DeviceAccessInformation.CreateFromId(selectedPortId).CurrentStatus;
FlagComm = false;
_eldb.attachEvent("E1002", "Starting Comunication Failed: " + status);
//ContentDialog noSerialDevice = new ContentDialog()
//{
// Title = "No Serial Connection",
// Content = "Check connection and try again. App Closing.",
//};
//await noSerialDevice.ShowAsync();
//this.Dispose();
}
InitTool();
await ActivateListen();
busyFlag = false;
}
}
catch (Exception ex)
{
_eldb.attachEvent("E1cC", ex.Message);
}
}
private async Task Listen()
{
try
{
if (SerialPort != null)
{
busyFlag = true;
_dataReaderObject = new DataReader(SerialPort.InputStream);
await ReadAsync(_readCancellationTokenSource.Token);
busyFlag = false;
}
}
catch (Exception ex)
{
}
}
//using (var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(1000)))
//{
// await dataReaderObject.LoadAsync(1024).AsTask(cts.Token);
//}
private async Task ReadAsync(CancellationToken cancellationToken)
{
busyFlag = true;
const uint readBufferLength = 1024; // only when this buffer would be full next code would be executed
var loadAsyncTask = _dataReaderObject.LoadAsync(readBufferLength).AsTask(cancellationToken); // Create a task object
_dataReaderObject.InputStreamOptions = InputStreamOptions.ReadAhead;
var bytesRead = await loadAsyncTask; // Launch the task and wait until buffer would be full
if (bytesRead > 0)
{
InBuffer += _dataReaderObject.ReadString(bytesRead);
OnChecRead();
}
busyFlag = false;
}
private async void WriteComm(string str2Send)
{
using (var dataWriter = new DataWriter(SerialPort.OutputStream))
{
dataWriter.WriteString(str2Send);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
}
private async Task ActivateListen()
{
while (FlagComm)
{
await Listen();
}
}
private void dispatcherTimer_Tick(object sender, object e)
{
_eldb.attachEvent("SYSTEM", "Checking ADDR: " + num);
SendComm(num++, 5);
if (num == 5)
{
mTimer.Stop();
_eldb.attachEvent("SYSTEM", "Modules Checking Finished.");
busyFlag = false;
}
}
public void InitTool()
{
busyFlag = true;
_eldb.attachEvent("SYSTEM", "Setting Parameters.");
// Get Parameters
if (_pdb.GetParameters() == null)
{
// Set Default Parameters
_cParam.SetParam();
// Insert Default parameters in database
_pdb.Insert(_cParam);
// Update Parameters Object
_cParam = _pdb.GetParameters();
}
else
{
// Update Parameters Object
_cParam = _pdb.GetParameters();
}
// Check Addresses in Line
_eldb.attachEvent("SYSTEM", "Start Verifiyng.");
num = 0;
mTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(4000) };
mTimer.Tick += dispatcherTimer_Tick;
mTimer.Start();
}
public async void StartSerialComm()
{
try
{
await OpenComm();
}
catch (Exception ex)
{
_eldb.attachEvent("E7cC", ex.Message);
}
}
public void SendComm(params int[] list)
{
try
{
_cParam = _pdb.GetParameters();
string toSend = "";// = "A" + list[0] + "#";
switch (list[1])
{
case 0:
// Send Initialazation command
toSend = "##" + list[0] + "#" + list[1] + "##";
break;
case 1:
// List of parameters (minPower, maxPower, ramPercent, initSpeed)
toSend = "##" + list[0] + "#" + list[1] + "#" + _cParam.minPower + "#" +
_cParam.maxPower + "#" + _cParam.percRamp + "#" + _cParam.initSpeed + "##";
break;
case 2:
// Send Status Request
toSend = "##" + list[0] + "#" + list[1] + "##";
break;
case 3:
// Send a move Request
toSend = "##" + list[0] + "#" + list[1] + "#" + list[2] + "##";
break;
case 4:
// Send a Error Request
toSend = "##" + list[0] + "#" + list[1] + "##";
break;
case 5:
// Send a start check
toSend = "##" + list[0] + "#" + list[1] + "##";
break;
default:
_eldb.attachEvent("E1004", "Wrong Function Command.");
break;
}
if (toSend != "")
{
WriteComm(toSend);
}
else
{
_eldb.attachEvent("E1003", "Wrong String comunication.");
}
}
catch (Exception ex)
{
_eldb.attachEvent("E8cC", ex.Message);
}
}
public void Dispose()
{
try
{
if (SerialPort == null) return;
FlagComm = false;
SerialPort.Dispose();
SerialPort = null;
if (_dataReaderObject == null) return;
_readCancellationTokenSource.Cancel();
_readCancellationTokenSource.Dispose();
}
catch (Exception ex)
{
_eldb.attachEvent("E6cC", ex.Message);
}
}
}
Main Page:
public sealed partial class MainPage : Page
{
CComm _cC = new CComm();
EventLogDB _eldb = new EventLogDB();
procTrama _cProcTrama = new procTrama();
private DispatcherTimer mTimer;
public MainPage()
{
try
{
InitializeComponent();
// Get the application view title bar
ApplicationViewTitleBar appTitleBar = ApplicationView.GetForCurrentView().TitleBar;
// Make the title bar transparent
appTitleBar.BackgroundColor = Colors.Transparent;
// Get the core appication view title bar
CoreApplicationViewTitleBar coreTitleBar = CoreApplication.GetCurrentView().TitleBar;
/*
ExtendViewIntoTitleBar
Gets or sets a value that specifies whether this title
bar should replace the default window title bar.
*/
// Extend the core application view into title bar
coreTitleBar.ExtendViewIntoTitleBar = true;
mTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(5000) };
mTimer.Tick += dispatcherTimer_Tick;
mTimer.Start();
_eldb.attachEvent("S1027", "Init Started...");
// Start comunication
_cC.StartSerialComm();
// Reference for CheckRead Event
_cC.CheckRead += OnCheckRead;
}
catch (Exception ex)
{
_eldb.attachEvent("MainP", ex.Message);
}
}
private void dispatcherTimer_Tick(object sender, object e)
{
if (!_cC.busyFlag)
{
Frame.Navigate(typeof(InitPage), null);
mTimer.Stop();
}
}
public void OnCheckRead(object source, EventArgs e)
{
try
{
if (CComm.InBuffer == null) return;
_cProcTrama.ProcessTrama(CComm.InBuffer);
CComm.InBuffer = "";
}
catch (Exception ex)
{
_eldb.attachEvent("OnCheckRead: ", ex.Message);
}
}
}
INIT Page:
public partial class InitPage : Page
{
CComm _cC = new CComm();
EventLogDB _eldb = new EventLogDB();
procTrama _cProcTrama = new procTrama();
public InitPage()
{
this.InitializeComponent();
_eldb.attachEvent("S1000", "System Started.");
// Reference for CheckRead Event
_cC.CheckRead += OnCheckRead;
}
private void button_Click(object sender, RoutedEventArgs e)
{
_eldb.attachEvent("S1001", "Login Activated.");
Frame.Navigate(typeof(Page1), null);
}
public void OnCheckRead(object source, EventArgs e)
{
if (CComm.InBuffer == null) return;
_eldb.attachEvent("OnCheckRead: ", CComm.InBuffer);
_cProcTrama.ProcessTrama(CComm.InBuffer);
}
}
Login Page where i more frequently the error occur:
public sealed partial class Page1 : Page
{
private CComm _cC = new CComm();
private procTrama _cProcTrama = new procTrama();
EventLogDB _eldb = new EventLogDB();
public Page1()
{
this.InitializeComponent();
// Reference for CheckRead Event
_cC.CheckRead += OnCheckRead;
user = null;
pass = null;
user_pass = 0;
}
private const int userLimit = 5;
private const int passLimit = 5;
private const char passChar = '*';
public string user
{
get; set;
}
public string pass
{
get; set;
}
public int user_pass
{
get; set;
}
private void execute(char val)
{
string aux = null;
if (user_pass == 1)
{
if (user == null)
user = val.ToString();
else
{
if (user.Length <= userLimit)
user = user + val;
}
userBtn.Content = user;
}
else
{
if (user_pass == 2)
{
if (pass == null)
pass = val.ToString();
else
{
if (pass.Length <= passLimit)
pass = pass + val;
}
for (int i = 0; i < pass.Length; i++)
aux = aux + passChar;
passBtn.Content = aux;
}
}
}
private void key1Btn_Click(object sender, RoutedEventArgs e)
{
execute('1');
}
private void key2Btn_Click(object sender, RoutedEventArgs e)
{
execute('2');
}
private void key3Btn_Click(object sender, RoutedEventArgs e)
{
execute('3');
}
private void key4Btn_Click(object sender, RoutedEventArgs e)
{
execute('4');
}
private void key5Btn_Click(object sender, RoutedEventArgs e)
{
execute('5');
}
private void key6Btn_Click(object sender, RoutedEventArgs e)
{
execute('6');
}
private void key7Btn_Click(object sender, RoutedEventArgs e)
{
execute('7');
}
private void key8Btn_Click(object sender, RoutedEventArgs e)
{
execute('8');
}
private void key9Btn_Click(object sender, RoutedEventArgs e)
{
execute('9');
}
private void key0Btn_Click(object sender, RoutedEventArgs e)
{
execute('0');
}
private void keyEntrarBtn_Click(object sender, RoutedEventArgs e)
{
if (pass == "123" && user == "123")
{
_eldb.attachEvent("S1002", "User Login: " + user);
Frame.Navigate(typeof(Page2), null);
}
user_pass = 0;
passBtn.Content = "Insirir Código";
userBtn.Content = "Inserir Utilizador";
}
private void keyApagarBtn_Click(object sender, RoutedEventArgs e)
{
pass = null;
user = null;
user_pass = 0;
passBtn.Content = "Inserir Código";
userBtn.Content = "Inserir Utilizador";
_eldb.attachEvent("S1003", " User data cleared.");
}
private void userBtn_Click(object sender, RoutedEventArgs e)
{
user_pass = 1;
userBtn.Content = "";
_eldb.attachEvent("S1004", "User button clicked.");
}
private void passBtn_Click(object sender, RoutedEventArgs e)
{
user_pass = 2;
passBtn.Content = "";
_eldb.attachEvent("S1005", "Pass button clicked.");
}
private void exitBtn_Click(object sender, RoutedEventArgs e)
{
_eldb.attachEvent("S1006", "Page1 exit button clicked.");
Frame.Navigate(typeof(InitPage), null);
}
public void OnCheckRead(object source, EventArgs e)
{
try
{
if (CComm.InBuffer == null) return;
_eldb.attachEvent("OnCheckRead: ", CComm.InBuffer);
_cProcTrama.ProcessTrama(CComm.InBuffer);
}
catch (Exception ex)
{
_eldb.attachEvent("OnCheckRead: ", ex.Message);
}
}
}

How can I figured out why the timer event in my Windows Service isn't firing?

I have a very basic service
using System.ServiceProcess;
using System.Timers;
using SystemTimer = System.Timers.Timer;
using System.Net;
using System.Data.SqlClient;
using System;
namespace ServiceThatConnectsToADb
{
public class LrcArchiver : ServiceBase
{
private static SystemTimer PageLoadTimer = new SystemTimer(5000);
public LrcArchiver()
{
ServiceName = "SO Archiver";
CanStop = true;
CanPauseAndContinue = true;
AutoLog = true;
PageLoadTimer.Elapsed += new ElapsedEventHandler(WritePageToDb);
}
protected override void OnStart(string[] args)
{
EventLog.WriteEntry(ServiceName + " started");
}
protected override void OnStop()
{
EventLog.WriteEntry(ServiceName + " stopped");
PageLoadTimer.Enabled = false;
}
protected void WritePageToDb(object source, ElapsedEventArgs e)
{
try
{
string html;
using(WebClient client = new WebClient())
{
html = client.DownloadString("http://stackoverflow.com");
}
EventLog.WriteEntry("html = " + html.Substring(0, 100));
using(SqlConnection connection = new SqlConnection("Data Source=DESKTOP-300NQR3\\SQLEXPRESS;Initial Catalog=SoArchive;Integrated Security=True"))
{
string nonQuery = $"INSERT INTO [dbo].[Homepage] ([Html]) VALUES ('{html}')";
using(SqlCommand command = new SqlCommand(nonQuery, connection))
{
bool succeeded = command.ExecuteNonQuery() == 1;
EventLog.WriteEntry(succeeded ? "Saved!" : "Not Saved");
}
}
}
catch(Exception ex)
{
EventLog.WriteEntry("uh-oh! " + ex.Message);
}
}
}
class Program
{
static void Main(string[] args)
{
ServiceBase.Run(new LrcArchiver());
}
}
}
which I've installed and started, but the WritePageToDb method doesn't appear to be firing as none of its WriteEntrys are showing. I see
SO Archiver started
but nothing after that.
Any idea why this is or how I can debug to find the cause?
You are only setting it to work, but you're not starting the timer.
protected override void OnStart(string[] args)
{
PageLoadTimer.Enabled = true;
EventLog.WriteEntry(ServiceName + " started");
}
Try this, i had a problem at some point in time, this works for me. The timer is set for 1 min in this part example
TimerCallback callbacktimer;
Timer IntervalCheck;
protected override void OnStart(string[] args) {
try {
callbacktimer = new TimerCallback(SomeMethode);
IntervalCheck = new Timer(callbacktimer, null, TimeSpan.Zero, new TimeSpan(0, 1, 0));
base.OnStart(args);
} catch (Exception ex) {
}
}
private void SomeMethode(object o) {
}

.NET BackgroundWorker RunWorkerAsync() oddly gets called twice

CODE UPDATED TO REFLECT ANSWER: SAME PROBLEM STILL OCCURS
This class is supposed to run all tasks in the list, sleep and then wake up and repeat the process infinitely. For some reason though, after the first sleep, the sleepThread.RunWorkerAsync() call gets called twice for some reason. I can obviously solve this by:
if (!sleepThread.IsBusy) { sleepThread.RunWorkerAsync(); }
but that feels like a work around.
Here is the main routine class:
public class ServiceRoutine
{
private static volatile ServiceRoutine instance;
private static object instanceLock = new object();
private static object listLock = new object();
private static readonly List<Task> taskList = new List<Task>()
{
new UpdateWaferQueueTask(),
new UpdateCommentsTask(),
new UpdateFromTestDataTask(),
new UpdateFromTestStationLogsTask(),
new UpdateFromWatchmanLogsTask(),
new UpdateStationsStatusTask()
};
private List<Task> runningTasks;
private BackgroundWorker sleepThread;
private Logger log;
private ServiceRoutine()
{
log = new Logger();
runningTasks = new List<Task>();
sleepThread = new BackgroundWorker();
sleepThread.WorkerReportsProgress = false;
sleepThread.WorkerSupportsCancellation = false;
sleepThread.DoWork += (sender, e) =>
{
int sleepTime = ConfigReader.Instance.GetSleepTime();
log.Log(Logger.LogType.Info,
"service sleeping for " + sleepTime / 1000 + " seconds");
Thread.Sleep(sleepTime);
};
sleepThread.RunWorkerCompleted += (sender, e) => { Run(); };
}
public static ServiceRoutine Instance
{
get
{
if (instance == null)
{
lock (instanceLock)
{
if (instance == null)
{
instance = new ServiceRoutine();
}
}
}
return instance;
}
}
public void Run()
{
foreach (Task task in taskList)
{
lock (listLock)
{
runningTasks.Add(task);
task.TaskComplete += (completedTask) =>
{
runningTasks.Remove(completedTask);
if (runningTasks.Count <= 0)
{
sleepThread.RunWorkerAsync();
}
};
task.Execute();
}
}
}
}
this is called like this:
ServiceRoutine.Instance.Run();
from the service start method. Here is the Task class as well:
public abstract class Task
{
private Logger log;
protected BackgroundWorker thread;
public delegate void TaskPointer(Task task);
public TaskPointer TaskComplete;
public Task()
{
log = new Logger();
thread = new BackgroundWorker();
thread.WorkerReportsProgress = false;
thread.DoWork += WorkLoad;
thread.RunWorkerCompleted += FinalizeTask;
}
protected abstract string Name { get; }
protected abstract void WorkLoad(object sender, DoWorkEventArgs e);
private string GetInnerMostException(Exception ex)
{
string innerMostExceptionMessage = string.Empty;
if (ex.InnerException == null) { innerMostExceptionMessage = ex.Message; }
else
{
while (ex.InnerException != null)
{
innerMostExceptionMessage = ex.InnerException.Message;
}
}
return innerMostExceptionMessage;
}
protected void FinalizeTask(object sender, RunWorkerCompletedEventArgs e)
{
try
{
if (e.Error != null)
{
string errorMessage = GetInnerMostException(e.Error);
log.Log(Logger.LogType.Error, this.Name + " failed: " + errorMessage);
}
else
{
log.Log(Logger.LogType.Info, "command complete: " + this.Name);
}
}
catch (Exception ex)
{
string errorMessage = GetInnerMostException(ex);
log.Log(Logger.LogType.Error, this.Name + " failed: " + errorMessage);
}
finally { TaskComplete(this); }
}
public void Execute()
{
log.Log(Logger.LogType.Info, "starting: " + this.Name);
thread.RunWorkerAsync();
}
}
The question is, why is sleepThread.RunWorkerAsync() getting called twice and is there a better way to get this work without checking if the thread is busy before calling it?
You are facing a race condition here. The problem is in the TaskComplete callback. Last two tasks remove themselves from the runningTasks list before executing the if condition. When it is executed, the list count is zero. You should lock the list before changing its. The lock needs to be taken in the TaskComplete callback:
runningTasks.Add(task);
task.TaskComplete += (completedTask) =>
{
lock (runningTasks)
{
runningTasks.Remove(completedTask);
if (runningTasks.Count <= 0)
{
sleepThread.RunWorkerAsync();
}
}
};
task.Execute();
SOLVED
I tried several different locking techniques on the runningTasks list but nothing worked. After changing runningTasks to a BlockingCollection, everything worked perfectly.
Here is the new add/remove implementation using a BlockingCollection instead of a List:
foreach (Task task in taskList)
{
runningTasks.Add(task);
task.TaskComplete += (completedTask) =>
{
runningTasks.TryTake(out completedTask);
if (runningTasks.Count <= 0 && completedTask != null)
{
sleepThread.RunWorkerAsync();
}
};
task.Execute();
}

Categories

Resources