简体   繁体   English

在DLL中实现的C#WCF服务

[英]C# WCF service implemented in a DLL

I have a WCF service written in C# what works fine. 我有一个用C#编写的WCF服务,效果很好。 It's the usual self-hosted type in a Win32 console application. 这是Win32控制台应用程序中通常的自托管类型。 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: 但是现在,出于特殊更新的原因(这不是一台简单的台式计算机,您只是在其中使用通常的安装程序来更新程序,而是一个特殊的嵌入式系统),我想将实现服务的实际类型移动到由DLL加载的DLL中。使用反射的非常简单的加载器可执行文件:

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: 我可以通过三种方式部署服务,要么通过MSI正常安装,要么使用sc.exe ,甚至使用如下的自我管理代码进行部署:

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. 正如我在开始时提到的,在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 . 但是只要MyService类型在DLL中, InstallService仍然可以,但是StartService失败,出现System.ComponentModel.Win32Exception:%1不是有效的Win32应用程序 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. Windows似乎期望该服务可执行文件(它不会以我实际安装的EXE的形式存储自身,而是以实现该服务的DLL的形式存储)成为一个可以随意调用的可执行文件。

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? 我该如何规避此限制,也许以某种方式表明我想调用的是我的加载程序EXE,而不是依赖的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. MyServices分成两个类:一个是从ServiceBase继承的瘦包装(驻留在.EXE中),另一个是做包括自托管在内的实际工作,以驻留在可更新的.DLL中。 The first one can take an instance of the second as a .ctor argument and delegate start/stop calls to it. 第一个可以将第二个实例作为.ctor参数,并委托对其的启动/停止调用。

You may also want to look at Topshelf . 您可能还想看看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. 我最终接受了Rene的建议,大部分服务都保留在EXE中,并作为程序集加载到加载器中。 Fortunately, loading an assembly can be done both from EXE and DLL. 幸运的是,可以从EXE和DLL加载程序集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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