【问题标题】:How do i run a Windows service in Azure Service Fabric?如何在 Azure Service Fabric 中运行 Windows 服务?
【发布时间】:2019-08-31 21:29:50
【问题描述】:

我有一个用于测试目的的 Windows 服务,我想迁移到 Service Fabric。该服务仅在启动和停止时写入驱动器上的 txt 文件。当我在机器上安装服务后手动启动和停止服务时,它工作正常。我可以在服务结构上实现相同的结果还是实现不同?

我已使用该服务创建了一个来宾可执行文件,并将其部署到this guide 之后的本地集群。

【问题讨论】:

  • “我已经使用该服务创建了一个来宾可执行文件并将其部署到本地集群” - 那么当您运行它时发生了什么?
  • 我希望它像我机器上的本地服务一样写入 txt 文件,但事实并非如此。
  • 您想要在 Azure Service Fabric 中实现的具体目标是什么?您想要一个将内容记录到文件中的服务还是需要做更多的事情?
  • @Madailei 没有。我有一个场景,我有几个 Windows 服务(微服务),这些服务的工作量可能非常高。但首先我想了解如何在 Service Fabric 中实际部署和运行 Windows 服务。

标签: windows-services azure-service-fabric


【解决方案1】:

首先,我不喜欢这个答案。在使用它之后,我确信最好的方法是将代码移植到服务结构应用程序。我很想看到一个更好的“螺栓固定”解决方案,但我还没有找到任何其他解决方案。我看到的每个答案都说“只需将 exe 作为来宾可执行文件运行”,但 Windows 服务 exe 不会“仅运行”。它需要作为调用Service 类(继承自ServiceBase)的OnStart 入口点的Windows 服务运行。

下面的代码将允许您的 Windows 服务在 Service Fabric 中运行,但 Service Fabric 似乎报告警告!所以它远非完美。

它不需要对您的 OnStart 或 OnStop 方法进行任何更改,但它确实需要一些基本的管道才能工作。如果您希望调试 Windows 服务,这也很有帮助,因为它允许您传入 /console 命令行参数并让它在控制台窗口中运行。

首先,创建您自己的ServiceBase 类,或者简单地将这段代码粘贴到您的服务类中(默认情况下,它在 C# Windows 服务项目中称为Service1.cs):

// Expose public method to call the protected OnStart method
public void StartConsole(string[] args)
{
    // Plumbing...
    // Allocate a console, otherwise we can't properly terminate the console to call OnStop
    AllocConsole();
    // Yuck, better way?
    StaticInstance = this;
    // Handle CTRL+C, CTRL+BREAK, etc (call OnStop)
    SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true);

    // Start service code
    this.OnStart(args);
}

// Expose public method to call protected OnStop method
public void StopConsole()
{
    this.OnStop();
}

public static Service1 StaticInstance;

private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{
    switch (ctrlType)
    {
        case CtrlTypes.CTRL_C_EVENT:
        case CtrlTypes.CTRL_BREAK_EVENT:
        case CtrlTypes.CTRL_CLOSE_EVENT:
        case CtrlTypes.CTRL_LOGOFF_EVENT:
        case CtrlTypes.CTRL_SHUTDOWN_EVENT:
            StaticInstance.StopConsole();
            return false;
    }

    return true;
}

[DllImport("kernel32.dll")]
private static extern bool AllocConsole();

[DllImport("Kernel32")]
public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add);

public delegate bool HandlerRoutine(CtrlTypes CtrlType);

public enum CtrlTypes
{
    CTRL_C_EVENT = 0,
    CTRL_BREAK_EVENT,
    CTRL_CLOSE_EVENT,
    CTRL_LOGOFF_EVENT = 5,
    CTRL_SHUTDOWN_EVENT
}

现在将Program.cs 中的Main 方法更改为如下所示:

static void Main(string[] args)
{
    var service = new Service1();
    if (args.Length > 0 && args.Any(x => x.Equals("/console", StringComparison.OrdinalIgnoreCase)))
    {
        service.StartConsole(args);
    }
    else
    {
        ServiceBase.Run(
            new ServiceBase[]
            {
                service
            });
    }
}

您可能需要将“Service1”重命名为所调用的服务类。

当通过 Service Fabric 调用它时,请确保它在 ServiceManifest.xml 中传入 /console 参数:

<CodePackage Name="Code" Version="1.0.0">
  <EntryPoint>
    <ExeHost>
      <Program>WindowsService1.exe</Program>
      <Arguments>/console</Arguments>
      <WorkingFolder>Work</WorkingFolder>
    </ExeHost>
  </EntryPoint>
</CodePackage>

如果您希望将此用作可调试的 Windows 服务,您还可以在“项目设置”>“调试”选项卡下将“命令行参数”设置为 /console

编辑:

更好的选择是使用TopShelf。这将在 Service Fabric 中运行而不会出现警告,但是它确实需要一些代码重构,因为它变成了控制台项目而不是 Windows 服务项目。

【讨论】:

  • 我们正试图摆脱 Topshelf。你是说如果我们转向服务结构,我们仍然需要 Topshelf?
  • 是的 - 如果您希望将客户机可执行文件与 Windows 服务一起使用。我没有看到任何证据表明正常的 Windows 服务项目可以与 SF 作为来宾 Exe 一起正常工作。 TopShelf 使用控制台应用程序项目,而不是 Windows 服务项目(在 Visual Studio 中),它将与来宾可执行文件一起使用。当然,理想情况下,您可以更改/重构您的代码以作为原生 SF 无状态或有状态服务,这应该不会太难(取决于它在做什么)。
猜你喜欢
  • 2020-02-01
  • 2016-08-15
  • 2020-01-05
  • 2017-06-09
  • 2020-01-23
  • 2017-10-30
  • 2016-09-28
  • 2018-09-15
  • 2017-06-05
相关资源
最近更新 更多