简体   繁体   中英

C# WCF service implemented in a DLL

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?

Split your MyServices into two classes - one a thin wrapper inherited from ServiceBase (to live in .EXE) and another doing real work including self-hosting to live in updatable .DLL. The first one can take an instance of the second as a .ctor argument and delegate start/stop calls to it.

You may also want to look at Topshelf .

I finally went with Rene's suggestion, the bulk of the service stays in an EXE and loaded as an assembly into the loader. Fortunately, loading an assembly can be done both from EXE and DLL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM