TopShelf ConsoleHost exit on end - topshelf

I have a TopShelf based console/windows service app. I am using this as part of an automation script (in OctopusDeploy), by running the console app. However, the console app does not exit unless I press Ctrl-C. Is there a way to disable this final key press check?
Code :
class Program
{
public static void Main()
{
HostFactory.Run(x =>
{
x.Service<BatchJobService>(s =>
{
s.ConstructUsing(name => new BatchJobService());
s.WhenStarted((svc, hostControl) => svc.Start(hostControl));
s.WhenStopped((svc, hostControl) => svc.Stop(hostControl));
});
x.RunAsLocalSystem();
x.StartAutomatically();
x.SetDisplayName(serviceName);
x.SetServiceName(serviceName);
});
}
}
public class BatchJobService : ServiceControl
{
private IDisposable host;
public bool Start(HostControl hostControl)
{
if (hostControl is ConsoleRunHost)
{
**// Code for console app....
return true; // Upon exit, program does not terminate**
}
// Start code for service...
return true;
}
public bool Stop(HostControl hostControl)
{
if (hostControl is ConsoleRunHost)
{
return true;
}
// Stop code for service...
return true;
}
}

seems that it is not possible
I've checked topshelf source code ConsoleRunHost.cs and there is no way to avoid waiting for the ManualResetEvent:
try
{
_log.Debug("Starting up as a console application");
_exit = new ManualResetEvent(false);
_exitCode = TopshelfExitCode.Ok;
Console.Title = _settings.DisplayName;
Console.CancelKeyPress += HandleCancelKeyPress;
if (!_serviceHandle.Start(this))
throw new TopshelfException("The service failed to start (return false).");
started = true;
_log.InfoFormat("The {0} service is now running, press Control+C to exit.", _settings.ServiceName);
_exit.WaitOne();
}
It is done by purpose I suppose since Windows service is long-running process and it has no sense to execute the Start method of the service and exit immediately.
However I'm testing how docfx tool is executed in the Azure build pipeline so I've created console that starts docfx and exits so there no long running process but there is a need in the windows service :)

Related

how to make TCP server in xamarin that does not freeze my app

I have a TCP Server with an start method looking like :
public async Task Start()
{
using (Canceler.Token.Register(() => listener.Stop()))
{
try
{
listener.Start();
var tcpClient = await listener.AcceptTcpClientAsync();
var clientStream = tcpClient.GetStream();
while(!CloseAll)
{
while (!clientStream.DataAvailable)
{
if (CloseAll)
{
break;
}
}
Byte[] bytes = new Byte[tcpClient.Available];
clientStream.Read(bytes, 0, bytes.Length);
String data = Encoding.UTF8.GetString(bytes);
Debug(data);
}
}
catch (Exception exc)
{
Debug(exc.Message);
Canceler.Token.ThrowIfCancellationRequested();
throw;
}
}
}
And then the communication class that handles it goes like:
internal async void Init()
{
DebugMessage("initializing gameBrain");
TCP = new TCPController();
TCP.newDebugMessage += Debug;
await TCP.Start();
}
And at the topmost, in the page we have :
public MainPage(GameBrain _brain)
{
InitializeComponent();
Brain = _brain;
Brain.newMessageToUI += NewMessageFromBrain;
Brain.Init();
}
I ran the thing and it works at the beginning. The UI is responsive (I added a button with a displayAlert for testing)
I noticed that the system freezes after the TCP client connects. In the inner while of the Start but ... I thought it was expected!
I thought the Start will run in a different thread while the app get's freed of it. To be honest I was used to backgroundworkers but I'm moving from there to Tasks, and there is clearly somethign I don't get.
How should that be done ?
In C#, async and await are used to allow code to keep executing while some asynchronous process is being done. This does not at all mean that you are starting a parallel process on another thread.
When you call this:
internal async void Init()
{
(..)
await TCP.Start();
}
You are merely saying to the runtime that TCP.Start() will eventually have a point in the execution where some asynchronous process (like an HTTP request to a 3rd party) is started and that it is allowed to execute code after TCP.Start() instead of waiting for TCP.Start() to finish like a normal C# method is being treated.
If you want TCP.Start() to be run in parallel, you should create a new Task in which you call the method like in the following code (I might have flunked on the proper syntax)
internal async void Init()
{
(..)
Task.Run(async () => await TCP.Start());
}
Now the TCP.Start() method will be executed in parallel to the rest of the application.
Read more on async and await here

