我有一个Windows服务,出于测试目的,我想迁移到Service Fabric。该服务仅在启动和停止时写入驱动器上的txt文件。在机器上手动启动和停止服务后,它可以正常工作。我可以在服务结构上获得相同的结果还是实现不同?
我已经使用该服务创建了一个来宾可执行文件,并将其部署到this guide之后的本地集群中。
答案 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项目,因此确实需要一些代码重构。