I have a WCF service written in C# what works fine. It's the usual self-hosted type in a Win32 console application. But now, for reasons of special updating (it's not a simple desktop computer where you simply update a program using the usual installers but a special embedded system) I'd like to move the actual type implementing the service to a DLL which is loaded by a very simple loader executable using reflection:
string DllFilename = Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, "myservice.dll");
var ServicesDll = Assembly.LoadFrom(DllFilename);
var ServicesType = ServicesDll.GetType("MyNamespace.MyServices");
var Instance = (ServiceBase)Activator.CreateInstance(ServicesType);
ServiceBase.Run(new ServiceBase[] { Instance });
I can deploy the service all three ways, either installing it normally via MSI, or using sc.exe
, or even with a self-managing code like this:
ServicesType.GetMethod("InstallService").Invoke(null, null);
ServicesType.GetMethod("StartService").Invoke(null, null);
where
public class MyServices : ServiceBase {
//...
public static void InstallService() {
if (!IsInstalled())
using (AssemblyInstaller installer = GetInstaller()) {
var state = new Hashtable();
try {
installer.Install(state);
installer.Commit(state);
}
catch {
installer.Rollback(state);
throw;
}
}
}
public static void StartService() {
if (IsInstalled())
using (var controller = new ServiceController("MyService")) {
if (controller.Status != ServiceControllerStatus.Running) {
controller.Start(); // fails here
controller.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(10));
}
}
}
//...
}
As I mentioned in the beginning, everything works just fine in an EXE. But as soon as the MyService
type is in the DLL, InstallService
is still OK but StartService
fails with System.ComponentModel.Win32Exception: %1 is not a valid Win32 application. It seems that Windows expects the service executable (which it stores itself not as the EXE I actually installed but as the DLL the service was implemented in) to be an executable to be called at its leisure.
How can I circumvent this limitation, maybe to signal somehow that it's my loader EXE that I want to be called, not the dependent DLL?