Start then Stop Windows Service very fast, the OnStop method did not call

I am doing a windows service (call it SampleService), every is fine. When I started then stopped service through Windows Service Management Tool (service.msc), it run properly.
But my service will be request Start and Stop by another application. So I will not use Windows Service Management Tool in this case.
This is my service implement.
using System.ServiceProcess;
public partial class SampleService : ServiceBase
{
public SampleService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
this.WriteLog("OnStart");
// Doing start service logic down here
// Some service logic like create some files.
// Or just leave it empty like a brand new Windows Service.
}
protected override void OnStop()
{
this.WriteLog("OnStop");
// Doing clean service logic down here.
// Some service logic like: delete files.
// Or just leave it empty like a brand new Windows Service.
}
static readonly object synObject = new object();
public void WriteLog(string message)
{
if (string.IsNullOrEmpty(message))
{
return;
}
// Write log.
lock (synObject)
{
using (var wr = new StreamWriter(#"C:\logfile.txt", true))
{
wr.WriteLine(DateTime.Now + "-" + message);
}
}
}
}
And this is code logic use to Start and Stop service inside my another application. I can not modify this another application. The bellow source code simulate what happen.
class Program
{
static void Main(string[] args)
{
ServiceController sc = new ServiceController("SampleService");
// start service
sc.Start();
// doing some logic cost deltaTime or just stand by in deltaTime.
Thread.Sleep(deltaTime);
try
{
// stop service first time, nothing happen.
sc.Stop();
}
catch
{
}
try
{
// stop service second times, by dump people or apllication.
sc.Stop();
}
catch
{
// It got an exception here: "The service cannot accept control messages at this time".
// But the service did stopped.
}
}
}
The problem is:"When deltaTime is too short (bellow 3000ms with empty OnStart(), OnStop()), Service will stop incorrectly. The output log OnStop will never show up, that mean OnStop method did not called.
My service will doing clean up work in OnStop (like delete some file), but if it not be called, these files still there.
I cannot change logic of another application but I can change SampleService.
I want to ask:
Is this an Windows Service base issue and I cant do anything with it?
What ever it is, can I do clean up some where else?
Thank you!

How to debug Windows Service Applications?

I'm creating a Windows Service Application in Visual Studio 2010 Ultimate SP1.
I was following 'How to' from MSDN:
http://msdn.microsoft.com/en-us/library/7a50syb3.aspx
I have encountered two problems:
I cannot start a service via Server Explorer - my service is listed there, but in the context menu I have only two options available: Refresh and Properties. There is no "Start" though MSDN documentation says that there should be that option.
Fortunately, I can avoid this hassle by using Services Control Manager.
The next step is: "In Visual Studio, choose Processes from the Debug menu".
That option doesn't exist in Debug menu. I have only "Attach to Process", but services aren't listed there.
Does somebody know what is wrong and how I am supposed to debug my application?
Thank you in advance.
As a thought: I have built a lot of Windows services and for one of many reasons, I do not create the core code in the service itself. The service is essentially the "operational layer", if you will. Creating the core code in a dll permits debugging and testing of that particular code. You can create a console or desktop app that will run the core code which can be used during development and testing phases.
Personally, I created a service runner application which captures logging in conjunction with the start and stop functionality. My OnStart and OnStop code blocks are literally identical to that of the service.
Next, when you test the service, you should be able to start the service (e.g. myService.exe) and attach to process. However, another note is that you should pause/wait the service thread (for say 30 seconds) with a debug build so you have time to attach to the process and you don't miss your initialization code. Just remember, you have to install your service then start via the Windows service manager.
Here is some code you that might point you in the direction that I use. In the service program.cs file I use the below; then in the Service OnStart() method you call your dll and run. Also, you can stop your service, replace the dll with an updated version then restart. With C# you can replace the service exe as well, but these are only C# characteristics: in C++ you cannot.
static class Program
{
public const string SERVICE_NAME = "myService";
public const string SERVICE_DISPLAY_NAME = "My Service";
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main(string[] args)
{
if (args != null && args.Length > 0)
{
foreach (string arg in args)
{
switch (arg.ToLower())
{
case "-install":
ManageService(true);
return;
case "-remove":
ManageService(false);
return;
}
}
}
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service()
};
ServiceBase.Run(ServicesToRun);
}
private static void ManageService(bool bInstall)
{
string parms;
if (bInstall == true)
{
parms = string.Format("Create {0} type= own start= demand binPath= \"{1}\" DisplayName= \"{2}\"", SERVICE_NAME,
System.Reflection.Assembly.GetExecutingAssembly().Location, SERVICE_DISPLAY_NAME);
}
else // remove
{
parms = string.Format("Delete {0}", SERVICE_NAME);
}
try
{
string output = string.Empty;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo("sc.exe", parms);
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.CreateNoWindow = true;
proc.StartInfo = startInfo;
proc.Start();
output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit(10000);
if (proc.HasExited == true)
{
// NOTE: The project type has been changed from Windows Service to Console Application
// so that Console.WriteLine will output to the console
Console.WriteLine(output);
}
else
{
proc.Close();
Console.WriteLine("Timed out waiting to install service");
}
}
catch (System.ComponentModel.Win32Exception)
{
Console.WriteLine("Unable to locate sc.exe");
}
}
}
//From the main function a method from service class can be called like below code
//DebugApp method can be called from main and so the service can be debug:
//Service class
public partial class CServices : ServiceBase
{
public CServices()
{
InitializeComponent();
}
**public void DebugApp()
{
OnStart(new string[]{});
}**
protected override void OnStart(string[] args)
{
System.Console.WriteLine("Testing");
System.Console.Read();
}
protected override void OnStop()
{
}
}
//Calling from main:
static void Main()
{
Services1.CServices uc = new CServices();
uc.DebugApp();
}

