如何在Azure Service Fabric中运行Windows服务?

时间:2019-04-10 12:12:25

标签: windows-services azure-service-fabric

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

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

1 个答案:

答案 0 :(得分:0)

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

下面的代码将允许您的Windows服务在Service Fabric中运行,但是Service Fabric似乎报告了警告!因此,它是完美的FAR。

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

首先,创建您自己的ServiceBase类,或简单地将此代码粘贴到您的Service类中(默认情况下,在C#Windows Service项目中将其称为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
}

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

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中运行而不会发出警告,但是由于它变成了Console项目而不是Windows Service项目,因此确实需要一些代码重构。