Automatically restart a self hosted wcf service on crash - c#

I have a self hosted wcf service that is using legacy c++ code via dll import and pinvoke. There are some instances in the old code where exceptions arise from the functions (that were handled in the old app, but not in the service) and when they occur my service is stopping. The exceptions are rare; however, I do not want my service just randomly stopping as a result of a crash in another assembly. The exceptions are not bubbling up to the service so I cannot try/catch them in the service. Is there a way to automatically have the service restart on crash?
It is self hosted, not through IIS.
Thanks in advance!!

On the machine where the service is running, you can open up the Services management console (start > run > services.msc). Find your service, right-click it and choose Properties. In the popup, click on the Recovery tab. Set First, Second, and Subsequent failures all to Restart the Service.
If you are using WIX to install your project, you can also set these properties using the util:ServiceConfig element.
If you're using a standard ServiceInstaller, these options aren't built in. I'd recommend having a look at the ServiceInstaller Extension class which exposes properties through a standard service installer interface.

Well I'm assuming that you are creating a Windows Service project for what you are doing. Go into your ProjectInstaller and find the "AfterInstall" method. Here you will need to add code to execute a command on the Service Controller to set recovery options. Unfortunatly, even though .NET has a ServiceController you will need to execute the command through a process start.
using (var process = new Process())
{
var startInfo = process.StartInfo;
startInfo.FileName = "sc";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
// tell Windows that the service should restart if it fails
startInfo.Arguments = string.Format("failure \"{0}\" reset= 0 actions= restart/60000", serviceName);
process.Start();
process.WaitForExit();
exitCode = process.ExitCode;
process.Close();
}
Note: I stole this code from another question

Related

Process.Start() working but no window is popping up

