I install and start a service with my C# console application.
Installing the service using WinAPI:
try
{
//Open sc manager
IntPtr sc_handle = OpenSCManager(null, null, SC_MANAGER_CREATE_SERVICE);
if (sc_handle.ToInt32() != 0)
{
//Create service
IntPtr sv_handle = CreateService(sc_handle, svcName, svcDispName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, svcPath, null, 0, null, null, null);
//If failed
if (sv_handle.ToInt32() == 0)
{
CloseServiceHandle(sc_handle);
return false;
}
else //If succeeded
{
CloseServiceHandle(sv_handle);
CloseServiceHandle(sc_handle);
return true;
}
}
else
return false;
}
catch (Exception e)
{
throw e;
}
Starting the service:
//Start the newly installed service
try
{
System.ServiceProcess.ServiceController newService = GetService(application.StartupName);
//If service is stopped or stopping
if (newService.Status == System.ServiceProcess.ServiceControllerStatus.StopPending ||
newService.Status == System.ServiceProcess.ServiceControllerStatus.Stopped)
{
newService.Start();
newService.WaitForStatus(System.ServiceProcess.ServiceControllerStatus.Running, TimeSpan.FromMilliseconds(300.0));
}
return true;
}
catch (Exception e)
{
return false;
}
When setting up a service I install and start it.
When I do this for a very simple service (which does nothing but log its events to a text file), it fails the first time when trying to start the service.
It is the call to WaitForStatus which fails (timeout error).
If I uninstall the service (sc delete servicename), delete the file it logged too and install/start the service again under the same OR a different name, it works fine every time.
If I uninstall the service and search the registry for the service name, there are no results.
I've tried this troubleshooting on 3 different machines (windows 8 and windows 7). I have no other machines to test with and cannot recreate the problem. I even did a system restore to a point BEFORE installing/starting the service for the first time and it still worked without error.
Anyone got any ideas?
Related
I am trying to get application pool status from within a web application. Application pool I am interested in is "ABC" but when I check for it by name I get nothing and when I inspect the available pools by name (i.e. manager.ApplicationPools) they show as Clr4ClassicAppPool, Clr4IntegratedAppPool, ... so I never find a match.
This is what I am using
public static int GetAppPoolStatus(string sAppPoolName)
{
int iRet = -1;
try
{
using (ServerManager manager = new ServerManager())
{
ApplicationPool appPool = manager.ApplicationPools.FirstOrDefault(ap => ap.Name == sAppPoolName);
if (appPool != null)
{
//Get the current state of the app pool
iRet = (int)appPool.State; // 0: Starting, 1: Started, 2: Stopping, 3: Stopped
}
else
{
}
}
}
catch (Exception ex)
{ }
return iRet;
}
The GAC version (7.9.0.0) was part of IIS Express, and is resolved by MSBuild when compiling your project if your project file does not explicitly point to %SystemRoot%\system32\inetsrv\Microsoft.Web.Administration.dll.
The ultimate solution (if not to uninstall IIS Express) is to add a reference explicitly to %SystemRoot%\system32\inetsrv\Microsoft.Web.Administration.dll to consume the right metadata at compile time. It has side effects, but still a reliable way. And at runtime, use assembly redirection to stick to version 7.0.0.0.
More tips can be found in this post
I am trying to send a command to my service TestService from a program running as administrator, I am able to start/stop it just fine, but whenever I try to ExecuteCommand() I encounter an Exception:
Cannot control service on computer '.'.
try
{
System.ServiceProcess.ServiceController service = new System.ServiceProcess.ServiceController("TestService");
if (service.Status == ServiceControllerStatus.Stopped)
{
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running);
}
service.ExecuteCommand(100); // Causes Exception every time
}
catch (Exception e)
{
MessageBox.Show(e.Message);
throw e;
}
This is happening is because ExecuteCommand only accepts integers: 128-256, anything under 128 is system reserved and since 100 is being passed the Exception occurs.
Replacing service.ExecuteCommand(100) with something like service.ExecuteCommand(130) will work just fine.
I have a WCF Service hosted in a Windows service as described here.
I have scheduled nightly restart of the service, but sometimes the restart fails and the service remains/hangs in Stopping state and the EXE process has to be killed manually. It looks likely that it hangs on line _ESSServiceHost.Close();, because nothing after that line is logged it the log file. It is possible but not very likely that the service gets the stop request when it is busy.
Moreover the underlying process cannot be killed because it is dependent on services.exe, so only server restart works.
What could be wrong with this approach?
protected override void OnStop()
{
try
{
if (_ESSServiceHost != null)
{
_ESSServiceHost.Close();
_ESSServiceHost = null;
//Never reaches the following line
Tools.LogInfo("Services stopped.");
}
}
catch (Exception ex)
{
Tools.LogError(ex.Message);
}
This is how I stop the service:
private bool StopService(ServiceController scESiftServer)
{
int i = 0;
if (scESiftServer.Status == ServiceControllerStatus.Running)
{
try
{
scESiftServer.Stop();
}
catch (Exception ex)
{
Tools.LogEvent("Exception ...");
return false;
}
while (scESiftServer.Status != ServiceControllerStatus.Stopped && i < 120)
{
Thread.Sleep(1000);
scESiftServer.Refresh();
i++;
}
}
if (scESiftServer.Status != ServiceControllerStatus.Stopped)
{
//This line gets executed
Tools.LogEvent("Failed within 120 sec...");
return false;
}
else
{
Tools.LogEvent("OK ...");
}
return true;
}
Could something like this help?
var task = Task.Run(() => _ESSServiceHost.Close(TimeSpan.FromSeconds(299)));
if (!task.Wait(TimeSpan.FromSeconds(300)))
{
_ESSServiceHost.Abort();
}
But _ESSServiceHost.Abort() should be called internally by the Close method if needed.
Target framework is 4.5, installed is .NET 4.7.2.
Found out that probably the service hangs after series of malformed requests. Expected record type 'Version', found '71'. etc.
I have found in the svclog file that my service hangs after series of malformed request that happen on Saturday and Sunday at approx. 5:15 AM. The error messages were Expected record type 'Version', found '71'., Error while reading message framing format at position 0 of stream (state: ReadingVersionRecord). But I could not find the cause of theese malformed request series, so I tried to fix the service to withstand the "attack".
I have modified the OnStop method as follows:
protected override void OnStop()
{
try
{
if (_ESSServiceHost != null)
{
Tools.LogInfo("Stopping ESService.");
var abortTask = Task.Run(() => _ESSServiceHost.Abort());
var closeTask = Task.Run(() => _ESSServiceHost.Close(TimeSpan.FromSeconds(300)));
try
{
if (_ESSServiceHost.State == CommunicationState.Faulted)
{
Tools.LogInfo("ESSServiceHost.State == CommunicationState.Faulted");
if (!abortTask.Wait(TimeSpan.FromSeconds(60)))
Tools.LogInfo("Failed to Abort.");
}
else
{
if (!closeTask.Wait(TimeSpan.FromSeconds(301)))
{
Tools.LogInfo("Failed to Close - trying Abort.");
if (!abortTask.Wait(TimeSpan.FromSeconds(60)))
Tools.LogInfo("Failed to Abort.");
}
}
}
catch (Exception ex)
{
Tools.LogException(ex, "ESSServiceHost.Close");
try
{
Tools.LogInfo("Abort.");
if (!abortTask.Wait(TimeSpan.FromSeconds(60)))
Tools.LogInfo("Failed to Abort.");
}
catch (Exception ex2)
{
Tools.LogException(ex2, "ESSServiceHost.Abort");
}
}
_ESSServiceHost = null;
Tools.LogInfo("ESService stopped.");
}
}
catch (Exception ex)
{
Tools.LogException(ex,"OnStop");
}
}
Today on Monday I have checked the svclog and the "attacks" with malformed request remained there but my service lived happily through it. So it seemed to be fixed. Moreover only:
Stopping ESService.
ESService stopped.
events were logged in my log file. No aborts etc. So I guess that putting the Close call on a separate thread fixed the problem but absolutely do not know why.
I am using the following code to stop my WCF service from its own thread to update some files that are used by my service.
try
{
var server = new ServerManager();
var site = server.Sites.FirstOrDefault(s => s.Name == "Default Web Site");
if (site != null)
{
Thread.Sleep(1000);
site.Stop();
if (site.State == ObjectState.Stopped)
{
Thread.Sleep(5000);
}
site.Start();
}
else
{
throw new FaultException("Server Are Trying To Stop Is not Found");
}
}
catch (Exception ex)
{
throw new FaultException(ex.Message);
}
But I get following error when I execute the code:
"Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))"
I think you should run Powershell script for such case, as you want to stop the process which is self as I understand. Meaning that after stop, your process will be killed and no update can be performed. With power shell you could stop process, copy over files and start over
Import-Module WebAdministration
Stop-WebSite 'Default Web Site'
#... copy files here
Start-WebSite 'Default Web Site'
For a project I have to start an application in C#, rip out the AutomationElement tree related to the process, and then close the application and output the tree. I'm doing this by opening the application using Process.Start. Then I'm finding the AutomationElements related to the spawned process and walking the tree using a combination of TreeWalker and AutomationElement's FindFirst and FindAll methods.
This runs fine on my computer and runs correctly using NUnit locally. It also runs on the other people in my groups computers. The problem is that it never runs on our central testing server that's running Hudson. After some hours of debugging, I had a test on Hudson start the application and then print the first level of the AutomationTree. On my computer, this prints all of the windows I have on my desktop. On Hudson, this only prints the Desktop.
Thinking there might be multiple desktops, I tried using TreeWalker's GetNextSibling function on the RootElement. It still only reported one desktop.
Here's the code I'm using to start a process.
public bool connect(string[] args)
{
if (this.process != null) {
Console.WriteLine("ERROR: Process already connected");
return false;
}
if (!File.Exists(sApplicationPath)) {
Console.WriteLine(sApplicationPath + " does not exist");
return false;
}
// Turn the command arguments into a single string
string arguments = "";
foreach (string arg in args) {
arguments += arg + " ";
}
try {
// Start the application
ProcessStartInfo processStartInfo =
new ProcessStartInfo(sApplicationPath);
processStartInfo.Arguments = arguments;
this.process = Process.Start(processStartInfo);
// Must be a positive integer (non-zero)
if ( !( iInitialDelay > 0 ) ) {
Console.WriteLine("Invalid initial delay. " +
"Defaulting to 5 seconds.");
this.iInitialDelay = 5000;
}
Thread.Sleep(this.iInitialDelay);
} catch (Exception ex) {
Console.WriteLine("WGApplication.connect: " + ex.Message);
return false;
}
// Check if the process still exists
try {
/** This part does not return an error, so I think that means the process exists and is started */
Process check = Process.GetProcessById(process.Id);
} catch (ArgumentException ex) {
Console.WriteLine("The process expired before connection was complete");
Console.WriteLine("Make sure the process is not open anywhere else");
Console.WriteLine("and that it is able to execute on the host machine.");
return false;
}
// Check if the base automation element exists to verify open
AutomationElement rootWindow =
AutomationElement.RootElement.FindChildProcessById(process.Id);
/** This part returns null, so it can't find the window associated with this process id */
if (this.process == null) {
return false;
} else if (rootWindow == null) {
// A root window with this process id has not been found
Console.WriteLine("Cannot find the root window of the created " +
"process. Unknown error.");
return false;
} else {
// Everything is good to go
return true;
}
}
sApplicationPath is set to the absolute path of the executable. iInitialDelay is a delay to make sure the application has time to start. I'm running this on 'C:\Windows\System32\notepad.exe' on Windows Vista SP2 and compiling it with the v3.5 C# compiler.
FindChildProcessById is defined as follows:
public static AutomationElement FindChildProcessById(
this AutomationElement element, int processId)
{
var result = element.FindChildByCondition(
new PropertyCondition(AutomationElement.ProcessIdProperty,
processId));
return result;
}
Remember that this compiles and works on my computer. My test program on Hudson said that the RootElement had no children at all.
So I start the application, confirm it exists, and then I can't find any windows associated with the process. I can't find any windows associated with anything except the desktop.
Is this a problem with Hudson? Does Hudson work in some specific way that this code wouldn't work on it? Is it a problem with my code? The Hudson server is running on a Windows Server 2003 computer. Any help would be appreciated. I know this is a very specific problem which is a reason why I can't find any solutions online.
Is Hudson running as a service? If so, it may not have the necessary rights to show windows.