Control over exit codes in a OSGI shutdown

So I initiated a clean OSGI shutdown
Best way to shutdown an OSGi Container (specifically equinox)
I use the bundle.stop() way to achieve the same.
Now the question arises if I call a bundle.stop() in case some critical failure happens, doing a clean shutdown means that I have a process exit code of 0, Is there any way that I can send out a exit code of 1 from the process after invoking a bundle.stop(), so that the process consumer knows that this was not a normal shutdown?
Thanks!
You should use the org.eclipse.equinox.app.IApplication interface, which gives you ability to return a result from the start() method, which is then returned as exit code from the Java process. In case you don't want to use this API, the following code, shows how Equinox itself controls the exit code of the Java process:
import org.eclipse.osgi.service.environment.EnvironmentInfo;
private static EnvironmentInfo getEnvironmentInfo() {
BundleContext bc = Activator.getContext();
if (bc == null)
return null;
ServiceReference infoRef = bc.getServiceReference(EnvironmentInfo.class.getName());
if (infoRef == null)
return null;
EnvironmentInfo envInfo = (EnvironmentInfo) bc.getService(infoRef);
if (envInfo == null)
return null;
bc.ungetService(infoRef);
return envInfo;
}
public static void setExitCode(int exitCode) {
String key = "eclipse.exitcode";
String value = Integer.toString(exitCode); // the exit code
EnvironmentInfo envInfo = getEnvironmentInfo();
if (envInfo != null)
envInfo.setProperty(key, value);
else
System.getProperties().setProperty(key, value);
}
The code above is not taken one for one, but it gives the idea.

Stop Watin Testing procedure

Once we have launched watin testing procedure and IE opens and automation is on the way is there any way to interrupt that process?
Or
as we implement watin in threaded enviourment so is there any way to have information of thread running and we can terminate that thread?
Lets say we ave started thread for testing website1 , website2 and website 3 so if we want to stop automated testing for website1 I should interrupt it and make it stop where ever it was.
you can use Browser.Close and then cacth the exception System.Runtime.InteropServices.COMException
I mean you could do
public class Test
{
public void Main()
{
// Create the three browser.
Browser browser1 = new Browser();
Browser browser2 = new Browser();
Browser browser3 = new Browser();
// Start the test.
new Thread(() => doTest(test1, browser1)).Start();
new Thread(() => doTest(test2, browser2)).Start();
new Thread(() => doTest(test3, browser3)).Start();
// interrupt test 1
browser1.Close();
}
private doTest(Action<Browser> test, Browser browser)
{
try
{
// do the test
test(browser);
}
catch (System.Runtime.InteropServices.COMException)
{
// test was interrupted
}
}
private void test1(Browser browser)
{
}
private void test2(Browser browser)
{
}
private void test3(Browser browser)
{
}
}

Resources