首先,我不喜欢这个答案。在使用它之后,我确信最好的方法是将代码移植到服务结构应用程序。我很想看到一个更好的“螺栓固定”解决方案,但我还没有找到任何其他解决方案。我看到的每个答案都说“只需将 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 服务项目。