0

I have a Windows service for test purposes that i want to migrate to Service Fabric. The service does nothing more than writing to a txt-file on my drive when it starts and when it stops. It works fine when i manually start and stop the service after installing it on my machine. Can i achieve the same result on service fabric or does the implementation be different?

I have created a guest executable with the service and deployed it to a local cluster following this guide.

Mohit Verma
  • 5,140
  • 2
  • 12
  • 27
WhoAmI
  • 1,188
  • 6
  • 17
  • 47
  • _"I have created a guest executable with the service and deployed it to a local cluster"_ - so what happened when you ran it? – stuartd Apr 10 '19 at 12:21
  • I was expecting it to write to the txt file like it does as a local service on my machine, however that was not the case. – WhoAmI Apr 10 '19 at 12:26
  • What exactly is it that you are trying to achieve within Azure Service Fabric? Do you want a service that will log stuff to a file or does it need to do more? – Ebbelink Apr 10 '19 at 12:33
  • @Madailei No. I have a scenario where iv'e got several windows services (micro services) where the workload on these services may be quite high. But first i'm trying to learn how to actualy deploy and run a windows service in Service Fabric. – WhoAmI Apr 10 '19 at 12:43
  • @WhoAmI if your main goal is to learn about the process of developing and deploying to Azure Service Fabric I would suggest following this tutorial for the first 2 steps: https://learn.microsoft.com/en-us/azure/service-fabric/service-fabric-tutorial-create-dotnet-app – Ebbelink Apr 10 '19 at 12:48
  • @Madailei Thx for the link but my main goal right now is to verify that my windows service works in Service Fabric. – WhoAmI Apr 10 '19 at 13:04
  • _"I was expecting it to write to the txt file like it does as a local service on my machine, however that was not the case"_ - writing to a file isn't always the best test, especially when you're running on a server. What location are you writing to? Does the account the fabric app is running under have the rights to create a file in that location? Finally, what actually happens when the app tries to write the file? – stuartd Apr 10 '19 at 13:23
  • 3
    Did you see this? https://stackoverflow.com/a/39786939/5946937 – LoekD Apr 11 '19 at 11:23
  • @stuartd Yeah meaby writing to a file might not be the best test. I'm writing to my C drive. I'm just running a local cluster on my machine in VS 17. If i just run my service in VS (not as a guest executable) as a plain Windows Service it writes to the file as expected. I've tried adding a tcp listener to the service (without Azure SF SDK implementation) that listens to port 80. If i go to http://localhost:80 in a browser the service writes to the file. But when add the azure implementation as guest executable im unable to run it.With the correct endpoint my service should execute i assume. – WhoAmI Apr 12 '19 at 06:17
  • @stuartd I don't know about the rights when you run a local cluster in debug mode in VS. The problem might be because of rights or because im trying to trigger the service with the wrong endpoint. or meaby i have overlooked something else. – WhoAmI Apr 12 '19 at 06:25
  • I am facing this same problem right now. Every answer I see says "just run the exe". Windows Service exe's can't typically be executed from the console since the core logic is executed by the entry-point method `OnStart(string[] args)` in `ServiceBase`. What am I missing here? Like you, I'm just trying to run a basic test Windows Service (before I move on to trying to get our big project into Service Fabric). The answer provided by @LoekD is the same as all the others. It doesn't actually say how to run a Windows Service from what I can tell (despite the fact it was marked as the answer) – Adam Plocher Oct 03 '19 at 16:28
  • @AdamPlocher this is pretty old now but it turned out it was a better idea migrating the code into service fabric instead of running a guest executable. The main benefit is that you don't have to depend on an exe-file and further more it enables service comunication in the cluster,.It is also a good practice to use async operations inside the cluster and if your windows service does not use async operations it will become the clusters weak part. – WhoAmI Nov 21 '22 at 17:30

1 Answers1

0

First of all, I don't like this answer. After playing with it, I'm convinced the best way is to just port the code to a service fabric app. I would love to see a better "bolt-on" solution, but I haven't found any others. Every answer I've seen says "just run the exe as a Guest Executable", but a Windows Service exe doesn't "just run". It needs to be ran as a Windows Service which calls the OnStart entry point of the Service class (which inherits from ServiceBase).

The code below will allow your Windows Service to run in Service Fabric, but Service Fabric seems to report WARNINGS! So it's FAR from perfect.

It shouldn't require any changes to your OnStart or OnStop methods, however it does require some basic plumbing to work. This is also helpful if you wish to debug your windows services, as it allows you to pass in a /console command line argument and have it run in a console window.

First, either create your own ServiceBase class, or simply paste this code into your Service class (by default it's called Service1.cs in a C# Windows Service project):

// 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
}

Now change your Main method in Program.cs to look like this:

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
            });
    }
}

You may need to rename 'Service1' to whatever your service class is called.

When calling it through Service Fabric, make sure it's passing in the /console argument in ServiceManifest.xml:

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

If you wish to use this as a debuggable Windows Service, you can also set your 'Command line arguments' to /console under the Project settings > Debug tab.

EDIT:

A better option is to use TopShelf. This will work without warnings in Service Fabric, however it does require some code refactoring as it becomes a Console project instead of a Windows Service project.

Adam Plocher
  • 13,994
  • 6
  • 46
  • 79
  • 1
    We're trying to get away from Topshelf. Are you saying that if we move to service fabric, we're still going to need Topshelf? – Christian Findlay Feb 09 '20 at 21:04
  • Yes - if you wish to use a Guest Executable with a Windows Service. I see no evidence that a normal Windows Service project can work properly with SF as a Guest Exe. TopShelf uses a Console App project, instead of a Windows Service project (in Visual Studio), and that will work with a Guest Executable. Of course, ideally you would change/refactor your code to work as a native SF Stateless or Stateful service, which shouldn't be too difficult (depending on what it's doing). – Adam Plocher Feb 10 '20 at 17:34