I am trying to create a windows service which periodically queries data from db and executing tasks based on the data.
I used threading and the following code terminates immediately after I run it.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace MESUDeleteService
{
public partial class MESDeleteService : ServiceBase
{
AutoResetEvent StopRequest = new AutoResetEvent(false);
private Thread _thread;
public MESDeleteService()
{
InitializeComponent();
}
public void startConsole()
{
OnStart(null);
}
protected override void OnStart(string[] args)
{
MESUDeleteService.Core.Logger.Writelog.Info("Deletion Service Start");
_thread = new Thread(WorkerThreadFunc);
_thread.IsBackground = true;
_thread.Start();
}
public void WorkerThreadFunc()
{
for (; ; )
{
if (StopRequest.WaitOne(10000)) return;
try
{
SNDX.DataAccess.UnitOfWork uow = new SNDX.DataAccess.UnitOfWork();
var deleteOrderCollection = uow.DeleteSettingsRepository
.Get()
.Where(m => m.STATUS == "ACTIVE" && m.NEXTRUN != null)
.Where(n => n.NEXTRUN.Value.ToString("{0:yyyyMMddHHmm}") == DateTime.Now.ToString("{0:yyyyMMddHHmm}"))
.ToList<SNDX.DataAccess.SND_DELETE_SETTINGS>();
if (deleteOrderCollection.Count > 0)
{
MESUDeleteService.Core.Logger.Writelog.Info("There'r new Delete Orders");
//process each delete orders
foreach (SNDX.DataAccess.SND_DELETE_SETTINGS x in deleteOrderCollection)
{
MESUDeleteService.Core.Logger.Writelog.Info("Delete Type : " + x.SETTINGS);
MESUDeleteService.Core.DeleteOrder deleteOrder = new MESUDeleteService.Core.DeleteOrder();
deleteOrder.Settings = x.SETTINGS;
deleteOrder.SearchPattern = x.SEARCHPATTERN;
deleteOrder.NetworkPath = x.NETWORKPATH;
deleteOrder.EmailList = x.EMAILLIST;
deleteOrder.ID = x.ID;
deleteOrder.LastRun = DateTime.Now;
deleteOrder.WeekRun = x.WEEKRUN;
deleteOrder.ComputerName = x.COMPUTERNAME;
deleteOrder.DomainName = x.DOMAINNAME;
deleteOrder.ADAccount = x.ADACCOUNT;
deleteOrder.ADPassword = x.ADPASSWORD;
//by having them in a thread.
Thread t = new Thread(new ThreadStart(deleteOrder.ThreadStart)) { IsBackground = true };
t.IsBackground = true;
MESUDeleteService.Core.Logger.Writelog.Info("Delete Thread Starting Type");
t.Start();
}
}
uow.Dispose();
}
catch (Exception ex)
{
MESUDeleteService.Core.Logger.Writelog.Error(ex.Message);
}
}
}
protected override void OnStop()
{
StopRequest.Set();
_thread.Join();
}
}
}
However, if I removed isBackground=true, it will run normally, but it will consume alot of CPU power.
With isBackground=true, the service/app terminates #
SNDX.DataAccess.UnitOfWork uow = new SNDX.DataAccess.UnitOfWork();
How can I optimize this code ?
Related
Hi i've a problem getting location each 1-5 minutes with a Foreground Service, when I unplug the device and turn off the screen, the thread stops but the service notification is visible all time,
how can i prevent this?
i was reading about to use AlarmManager (is a real solution), how can i do it ? or should only foreground service do it by self
this is my code:
using Android.App;
using Android.Content;
using Android.Locations;
using Android.OS;
using Android.Text.Format;
using Invima.VehiculosApp.ViewModels;
using Java.Util;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Invima.VehiculosApp
{
[Service(Label = "LocationUpdatesService", Enabled = true, Exported = true)]
[IntentFilter(new string[] { "com.Antss.InvimaVehiculos.Service" })]
public class LocationService : Service
{
IBinder Binder;
public override IBinder OnBind(Intent intent)
{
return Binder;
}
public const int ServiceRunningNotifID = 9000;
Ruta ruta;
Thread hiloUbicacion;
private System.Timers.Timer timer;
public override void OnCreate()
{
Notification notif = DependencyService.Get<INotification>().ReturnNotif();
StartForeground(ServiceRunningNotifID, notif);
_ = TomarUbicaciones();
base.OnCreate();
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
string rutaStr = intent.GetStringExtra("ruta");
this.ruta = JsonConvert.DeserializeObject<Ruta>(rutaStr);
var autoEvent = new AutoResetEvent(false);
// i tried this but ... the same problem
timer = new System.Timers.Timer(30000);
timer.Elapsed += async (object sender, System.Timers.ElapsedEventArgs e) =>
{
using (HttpClient cl = new HttpClient())
{
await cl.GetAsync("https://webhook.site/a718fef4-769b-4871-87a8-ec1ccd83fc50");
}
};
timer.Start();
return StartCommandResult.Sticky;
}
public int TomarUbicaciones()
{
hiloUbicacion = new Thread(TomarUbicacionAsync);
hiloUbicacion.Start();
return 1;
}
int contador = 0;
public async void TomarUbicacionAsync()
{
while (true)
{
try
{
var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);
if (location != null && ruta != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
App.BD.RutaUbicacion.Add(new RutaUbicacion
{
Fecha = DateTime.Now,
IdRuta = ruta.IdRuta,
Latitud = (decimal)location.Latitude,
Longitud = (decimal)location.Longitude,
Altitud = (decimal)location.Altitude
});
App.BD.SaveChanges();
App.Sincronizar();
}
Device.BeginInvokeOnMainThread(() =>
{
DependencyService.Get<IMessage>().ShortAlert("Done!");
});
}
catch (Exception ex)
{
}
Thread.Sleep(60000); // each minute
}
}
public override void OnDestroy()
{
try
{
hiloUbicacion.Abort();
}
catch { }
base.OnDestroy();
}
public override bool StopService(Intent name)
{
try
{
hiloUbicacion.Abort();
}
catch { }
return base.StopService(name);
}
}
}
I have made a Windows Service in C# that calls a python script to run. This works without a problem. However, when I go to stop the service, it gives the error "could not be stopped" and I have to manually kill it using the PID in the command line. This hasn't always been like this and I can't seem to find previous versions of my code in VS2017. What part of my code is causing the Windows service to not be able to close?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Timers;
using System.Threading;
using System.Security.Permissions;
namespace WindowsService1
{
public partial class Service1 : ServiceBase
{
public ThreadStart startScript;
public Thread PyScriptThread;
public ServerClass serverObject;
//-------------------------------------------------------------------------
public Service1() { InitializeComponent(); }
//-------------------------------------------------------------------------
protected override void OnStart(string[] args)
{
serverObject = new ServerClass();
PyScriptThread = new Thread(new ThreadStart(serverObject.PyScript));
var t = Task.Run(() => serverObject.PyScriptAsync(PyScriptThread));
}
//-------------------------------------------------------------------------
protected override void OnStop()
{
try
{
StreamWriter sw = new StreamWriter(#"C:\Users\bakere1\A19149\Projects\text_doc.txt", false);
sw.Write("***STOP***");
sw.Close(); //stop the script within the process
if (!serverObject.p.HasExited) //kill the process within the thread
{
serverObject.p.CancelErrorRead();
serverObject.p.CancelOutputRead();
serverObject.p.CloseMainWindow();
serverObject.p.Refresh();
serverObject.p.Close();
serverObject.p.Kill();
serverObject.p.Dispose();
}
serverObject.PyScriptAsync(PyScriptThread).Dispose();
killPyThread(PyScriptThread); //kill the overarching thread
base.OnStop();
}
catch (Exception ex)
{
if (ex is IOException || ex is ThreadInterruptedException || ex is ThreadAbortException || ex is InvalidOperationException)
{
StreamWriter errorSW = new StreamWriter(#"C:\Users\bakere1\A19149\Projects\text_doc.txt", true);
errorSW.Write("Error occurred: Stacktrace/Message/Source", ex.StackTrace, ex.Message, ex.Source);
errorSW.Close();
}
}
}
//-------------------------------------------------------------------------
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
public void killPyThread(Thread thread)
{
thread.Interrupt();
thread.Abort();
}
}
public class ServerClass
{
public event System.EventHandler serviceChanged;
public Process p;
//-------------------------------------------------------------------------
public async Task PyScriptAsync(Thread thread)
{
await Task.Delay(10000).ConfigureAwait(false);
thread.Start();
}
public void PyScript()
{
string fileName = #"C:\Users\bakere1\A19149\Projects\BLE_Advertiser.py";
p = new Process
{
StartInfo = new ProcessStartInfo(#"C:\Python36_64\python.exe", fileName)
{
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = false
}
};
p.Start();
p.WaitForExit();
p.CancelErrorRead();
p.CancelOutputRead();
p.CloseMainWindow();
p.Refresh();
p.Close();
p.Kill();
p.Dispose();
return;
}
//-------------------------------------------------------------------------
protected virtual void onServiceChanged()
{
serviceChanged?.Invoke(this, EventArgs.Empty);
}
}
}
I'm doing a small windows service, it reads from a web service and stores the data in a local database, however, it does not finish executing the while (while it's a service), when I'm debugging it in vs 15 it works perfectly , Follow the code below.
PS: The code I used to debug I comment it before it starts, it arrives to enter the while, but only the first line and does not check the rest.
Program.cs
using System.ServiceProcess;
namespace rdi_server.service
{
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
}
}
}
Service1.CS
using System;
using System.Configuration;
using System.ServiceProcess;
using System.Threading;
namespace rdi_server.service
{
public partial class Service1 : ServiceBase
{
private Thread _thread;
private Updater _updater = new Updater();
private readonly int Interval = Convert.ToInt32(ConfigurationManager.AppSettings["timer"]);
private readonly string Connection = ConfigurationManager.AppSettings["connection"];
private readonly Connector _usuarioConnector;
private readonly Connector _bandaConnector;
private readonly Connector _generoConnector;
private readonly Connector _musicaConnector;
public Service1()
{
_usuarioConnector = new Connector("UsuarioBase");
_bandaConnector = new Connector("BandaBase");
_generoConnector = new Connector("GeneroBase");
_musicaConnector = new Connector("MusicaBase");
InitializeComponent();
}
protected override void OnStart(string[] args)
{
StartDebug();
}
public void StartDebug()
{
_thread = new Thread(OnTime);
_thread.Name = "My Worker Thread";
_thread.Start();
}
protected override void OnStop()
{
}
protected void OnTime()
{
while (true)
{
EventLog.WriteEntry("Dentro do WHILE foi executado!");
_updater.Do(Connection, _usuarioConnector, _generoConnector, _bandaConnector, _musicaConnector);
EventLog.WriteEntry("Fim do while");
Thread.Sleep(Interval);
}
}
}
}
Updater.CS
using rdi_musica.core;
using System.Collections.Generic;
using System.Data.SqlClient;
namespace rdi_server.service
{
class Updater
{
public void Do(string Connection,
Connector usuario,
Connector genero,
Connector banda,
Connector musica)
{
var usuarios = Loader.LoadUsuarios(usuario);
var generos = Loader.LoadGeneros(genero);
var bandas = Loader.LoadBandas(banda);
var musicas = Loader.LoadMusicas(musica);
using (var connection = new SqlConnection(Connection))
{
connection.Open();
foreach (var _usuario in usuarios)
{
DomainDAO.InsertUsuario(connection, _usuario);
}
foreach (var _genero in generos)
{
DomainDAO.InsertGenero(connection, _genero);
}
foreach (var _banda in bandas)
{
DomainDAO.InsertBanda(connection, _banda);
}
foreach (var _musica in musicas)
{
DomainDAO.InsertMusica(connection, _musica);
}
}
}
}
}
What's probably happening is you have an unhandled exception happening somewhere, which is breaking out of your while loop.
You can use the windows event log in combination with try-catch to log your errors, without breaking your infinite loop:
protected void OnTime()
{
while (true)
{
try
{
EventLog.WriteEntry("Dentro do WHILE foi executado!");
_updater.Do(Connection, _usuarioConnector, _generoConnector, _bandaConnector, _musicaConnector);
EventLog.WriteEntry("Fim do while");
}
catch (Exception ex)
{
this.EventLog.WriteEntry("ERROR: " + ex.GetType().ToString() + " : " + ex.Message + " : " + ex.StackTrace, EventLogEntryType.Error);
}
Thread.Sleep(Interval);
}
}
I have following problem with the windows service I was writing:
When I start the service it stops immediately. When I was using a console app it wasn't crushing. I have no idea what's the cause of this problem.
Here's the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.ServiceModel;
using System.ServiceProcess;
using System.Configuration;
using System.Configuration.Install;
using WindowsService;
namespace WS
{
[ServiceContract(Namespace = "http://WS")]
public interface INewsReader
{
}
public class NewsReaderService : INewsReader
{
public NewsReaderService()
{
var config = new Config();
var scheduled = new Schedule(config);
scheduled.ExecuteScheduledEvents();
while (true)
{
System.Threading.Thread.Sleep(1000);
int i = 0;
}
}
}
public class NewsReaderWindowsService : ServiceBase
{
public ServiceHost serviceHost = null;
public NewsReaderWindowsService()
{
ServiceName = "NewsReaderWindowsService";
}
public static void Main()
{
ServiceBase.Run(new NewsReaderWindowsService());
}
protected override void OnStart(string[] args)
{
var thread = new System.Threading.Thread(() =>
{
while (true)
{
int i = 0;
System.Threading.Thread.Sleep(1000);
}
});
thread.Start();
serviceHost = new ServiceHost(typeof(NewsReaderService));
serviceHost.Open();
}
protected override void OnStop()
{
}
}
[RunInstaller(true)]
public class ProjectInstaller : Installer
{
private ServiceProcessInstaller process;
private ServiceInstaller service;
public ProjectInstaller()
{
process = new ServiceProcessInstaller();
process.Account = ServiceAccount.LocalSystem;
service = new ServiceInstaller();
service.ServiceName = "NewsReaderWindowsService";
Installers.Add(process);
Installers.Add(service);
}
}
}
Well, first of all I think your OnStart method is written badly. I can't see the reason for creating a, basicly, empty thread. You should there only initialize service (If necessary), immediately start a new thread that will work for whole time and leave the OnStart method.
Second of all use try catch block, because in my opinion somewhere in there is exception and that's why your windows service stops.
Thirdly see this example WCF Hosting with Windows Service
I have some big trouble with serial requests.
Description from what i want:
establish a serial connection, send serial requests to 6 temperature
sensors one by one (this is done every 0,5 second in a loop)
the question and answer-destination is stored in a List array
every request is started in a separate thread so the gui does not bug
while the programme waits for the sensor-hardware to answer
My problem:
The connection and the request is working fine, but if I am browsing data at the local hard drive the answer from the sensor-unit gets destroyed (negative algebraic sign or value from other sensor or simply wrong value).
How does this happen or how can I solve this?
Where I guess the problem might be:
In the private void ReceiveThread() of class SerialCommunication
Here is my code:
Class CommunicationArray:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Hardwarecommunication
{
public class CommunicationArray
{
public string request { get; set; }
public object myObject { get; set; }
public string objectType { get; set; }
}
}
Class SerialCommunication
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.IO;
using System.IO.Ports;
using System.Windows.Forms;
namespace Hardwarecommunication
{
class SerialCommunication
{
Thread t2;
Thread t;
private SerialPort serialPort = new SerialPort("COM2", 115200, Parity.Even, 8, StopBits.One);
string serialAnswer = "";
private volatile bool _shouldStop;
private int counter;
List<CommunicationArray> ar = new List<CommunicationArray>();
object[] o = new object[3];
public void addListener(string request, object myObject, string objectType)
{
CommunicationArray sa = new CommunicationArray();
sa.request = request;
sa.myObject = myObject;
sa.objectType = objectType;
ar.Add(sa);
}
public void startListen()
{
t2 = new Thread(() => writeSerialPortThread());
t2.Start();
}
public void startSerialPort2()
{
try
{
serialPort.Open();
//MessageBox.Show("Connection opend!");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
public void stopSerialPort2()
{
try
{
if (serialPort.IsOpen == true)
// Connection closed
serialPort.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void writeSerialPortThread()
{
string request = "";
for (int i = 0; i < ar.Count(); i++)
{
request = ar[i].request;
//request = ((object[])ar[0])[0].ToString();
//if (!t.IsAlive)
//{
try
{
t = new Thread(ReceiveThread);
_shouldStop = false;
//MessageBox.Show("start thread");
t.Start();
serialPort.Write(request);
Thread.Sleep(50);
_shouldStop = true;
t.Join();
}
catch
{
}
Label tmpLabelObject = (Label)ar[i].myObject;
serialAnswer = serialAnswer.Replace("=", "");
if (tmpLabelObject.InvokeRequired)
{
MethodInvoker UpdateLabel = delegate
{
tmpLabelObject.Text = serialAnswer;
};
try
{
tmpLabelObject.Invoke(UpdateLabel);
}
catch
{
}
}
}
}
private void ReceiveThread()
{
//MessageBox.Show("in thread");
while (!_shouldStop)
{
serialAnswer = "";
try
{
//MessageBox.Show("in thread");
serialAnswer = serialPort.ReadTo("\r");
if (serialAnswer != "")
{
}
return;
}
catch (TimeoutException) { }
}
}
}
}
Class Form1 //to establish the connection and to start the Sensor request
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Hardwarecommunication
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private SerialCommunication serialCommunication1 = new SerialCommunication();
private void Form1_Load(object sender, EventArgs e)
{
//start up serial connection
serialCommunication1.startSerialPort2();
}
private void buttonStart_Click(object sender, EventArgs e)
{
timerRecord.Enabled = true;
if (this.buttonStart.Text == "Start")
this.buttonStart.Text = "Stop";
else
this.buttonStart.Text = "Start";
}
private void timerRecord_Tick(object sender, EventArgs e)
{
if (this.buttonStart.Text == "Stop")
{
this.serialCommunication1.startListen();
}
}
private void buttonFillRequestArray_Click(object sender, EventArgs e)
{
this.serialCommunication1.addListener("$0BR00\r" + "\r", this.labelResult0, "label0"); //request to the hardware
this.serialCommunication1.addListener("$0BR01\r" + "\r", this.labelResult1, "label1");
this.serialCommunication1.addListener("$01R00\r" + "\r", this.labelResult2, "label2");
this.serialCommunication1.addListener("$01R01\r" + "\r", this.labelResult3, "label3");
this.serialCommunication1.addListener("$01R02\r" + "\r", this.labelResult4, "label4");
}
}
}
I woud be happy about any try to fix the problem.
I coud also upload the solution as .zip but you can't test it at all because you do not have the sensor hardware.
Note: serialPort.Write(string) is a non-blocking store into the output buffer.
That means the following won't guarantee you've even finished writing your request before you stop listening for a response:
serialPort.Write(request);
Thread.Sleep(50);
_shouldStop = true;
You could add:
while( serialPort.BytesToWrite > 0 ) Thread.Sleep(1); // force blocking
but it's ill advised.
One thing I'm wondering. There is only a single serial port here. Why do you want many different threads to work with it when you could manage the entire serial port interaction with a single thread? (Or at worse, 1 thread for input 1 thread for output)
To me it makes a lot more sense to store up requests into a queue of some kind and then peel them off one at a time for processing in a single thread. Responses could be similarly queued up or fired as events back to the caller.
EDIT: If you don't mind one read/write cycle at a time you could try:
string response;
lock(serialPort) {
// serialPort.DiscardInBuffer(); // only if garbage in buffer.
serialPort.Write(request);
response = serialPort.ReadTo("\r"); // this call will block till \r is read.
// be sure \r ends response (only 1)
}