I have a web API project that has a call that allows the user to basically start a separate application on the server.
Basically my web API is a gateway to remotely call this application from an MVC project.
Problem:
The problem I am facing is that the Process.Start() method is working perfectly (as in I can see the process starting on the server's task manager) but no window is popping up? I can run the application directly and see it start in its own window.
Web API Code:
public void ReconnectEPLAN()
{
if (CheckEplanConnection() == false)
{
Process process = new Process();
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = #"C:\Program Files\EPLAN\Pro Panel\2.8.3\Bin\W3u.exe"; //works but no ui poopup
process.StartInfo.CreateNoWindow = false;
process.Start();
}
}
What can I do to force the started process's app window to appear as well?
On your server, IIS runs as a service (unlike IIS Express, which runs in the user space).
Since Windows Vista, services can no longer interact with the user's desktop directly.
See:
How to run console application from Windows Service?
https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/f8f91e8f-5954-43a7-8bc4-80ed2ff1e3b1/quotallow-service-to-interact-with-desktopquot-does-not-work-on-vista?forum=windowssdk
https://www.codeproject.com/Questions/1239551/Why-does-process-start-goes-to-background-when-sta
Services cannot interact directly with the user at all: this is because services can run on a machine that doesn't have a user logged in at all, so there is no way to interact with them.

Start & Stop a Windows Service from another Windows Service

I need to control a Windows service (slave) from another one (master) on the same machine (Windows 7 or Server 2008). It's unable to either start or stop the service. What do I need to do to be control the service? The master service is written in C#
UPDATE:
The master service is meant to be a sort of watchdog - it monitors an HTTP connection to the slave and restarts the slave if the slave is non-responsive (not returning any HTTP data).
You can have the master service create a new process that creates a hidden command window with an argument that causes it to call the windows command and start or stop the service. We use this model all the time at my job, the /C will cause the command window to exit as soon as the service finishes changing state.
System.Diagnostics.Process p = new System.Diagnostics.Process ();
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo ( "cmd.exe", "/C net [start or stop] [service name]");
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
p.StartInfo = psi;
P.Start();
You will need to replace the bracketed sections of the command, and sorry if there are any syntax errors I am typing this on my tablet.
The best way to handle windows services is to use System.ServiceProcess namespace. Check it on:
https://ourcodeworld.com/articles/read/363/how-to-start-stop-and-verify-if-a-service-exists-with-c-in-winforms
But you will have some problems trying that because you will need administrator permissions to turn other services off, so you can handle that by following this link (for debug purposes you can open your VS as admin and everything will work):
How do I force my .NET application to run as administrator?

Triggering an application from a windows service cannot find file?

Background:
I created a service that will trigger the execution of an application when certain conditions have been met. This service is setup to run under the same windows user account that is used to log on to the system via RDP. I also created the .NET application that is trigger via this service. This application looks for a configuration file on disk (found in the ProgramData folder for the application) uses the settings found in the configuration file to affect the output of this application.
Problem:
When the application is ran by the user interactively the application runs great. However when the service triggers the application to run it appears that the application is not loading the correct values from the configuration files. It's almost as though the application when ran from a service has its own configuration file, and is not using the one found in ProgramData.
I'm just looking for some insight to why this may be happening. I have seem some odd behavior from Windows 7 and Windows 2008 R2 when running applications via scheduled tasks or as a service. It's almost like interactive applications and service applications have different environments on the same system running as the same user...
Note: The service executable is also found in the same folder as the triggered application. I would expect that the working directory by default would be the services running directory.
public int ExecRun()
{
Process proc = new Process();
proc.StartInfo = new ProcessStartInfo
{
FileName = "C:\\Program Files\\TEST\\runme.exe",
Arguments = "/DS:TEMP"
};
proc.Start();
proc.WaitForExit();
return proc.ExitCode;
}
Try adding the working directory info:
Process proc = new Process();
proc.StartInfo = new ProcessStartInfo
{
FileName = "C:\\Program Files\\TEST\\runme.exe",
WorkingDirectory="C:\\Program Files\\TEST",
Arguments = "/DS:TEMP"
};
It sounds like the service that triggers the execution of the application also needs to set the working directory. If you're using the Process class, you'll need to set the StartInfo.WorkingDirectory property the path where your application resides.
This has been solved.
Unfortunately, I think I wasted all your time with this question. The users is running this service on a second system (other than the one they claimed was having this issue). They copied the same configuration to both systems which would've been fine if they had setup both systems the same way, but alas they did not. The file did not exist on the system throwing the error, but both systems were setup to log exceptions to the same location.
The user had to disable the second service, or setup the configuration file correctly.

Can I stop an IIS?

In a .NET windows application to to modify a remote machine config file that is used by an ASP.NET application. However, I keep getting the error:
System.IO.IOException: The process cannot access the file '[file name]' because it is being used by another process.
Now, this may not be the problem, but I'm figuring that if I can stop the IIS, then I can modify the machine config file (without getting the exception), and then I can restart the IIS using this code:
Process proc = new Process();
proc.EnableRaisingEvents = false;
proc.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
proc.StartInfo.FileName = "iisreset";
proc.StartInfo.Arguments = serverName;
try
{
proc.Start();
proc.WaitForExit();
...
1) Is there a way to stop the IIS without restarting it, and 2) Doe this approach to changing the server.config file even make sense?
(note, I am modifying the file with regular expressions search and replace; is this a problem?)
You should be able to do something like this. I don't have windows, so I can't check the exact name of the service, but I think it is "IISADMIN" or "w3svc". Remember this should be the service name and not the display name you see in the service control panel.
ServiceController controller = new ServiceController();
controller.MachineName = "."; // or the remote machine name
controller.ServiceName = "IISADMIN"; // or "w3svc"
string status = controller.Status.ToString();
// Stop the service
controller.Stop();
// Start the service
controller.Start();
You can also use
net stop w3svc
or
net stop IISADMIN
from the commandline or in your process in your code
Strange. A .config file should not be locked exclusively.
But to answer your question, you can also use the net command for this:
net stop w3svc
to stop the www service, and
net start w3svc
to start it again.
You can also do this programmatically as described by #monkeyp
Note that I would advice against this and first try to determine (and resolve) the cause of the lock as described by #RichardOD.
Using System.Diagnostics;
//to stop ISS
ProcessStartInfo startInfo = new ProcessStartInfo("iisreset.exe", " /stop");
System.Diagnostics.Process.Start(startInfo);
//to start ISS
ProcessStartInfo stopInfo = new ProcessStartInfo("iisreset.exe", " /start");
System.Diagnostics.Process.Start(stopInfo);
You can use the IISRESET /STOP command.
If you type IISRESET /? you will get a list of other available options.
[Edit: Pass the "/STOP" switch as the arguments property on the process' startinfo object.]
Should be "iisreset /STOP" to stop the services, then "iisreset /START" to restart them.
Use a tool like wholockme or unlocker to find the root cause of the locking.
Update- another option is to use Process Explorer (thanks fretje)- this is a good option as lots of developers have this utility on their PC.
You can often just recycle or stop/start the Application Pool IIS is running, rather than restarting IIS altogether.

Add commandline arguments to service installer c#

I am working on an application which starts as a service but only if a commandline switch tells it to (otherwise a standard form is opened). So when the service is started by Windows at bootup, it must pass this commandline option or the service fails to start.
I would like to have the installer (ServiceProcessInstaller) add a commandline option so that when the service is started it adds the commandline option to the command.
Example:
MyService.exe -commandlineoption
I thought this was what the ServiceProcessorInstaller.Context property was for, but that is for the arguments that were executed on InstallUtil.
Any suggestions?
When I've added command-line options to services, I've always defaulted to running as a service. However, I know that the opposite is possible because it's how SvcHost works: it's an EXE that's always configured to load DLL's as services.
A service is only installed once per release. It sounds like you are talking about passing a command line argument to the service when it's started.
You can pass command line arguments to the service when you start it using the ServiceController.Start method:
using (var controller = new ServiceController("servicename")) {
controller.Start(arg0, arg1);
}

Categories

Resources