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);
}
}
}
Related
I'm trying to create a Multi-Threaded Named Pipe Server which can handle multiple requests in parallel. See below for my code.
The behaviour is not as expected. If new requests come in while the current one is busy it throws "access to the path is denied" error until the current executing thread is released.
Any idea what could be the problem ?
using Newtonsoft.Json;
using System;
using System.IO;
using System.IO.Pipes;
using System.Security.AccessControl;
using System.Security.Principal;
using System.Text;
using System.Threading;
namespace API.PipeServer
{
public class Server
{
private bool running;
private Thread runningThread;
private EventWaitHandle terminateHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
public string PipeName { get; set; }
private void ServerLoop()
{
while (running)
{
ProcessNextClient();
}
terminateHandle.Set();
}
public void Run()
{
running = true;
runningThread = new Thread(ServerLoop);
runningThread.Start();
}
public void Stop()
{
running = false;
terminateHandle.WaitOne();
}
public virtual string ProcessRequest(string message)
{
return "";
}
public void ProcessClientThread(object o)
{
using (NamedPipeServerStream pipeStream = (NamedPipeServerStream)o)
{
StreamReader sr = new StreamReader(pipeStream);
//Receive instruction message
string instructionJson = sr.ReadLine();
Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}: --- Receiving Instruction ---");
Console.WriteLine(instructionJson);
//Getting instruction message
var instruction = JsonConvert.DeserializeObject<InstructionHandler.Instruction>(instructionJson);
//Get data
var json = API.API.GetAPIJson(instruction);
//Send data back to Python client
try
{
pipeStream.Write(Encoding.UTF8.GetBytes(json));
pipeStream.WaitForPipeDrain();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}: --- Closing Stream ---");
pipeStream.Close();
pipeStream.Dispose();
}
}
public void ProcessNextClient()
{
try
{
Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}: Creating server");
PipeSecurity pipeSecurity = new PipeSecurity();
pipeSecurity.AddAccessRule(new PipeAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), PipeAccessRights.ReadWrite, AccessControlType.Allow));
var pipeStream = NamedPipeServerStreamAcl.Create("test_api", PipeDirection.InOut, 254, PipeTransmissionMode.Message, PipeOptions.None, 1024, 1024, pipeSecurity);
pipeStream.WaitForConnection();
//Spawn a new thread for each request and continue waiting
Thread t = new Thread(ProcessClientThread);
t.Start(pipeStream);
}
catch (Exception e)
{
Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}: Error - {e.Message}");
}
}
}
}
Below is a typical output:
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 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 ?
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)
}
I have to establish an HttpListener that will wait for requests made by our client's server. I have to receive that request on port 8088 and extract the query string. That is the easy part.
I'm running the HttpListener in a windows service. I cannot get it to fire properly. I build the setup project install the service on our server and it never starts. I suspect there's an error with my code.
HttpListenerClass:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Threading;
namespace lalalolo
{
class HttpListenerClass
{
bool keepAlive = true;
public void AddToFile(string contents)
{
var fs = new FileStream(#"C:\HttpListenerserv.txt", FileMode.OpenOrCreate, FileAccess.Write);
var sw = new StreamWriter(fs);
sw.BaseStream.Seek(0, SeekOrigin.End);
sw.WriteLine(contents);
sw.Flush();
sw.Close();
}
private HttpListener listener;
public HttpListenerClass()
{
ThreadPool.SetMaxThreads(50, 100);
ThreadPool.SetMinThreads(50, 50);
listener = new HttpListener();
listener.Prefixes.Add("http://*:8088/");
}
public void Start()
{
listener.Start();
if(keepalive == true){
{
try
{
HttpListenerContext ctx = listener.GetContext();
ThreadPool.QueueUserWorkItem(new WaitCallback(ProcessRequest), ctx);
}
catch(Exception ex)
{
AddToFile(ex.Message);
}
}
}
}
public void Stop()
{
listener.Stop();
keepalive == false;
}
public void ProcessRequest(object listenerContext)
{
try
{
var context = (HttpListenerContext)listenerContext;
string QS = context.Request.QueryString["ID"];
AddToFile(QS);
}
catch(Exception ex)
{
AddToFile(ex.Message);
}
}
}
}
Service1.cs:
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.ServiceProcess;
using System.Text;
using System.Threading;
namespace lalalolo
{
public partial class HttpListenerTest1 : ServiceBase
{
HttpListenerClass HTTP = new HttpListenerClass();
public void AddToFile(string contents)
{
var fs = new FileStream(#"C:\HttpListenerserv.txt", FileMode.OpenOrCreate, FileAccess.Write);
var sw = new StreamWriter(fs);
sw.BaseStream.Seek(0, SeekOrigin.End);
sw.WriteLine(contents);
sw.Flush();
sw.Close();
}
public HttpListenerTest1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
HTTP.Start();
}
protected override void OnStop()
{
HTTP.Stop();
}
}
}
What am I doing wrong?
Thank you guys!
Queuing worker items in a while(true) loop? Are you serious?!
Your OnStart method never returns because of that while loop. However, returning from the OnStart method is essential for the service manager to know, that your service started correctly.
Your service will probably just die with an OutOfMemoryException or something similar, because of that endless loop.
Suggestion:
Try adopting this sample. It is in IronPython but that also uses the .NET framework. Hint: The while(true) in that implementation should be changed to be able to break the while loop when your service is being stopped. Additionally, you must call serveforever in your Start method in an async way.
This should get you going.