Windows Service - Crashes At Startup - c#

I have built a windows Service to monitor a few settings on our servers, I have developed quite a few WinForm and WPF apps but I am an absolute newbie when it comes to Windows Services, which is why I resorted to msdn and followed the tutorial on how to create a simple service. Now I can install the service just fine and make it run, but only if I cut some bits and pieces out of the microsoft tutorial.. but I am curious why, when I follow the tutorial, my service gets an unexpected error at startup.
After some testing it seems that the service seems to crash in the onstart method at SetServiceStatus()
public partial class MyService: ServiceBase
{
private static ManualResetEvent pause = new ManualResetEvent(false);
[DllImport("ADVAPI32.DLL", EntryPoint = "SetServiceStatus")]
public static extern bool SetServiceStatus(IntPtr hServiceStatus, SERVICE_STATUS lpServiceStatus);
private SERVICE_STATUS myServiceStatus;
private Thread workerThread = null;
public MyService()
{
InitializeComponent();
CanPauseAndContinue = true;
CanHandleSessionChangeEvent = true;
ServiceName = "MyService";
}
static void Main()
{
// Load the service into memory.
System.ServiceProcess.ServiceBase.Run(MyService());
}
protected override void OnStart(string[] args)
{
IntPtr handle = this.ServiceHandle;
myServiceStatus.currentState = (int)State.SERVICE_START_PENDING;
**SetServiceStatus(handle, myServiceStatus);**
// Start a separate thread that does the actual work.
if ((workerThread == null) || ((workerThread.ThreadState & (System.Threading.ThreadState.Unstarted | System.Threading.ThreadState.Stopped)) != 0))
{
workerThread = new Thread(new ThreadStart(ServiceWorkerMethod));
workerThread.Start();
}
myServiceStatus.currentState = (int)State.SERVICE_RUNNING;
SetServiceStatus(handle, myServiceStatus);
}
}
Now my service seems to run just fine when I comment out the SetServiceStatus() lines. Why does this fail? Is this a rights-issue or am I completely missing the point here?

In general, you shouldn't have to call SetServiceStatus when implementing a managed service using the framework.
That being said, if you do call it, you need to fully initialize the SERVICE_STATUS before using it. You're currently only setting the state, but none of the other variables.
This is suggested in the best practices for SetServiceStatus: "Initialize all fields in the SERVICE_STATUS structure, ensuring that there are valid check-point and wait hint values for pending states. Use reasonable wait hints."

Related

Is there a way to force an AssemblyLoadContext to unload?

