What is the best way to run a windows service as a console?
My current idea is to pass in an "/exe" argument and do the work of the windows service, then calling Application.Run().
The reason I'm doing this is to better debug a windows service and allow easier profiling of the code. The service is basically hosting .NET remoted objects.
This is how I do it. Give me the same .exe for console app and service. To start as a console app it needs a command line parameter of -c.
private static ManualResetEvent m_daemonUp = new ManualResetEvent(false);
[STAThread]
static void Main(string[] args)
{
bool isConsole = false;
if (args != null && args.Length == 1 && args[0].StartsWith("-c")) {
isConsole = true;
Console.WriteLine("Daemon starting");
MyDaemon daemon = new MyDaemon();
Thread daemonThread = new Thread(new ThreadStart(daemon.Start));
daemonThread.Start();
m_daemonUp.WaitOne();
}
else {
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}
}
The Code Project site had a great article showing how to run a Windows Service in the Visual Studio debugger, no console app needed.
Or
C:\> MyWindowsService.exe /?
MyWindowsService.exe /console
MyWindowsService.exe -console
Related
I have created a c# service which I can run as standalone (console) application from console and also as a windows service. I want to stop run these two (stand alone exe and windows service) to run simultaneously. I want to stop launching this application as a service if i have already started this application from console as a standalone application (or) I want to stop this application starting from console if i have already stated this application as a service. i have tried some of the approaches available (Mutex approach) but they are working only for "stop launching same application twice (2 standalone applications)" but not for "stand alone windows application and windows service".
static void Main()
{
bool createdNew = true;
using (Mutex mutex = new Mutex(true, "MyService.exe", out createdNew))
{
if (createdNew)
{
//new app
MyService service = new MyService();
//Launch as console application
if (Environment.UserInteractive)
{
service.OnStartForConsole();
if (service.IsServiceStartedSuccessfully)
{
//wait for user to quite the application
Console.ReadLine();
}
}
service.OnStopForConsole();
}
else
{
//Launching as windows service
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
service
};
ServiceBase.Run(ServicesToRun);
}
}
else
{
Process current = Process.GetCurrentProcess();
foreach (Process process in Process.GetProcessesByName(current.ProcessName))
{
if (process.Id != current.Id)
{
Console.WriteLine("Already started the proces.");
break;
}
}
}
}
}
can anyone help me how can I achieve this.
thanks in advance.
//This has worked finally, but at the cost of #IInspectable comments.
if (System.Diagnostics.Process.GetProcessesByName(System.IO.Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetEntryAssembly().Location)).Count() > 1) System.Diagnostics.Process.GetCurrentProcess().Kill();
I have a console application that tracks the performance of the computer, and I am trying to make it into a Windows Service. The service installs fine, however when I go into task manager and try to run the service I get Error 1053: the service did not respond to the start or control request in a timely fashion. In the task manager the service sometimes has a "starting" status, but it will not run.
On top of that, when I run the console app, I also get an error stating that: Cannot start service from the command line or a debugger. A windows service must first be installed - which I have done.
This is my program class:
public static string ServiceName = "performanceService";
static void Main(string[] args)
{
if (!Environment.UserInteractive)
{
PerformanceCounter ramCount = new PerformanceCounter("Memory", "Available MBytes");
PerformanceCounter cpuCount = new PerformanceCounter("Processor", "% Processor Time", "_Total");
Console.WriteLine("Press any key to view other information...\n");
Console.WriteLine("CPU and RAM information");
while (!Console.KeyAvailable)
{
double perf = cpuCount.NextValue();
Console.WriteLine("CPU Performance: " + perf + " %");
... Code continues on that calculates the performance and displays it in the console...
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new ServiceControl()
};
ServiceBase.Run(ServicesToRun);
}
}
This is my ServiceControl class:
public ServiceControl()
{
ServiceName = Program.ServiceName;
InitializeComponent();
}
public void Start()
{
OnStart(null);
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
}
protected override void OnStop()
{
base.OnStop();
}
private void InitializeComponent()
{
//
// ServiceControl
//
this.ServiceName = "performanceService";
}
To install the service I have used both the Project Installer and manual install, just out of curiosity to be honest.
I changed the time limit through regedit, and that did not help.
Please let me know if you need to see additional code.
My question is, am I missing something from the code, that will not allow my service to start?
Thanks for your help.
Thank you for all your help.
The problem was that I had the Start() method in the ServiceControl class and I had my code the other way around in the Program class.
I was supposed to have the code to start the service in the if statement and the performance logic in the else, so that the start method executes quickly, like one of the comments suggested. After clicking start on the service in the task manager, the status changes to "running".
Thank you again.
I'm working on a Windows Service that hosts a WCF-webservice, which works when I run it in debug mode:
#if DEBUG
SynchroService myService = new SynchroService();
myService.OnDebugStart();
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new SynchroService()
};
ServiceBase.Run(ServicesToRun);
#endif
The OnDebugStart() just calls the OnStart() method of the Windows service and the thread that runs is just a thread that runs infinitely (untill the OnStop() is called) to check if the service is still alive & online.
protected override void OnStart(string[] args)
{
try
{
ServiceStatus serviceStatus = new ServiceStatus();
serviceStatus.dwCurrentState = ServiceState.SERVICE_START_PENDING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
syncService = new SynchroComService();
myServiceHost = new ServiceHost(syncService);
myServiceHost.Open();
syncService.StartListening();
thread = new Thread(CheckHost);
thread.Start();
serviceStatus.dwCurrentState = ServiceState.SERVICE_RUNNING;
SetServiceStatus(this.ServiceHandle, ref serviceStatus);
}
catch (Exception ex)
{
WriteError(ex);
}
}
Now, when I create the WCF service (syncService), it should run code to start up SQLDependency and start listening to the database. This works perfectly fine when I start it in debugmode, but when I run it in release, the service gets hosted, but the code doesn't execute.
I've looked everywhere for an answer or problems of the same type, but I've come up with nothing. So if anyone has every come across a problem of the same type, please do tell how you solved it.
Kind regards
The problem wasn't my code, it was with the permissions when running the service.
The service was being started as local systemaccount, but it didn't have permissions to run the service/execute the code.
To change the account that runs the service:
Open services.msc
Right click the service name
Go to the logon tab and change the account to the/an account that has the correct permissions
Restart the service
Situation
There's a windows service given and I want to implement something like an auto-update feature. For this case I call another executable file which handles the update process.
public partial class Main : ServiceBase
{
public Main()
{
InitializeComponent();
TryUpdate();
/* Some Extra Code */
}
private void TryUpdate()
{
Process proc = new Process();
proc.StartInfo.FileName = #"UpdateCheck.exe";
proc.Start();
proc.WaitForExit();
if (proc.ExitCode != 0)
{
Process proc2 = new Process();
proc2.StartInfo.FileName = #"UpdateCheck.exe";
proc2.StartInfo.Arguments = "Update";
proc2.Start();
/* Here is where I want the application to quit! */
throw new Exception();
}
}
protected override void OnStart(string[] args)
{
/* Some Extra Code */
base.OnStart(args);
}
}
When I call the TryUpdate-Function, it starts another process which determines if there's an update available or not. If there is one, I call the process again with the parameter to update the service (it basically just waits for a few seconds so that the service can shut down and then uninstalls and installs the service using an installshield setup).
Obviously it is not the smartest solution. The problem I am facing now though is the following:
When I throw an Exception to stop the service from starting (I guess?) the application crashes and tells me the service did not respond in a timely fashion (Error 1053).
Actual Question
How do I cancel a windows service properly at this state?
I'm calling Process.Start, but it blocks the current thread.
pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
// Start process
mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Trace.TraceError("Unable to run process {0}.");
}
Even when the process is closed, the code doesn't respond anymore.
But Process.Start is really supposed to block? What's going on?
(The process start correctly)
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
namespace Test
{
class Test
{
[STAThread]
public static void Main()
{
Thread ServerThread = new Thread(AccepterThread);
ServerThread.Start();
Console.WriteLine (" --- Press ENTER to stop service ---");
while (Console.Read() < 0) { Application.DoEvents(); }
Console.WriteLine("Done.");
}
public static void AccepterThread(object data)
{
bool accepted = false;
while (true) {
if (accepted == false) {
Thread hThread = new Thread(HandlerThread);
accepted = true;
hThread.Start();
} else
Thread.Sleep(100);
}
}
public static void HandlerThread(object data)
{
ProcessStartInfo pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
Console.WriteLine("Starting process.");
// Start process
Process mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Console.WriteLine("Unable to run process.");
}
Console.WriteLine("Still living...");
}
}
}
Console output is:
--- Press ENTER to stop service ---
Starting process.
Found it:
[STAThread]
Makes the Process.Start blocking. I read STAThread and Multithreading, but I cannot link the concepts with Process.Start behavior.
AFAIK, STAThread is required by Windows.Form. How to workaround this problem when using Windows.Form?
News for the hell:
If I rebuild my application, the first time I run application work correctly, but if I stop debugging and restart iy again, the problem araise.
The problem is not raised when application is executed without the debugger.
No, Process.Start doesn't wait for the child process to complete... otherwise you wouldn't be able to use features like redirected I/O.
Sample console app:
using System;
using System.Diagnostics;
public class Test
{
static void Main()
{
Process p = new Process {
StartInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe")
};
p.Start();
Console.WriteLine("See, I'm still running");
}
}
This prints "See, I'm still running" with no problems on my box - what's it doing on your box?
Create a ProcessStartInfo and set UseShellExecute to false (default value is true). Your code should read:
pInfo = new ProcessStartInfo("C:\\Windows\\notepad.exe");
pInfo.UseShellExecute = false;
// Start process
mProcess = new Process();
mProcess.StartInfo = pInfo;
if (mProcess.Start() == false) {
Trace.TraceError("Unable to run process {0}.");
}
I had the same issue and starting the executable creating the process directly from the executable file solved the issue.
I was experiencing the same blocking behavior as the original poster in a WinForms app, so I created the console app below to simplify testing this behavior.
Jon Skeet's example uses Notepad, which only takes a few milliseconds to load normally, so a thread block may go unnoticed. I was trying to launch Excel which usually takes a lot longer.
using System;
using System.Diagnostics;
using static System.Console;
using System.Threading;
class Program {
static void Main(string[] args) {
WriteLine("About to start process...");
//Toggle which method is commented out:
//StartWithPath(); //Blocking
//StartWithInfo(); //Blocking
StartInNewThread(); //Not blocking
WriteLine("Process started!");
Read();
}
static void StartWithPath() {
Process.Start(TestPath);
}
static void StartWithInfo() {
var p = new Process { StartInfo = new ProcessStartInfo(TestPath) };
p.Start();
}
static void StartInNewThread() {
var t = new Thread(() => StartWithPath());
t.Start();
}
static string TestPath =
Environment.GetFolderPath(Environment.SpecialFolder.Desktop) +
"\\test.xlsx";
}
Calls to both StartWithPath and StartWithInfo block my thread in a console app. My console does not display "Process Started" until after the Excel splash screen closes and the main window is open.
StartInNewThread will display both messages on the console immediately, while the splash screen for Excel is still open.
We had this problem when launching a .bat script that was on a network drive on a different domain (we have dual trusted domains). I ran a remote C# debugger and sure enough Process.Start() was blocking indefinitely.
When repeating this task interactively in power shell, a security dialog was popping up:
As far as a solution, this was the direction we went. The person that did the work modified domain GPO to accomplish the trust.
Start server via command prompt:
"C:\Program Files (x86)\IIS Express\iisexpress" /path:\Publish /port:8080
This take access to sub-threads of the tree process of OS.
If you want to launch process and then make the process independent on the "launcher" / the originating call:
//Calling process
using (System.Diagnostics.Process ps = new System.Diagnostics.Process())
{
try
{
ps.StartInfo.WorkingDirectory = #"C:\Apps";
ps.StartInfo.FileName = #"C:\Program Files\Microsoft Office\Office14\MSACCESS.EXE"; //command
ps.StartInfo.Arguments = #"C:\Apps\xyz.accdb"; //argument
ps.StartInfo.UseShellExecute = false;
ps.StartInfo.RedirectStandardOutput = false;
ps.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Maximized;
ps.StartInfo.CreateNoWindow = false; //display a windows
ps.Start();
}
catch (Exception ex)
{
MessageBox.Show(string.Format("==> Process error <=={0}" + ex.ToString(), Environment.NewLine));
}
}