I am working on a big ASP.Net 5 web application, and I would like to implement a self-update feature. Since the program can be deployed on many different platform and different ways (e.g. a Windows Service, a systemd service on linux, Docker container, etc...), the only viable way of implementing a self update mechanism is to write a host process that can load and unload the main program DLL and its dependencies. Unloading is important because the host program (updater) must be able to overwrite the server's DLL files while it's running.
Here's what I've done so far: I have changed the output type of the main web application to Library, and I've made a small loader program that loads this DLL and its dependencies into an HostAssemblyLoadContext, then invokes the original Main() method. The server application is programmed to shut down gracefully a few seconds after it starts up, so the CreateHostBuilder(args).Build().Run() and the Main() method can return. After this, I try to call HostAssemblyLoadContext.Unload(), but for some reason, the load context refuses to actually unload.
Here's my HostAssemblyLoadContext implementation:
public class HostAssemblyLoadContext : AssemblyLoadContext
{
private readonly AssemblyDependencyResolver _resolver;
public HostAssemblyLoadContext(string pluginPath) : base(isCollectible: true)
{
_resolver = new AssemblyDependencyResolver(pluginPath);
}
protected override Assembly? Load(AssemblyName name)
{
string? assemblyPath = _resolver.ResolveAssemblyToPath(name);
if (assemblyPath != null)
return LoadFromAssemblyPath(assemblyPath);
string filePath = $"{name.FullName.Split(',')[0]}.dll";
if(File.Exists(filePath))
return Assembly.LoadFrom(filePath);
return null;
}
}
My loader code:
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ExecuteMainMethod(string[] args, string assemblyFileName, out WeakReference contextReference, out HostAssemblyLoadContext loadContext)
{
loadContext = new HostAssemblyLoadContext(new DirectoryInfo(".").FullName);
contextReference = new WeakReference(loadContext);
var assembly = loadContext.LoadFromAssemblyPath(assemblyFileName);
var mainMethod = FindMainMethod(assembly)!;
try
{
mainMethod.Invoke(null, new object?[] {args});
}
catch
{
// ignore
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Unload(WeakReference weakReference, ref HostAssemblyLoadContext loadContext)
{
loadContext.Unload();
loadContext = null;
for (int i = 0; weakReference.IsAlive && i < 100; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine($"is alive: {weakReference.IsAlive}");
}
public static void Main(string[] args)
{
ExecuteMainMethod(args, new FileInfo("FirestormSW.SmartGrade.dll").FullName, out var weakReference, out var loadContext);
Unload(weakReference, ref loadContext);
Console.Out.WriteLine("Press ENTER to exit");
Console.ReadLine();
}
And the main method of the actual ASP server:
public static void Main(string[] args)
{
Console.Out.WriteLine("Starting Server...");
CreateHostBuilder(args).Build().Run();
Console.Out.WriteLine("Server stopped.");
}
Note that if I replace the contents of this Main method with a simple Thread.Sleep(1000), the context does unload successfully.
When I run this program, and wait for the server to shut itself down, this is what I see on the console:
Starting Server...
Shutting down...
is alive: True
This means that the server's main method has returned, but something is still keeping the load context alive. I have looked at the thread count (Process.GetCurrentProcess().Threads.Count) before and after the server is started/stopped, and the number jumps from 8 up to 27. This makes me assume that the context is being kept alive by some threads that are created by the ASP.Net application, but I'm not sure. And if that's the case, I don't know how to find out which threads are responsible, and even if I could, I'm not sure if it's possible to abort them.

Managed DLL referenced by 2 Winform apps. Winform 1 launches Winform 2, but context is shared unless both are executed separately

I have two WinForm client applications that reference the same managed DLL (written in C++/CLI) with the purpose of connecting to a native socket server.
Both Winform applications run fine when launched separately, but not when one launches the other.
Let's say that client Winform 1 is launched. It creates its own socket and context as intended and then proceeds to launch Winform 2 as a separate thread.
Winform 2 will also open its own socket as a client of the native server, but when Winform 2 closes its socket and exits, Winform 1 stops working because it seems to think it's Winform 2. So any server requests by WinForm 1 fail because its socket becomes the one previously closed by socket 2.
This behavior is new to me, but it must obviously extend beyond variable "SOCKET socket_id".
Is Winform 2 supposed to be launched as a separate process instead of the typical thread that executes Application.Run(Winform2)?
Thanks.
private void LaunchWinForm2Button_Click(object sender, EventArgs e)
{
System.Threading.Thread myThread =
new System.Threading.Thread(new System.Threading.ThreadStart(StartWinForm2));
myThread.Start();
}
private void StartWinForm2()
{
CSharpFormApp.WinForm2 theWinForm2 = new CSharpFormApp.WinForm2();
Application.Run(theWinForm2);
}
The problem was with a global pointer to native data in the C++/CLI DLL.
Since the WinForms get their data through several C++/CLI interfaces, it was initially easier to just have them access native data through a global pointer.
NativeLayer::NativeLayerData* native_data;
public ref class Test1Implementer : ITest1
{
virtual bool TestConnect()
{
bool success = native_data->Connect();
return success;
}
};
public ref class Test2Implementer : ITest2
{
virtual bool TestDisconnect()
{
bool success = native_data->Disconnect();
return success;
}
};
Eventually, such an implementation would come back to haunt me, but those are the perils of attempting to use globals in industrial applications.
Once I got rid of the managed global pointer to native data, everything works as intended. Here's a possible solution that allows for multithreading using nested interfaces:
public ref class TestsImplementer : ITests
{
private:
NativeLayer::NativeLayerData* native_data;
public:
TestsImplementer()
{
native_data = new NativeLayer::NativeLayerData();
}
ref class Test1Implementer : ITest1
{
virtual bool TestConnect(TestsImplementer^ tests)
{
bool success = tests->native_data->Connect();
return success;
}
};
ref class Test2Implementer : ITest2
{
virtual bool TestDisconnect(TestsImplementer^ tests)
{
bool success = tests->native_data->Disconnect();
return success;
}
};
};

windows service will not stop when I select stop from the services windows C#

I have written a windows service but when I try to stop the service it says that the service cannot be stopped at this time. Here's my whole class:
public partial class RenewalsService : ServiceBase
{
private readonly ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
private Thread _thread;
public RenewalsService()
{
InitializeComponent();
this.CanStop = true;
}
protected override void OnStart(string[] args)
{
_thread = new Thread(WorkerThread)
{
Name = "Renewals Service Thread",
IsBackground = true
};
_thread.Start();
}
protected override void OnStop()
{
try
{
if (!_shutdownEvent.SafeWaitHandle.IsClosed)
{
_shutdownEvent.Set();
}
if (_thread.IsAlive)
{
if (!_thread.Join(3000))
{
// give the thread 3 seconds to stop
_thread.Abort();
}
}
}
catch (Exception ex)
{
// _thread.Join may raise an error at this point. If it does we dont care. We dont care about any other exceptions
// since we are already in the process of closing the service.
}
finally
{
IError logger = new Logger();
Exception ex = new Exception("The Renewals service has been stopped.");
logger.Log(this, SeverityEnum.Warning, ex);
Environment.ExitCode = 0;
Environment.Exit(Environment.ExitCode);
}
}
private void WorkerThread()
{
try
{
while (!_shutdownEvent.WaitOne(1))
{
string timeToRun = ConfigurationManager.AppSettings["RunTime"];
string[] timeStrings = timeToRun.Split(':');
TimeSpan runtime = new TimeSpan(0, Int32.Parse(timeStrings[0]), Int32.Parse(timeStrings[1]), Int32.Parse(timeStrings[2]));
if (DateTime.Today.TimeOfDay.Hours == runtime.Hours &&
DateTime.Today.TimeOfDay.Minutes == runtime.Minutes)
{
Renewals renewals = new Renewals();
renewals.GenerateRenewal();
}
}
}
catch (Exception ex)
{
IError logger = new Logger();
logger.Log(this, SeverityEnum.Warning, ex);
this.OnStop();
}
}
}
What's missing to ensure the user can stop the service.
Your code looks ok to me, so here's a couple of things to check.
First, does the GenerateRenewal() method take a long time to complete? If so, you might need to periodically check _shutdownEvent inside that method for a timely shutdown. Of course, you've marked the thread as a background thread so it should shut down when you tell the service to stop anyway. I haven't seen background threads hold up process termination, but I guess there's always that chance.
Second, the more likely culprit to me is that the service has already shut down due to an exception. The Services console doesn't automatically refresh when a service shuts down, so it's possible you see the Stop link available to you when it shouldn't be. If you hit F5, the console will refresh, and if your service has stopped, the Start link should be the only one available. Check your log files to see if your exception handlers have been triggered.
UPDATE
So it looks like your WorkerThread() method is throwing an exception, which causes the service to stop. This explains why the Stop link is giving you the error message when you click it.
Providing you have sufficient permissions on your box, use this link to debug your service to find out why the exception is occurring.
HTH
The base ServiceBase class calls your overridden virtual method OnStop() when the Windows Service Control Manager ("the SCM") has sent the service a "Stop" command. In the method's implementation you are supposed to do whatever is necessary to get your service to a stopped state, then return from the method back to the ServiceBase class, which handles the interaction with the SCM, in this case to tell the SCM that your service is now stopped. The SCM will decide when your service process should be terminated, and the ServiceBase class handles that without you needing to do anything explicit.
For a well-behaved service, you should either just return at the end of your OnStop method, or throw an exception. The ServiceBase class will handle things appropriately, including logging your exception, if you have thrown one, as an error in the Windows Event Log. If your method may take a while to get your service stopped, you should call base.RequestAdditionalTime() at the appropriate points, so the base class can tell the SCM that you haven't just hung, your service is in the process of stopping.
I think your main problem lies in these lines:
Environment.ExitCode = 0;
Environment.Exit(Environment.ExitCode);
You never return to the base class at all... so the ServiceBase class never has a chance to respond gracefully to the SCM... you are just unilaterally terminating the process hosting your service. This is not what a well-behaved Windows service does.
The ServiceBase class is designed to be able to support multiple services hosted in a single service process. Individual services should not concern themselves with the lifetime of the host service process, only with the logical state of their own service.

Why doesn't my CriticalFinalizerObject get finalized when a new app domain spins up?

I have an .NET MVC site which spins up child processes for doing background work. I'd like to ensure that those processes are shut down when IIS spins up a new app domain (e. g. on deployment or any change to Web.config).
For this purpose, I've created a CriticalFinalizerObject as follows:
public class ProcessHandle : CriticalFinalizerObject, IDisposable
{
private readonly int _processId;
private int _disposed;
public ProcessHandle(int processId)
{
this._processId = processId;
}
// dispose is called if we shut down the process normally, so
// we don't need to kill it here
public void Dispose()
{
if (Interlocked.Exchange(ref this._disposed, 1) == 0)
{
GC.SuppressFinalize(this);
}
}
~ProcessHandle()
{
if (Interlocked.Exchange(ref this._disposed, 1) == 0)
{
try
{
using (var process = Process.GetProcessById(this._processId))
{
process.Kill();
}
}
catch
{
}
}
}
}
Whenever I create a process, I store a ProcessHandle alongside. The hope is that when a new app domain spins up, IIS will unload the old app domain (after some timeout). This will run the finalizers for my handles, which will kill any processes.
However, I'm observing that changing Web.config does not seem to reliably cause the finalizers to run. What am I doing wrong? Is there another way to achieve this?
Note: I'd love to have the child process watch for the parent process, but I don't control the child process code. I could create a wrapper process for this purpose, but I was hoping not to need that extra layer of complexity.

Error 1054 - Service did not respond in Timely Fashion - C# Application

Im having a problem installing my service application. When I'm running my debug mode it all works correctly and all the logical stuff works. I've written service applications before and comparing the two there is little difference between this one and a working one. Thanks in advance for any help on my code:
class MainClass : ServiceBase
{
ABCSQLCon _SQLCon = new ABCSQLCon();
private int cycleTime = 0;
private delegate void processError(String errorMessage);
static void Main(string[] args)
{
#if(!DEBUG)
ServiceBase.Run(new MainClass());
#else
MainClass service = new MainClass();
service.OnStart(new string[0]);
#endif
}
protected override void OnStart(string[] args)
{
addToLog("Testing SQL Connection...", "Log");
cycleTime = _SQLCon.sleepTime;
addToLog("Sleep Time has been set...", "Log");
if (_SQLCon.testSQLConnection())
{
addToLog("Connection to SQL Database succeeded", "Log");
// queryThread();
//not neccessary to make applicated multithreaded yet.
addToLog("Starting Query Thread...", "Log");
ThreadStart queryCycle = new ThreadStart(queryThread);
Thread qThread = new Thread(queryCycle);
qThread.Start();
}
}
private void startProgram()
{
}
protected override void OnStop()
{
base.OnStop();
}
public MainClass()
{
this.ServiceName = "ABCSQL Engine";
}
Ah I found the problem now, the sql connection test was just a quick open and close job but what I didn't see or realise was where I was initializing that _SQLCON object.
I've moved that to my method and works fine now. Happy days, thanks for the answers as it helped me look in the place I wasnt looking. x
It is a best practise to call to methods on a different thread then the service thread to avoid the blocking of the service thread
public void MyMethod()
{
addToLog("Testing SQL Connection...", "Log");
cycleTime = _SQLCon.sleepTime;
addToLog("Sleep Time has been set...", "Log");
if (_SQLCon.testSQLConnection())
{
addToLog("Connection to SQL Database succeeded", "Log");
// queryThread();
//not neccessary to make applicated multithreaded yet.
addToLog("Starting Query Thread...", "Log");
ThreadStart queryCycle = new ThreadStart(queryThread);
Thread qThread = new Thread(queryCycle);
qThread.Start();
}
}
private Thread _myThread;
protected override void OnStart(string[] args)
{
ThreadStart threadStart = MyMethod;
_myThread = new Thread(threadStart);
_myThread.Start();
}
The problem is that you are making the database connection in the initialisation of the service itself.
It work in debug because you're not actually starting it as a service:
#if(!DEBUG)
ServiceBase.Run(new MainClass());
#else
MainClass service = new MainClass();
service.OnStart(new string[0]);
#endif
I suspect that the start method is taking a long time because of this line:
if (_SQLCon.testSQLConnection())
You need to make sure that the start method of the service returns in a timely manner and any potentially long running process is done in a thread. If you move this test into a thread then you should find it working OK.

Categories