GithubHelp home page GithubHelp logo

peterkottas / dotnetcore.windowsservice Goto Github PK

View Code? Open in Web Editor NEW
569.0 44.0 150.0 111 KB

Simple library that allows one to host dot net core application as windows services. Perfect solution to power micro-services architecture.

License: MIT License

C# 100.00%

dotnetcore.windowsservice's Introduction

DotNetCore.WindowsService

Simple library that allows one to host dot net core application as windows services. Perfect solution to power micro-services architecture.

Important note

This library was created to enable one to host CONSOLE dot net core applications. If you want to host a WEBSITE as a service, you're better of following https://docs.microsoft.com/en-us/aspnet/core/hosting/windows-service

Installation

Using NuGet:

Install-Package PeterKottas.DotNetCore.WindowsService

Quick start

Easiest way to start is using a brand new template. Just do:

dotnet new -i PeterKottas.DotNetCore.WindowsService.Templates::*

This will add one template at the moment.

Follow up with this

mkdir NameOfYourProject
cd NameOfYourProject
dotnet new [ mcrsvc-min | mcrsvc-std ]

This will create a sample project for you. Next chapter explains its features in more details especially points 6 onwards if you used the template.

Community, feel encouraged to add more templates if you find something missing/usefull. I'll be more than happy to add these. Just copy the project in https://github.com/PeterKottas/DotNetCore.WindowsService/tree/master/Source/Templates/PeterKottas.DotNetCore.WindowsService.MinimalTemplate and follow instructions in https://github.com/dotnet/templating if you need more specific behvaiour.

Usage

  1. Create .NETCore console app.

  2. Create your first service, something like this:

    public class ExampleService : IMicroService
    {
    	public void Start()
    	{
    		Console.WriteLine("I started");
    	}
    	
    	public void Stop()
    	{
    		Console.WriteLine("I stopped");
    	}
    }
  3. You can also inherit MicroService base class and take advantage of built in timers:

    public class ExampleService : MicroService, IMicroService
    {
    	public void Start()
    	{
    		this.StartBase();
    		Timers.Start("Poller", 1000, () =>
    		{
    			Console.WriteLine("Polling at {0}\n", DateTime.Now.ToString("o"));
    		},
    		(e) =>
    		{
    			Console.WriteLine("Exception while polling: {0}\n", e.ToString());
    		});
    		Console.WriteLine("I started");
    	}
    	
    	public void Stop()
    	{
    		this.StopBase();
    		Console.WriteLine("I stopped");
    	}
    }
  4. Api for services (and yeah, it's similar to Topshelf, thanks for inspiration, I just couldn't wait for you guys to implement this):

    ServiceRunner<ExampleService>.Run(config =>
    {
    	var name = config.GetDefaultName();
    	config.Service(serviceConfig =>
    		{
    			serviceConfig.ServiceFactory((extraArguments, microServiceController) =>
    		{
    			return new ExampleService();
    		});
    		serviceConfig.OnStart((service, extraArguments) =>
    		{
    			Console.WriteLine("Service {0} started", name);
    			service.Start();
    		});
    
    		serviceConfig.OnStop(service =>
    		{
    			Console.WriteLine("Service {0} stopped", name);
    			service.Stop();
    		});
    		
    		serviceConfig.OnInstall(service =>
    		{
    			Console.WriteLine("Service {0} installed", name);
    		});
    		
    		serviceConfig.OnUnInstall(service =>
    		{
    			Console.WriteLine("Service {0} uninstalled", name);
    		});
    		
    		serviceConfig.OnPause(service =>
    		{
    			Console.WriteLine("Service {0} paused", name);
    		});
    		
    		serviceConfig.OnContinue(service =>
    		{
    			Console.WriteLine("Service {0} continued", name);
    		});
    		
    		serviceConfig.OnShutdown(service =>
    		{
    			Console.WriteLine("Service {0} shutdown", name);
    		});
    
    		serviceConfig.OnError(e =>
    		{
    			Console.WriteLine("Service {0} errored with exception : {1}", name, e.Message);
    		});
    	});
    });
  5. Optionally set the name of the service like this:

    ServiceRunner<ExampleService>.Run(config =>
    {
    	config.SetName("MyTestService");
    });
  6. Run the service without arguments and it runs like console app.

  7. Run the service with action:install and it will install the service.

  8. Run the service with action:uninstall and it will uninstall the service.

  9. Run the service with action:start and it will start the service.

  10. Run the service with action:stop and it will stop the service.

  11. Run the service with action:pause and it will pause the service.

  12. Run the service with action:continue and it will continue the service.

  13. Run the service with username:YOUR_USERNAME, password:YOUR_PASSWORD and action:install which installs it for the given account.

  14. Run the service with built-in-account:(NetworkService|LocalService|LocalSystem) and action:install which installs it for the given built in account. Defaults to LocalSystem.

  15. Run the service with description:YOUR_DESCRIPTION and it setup description for the service.

  16. Run the service with display-name:YOUR_DISPLAY_NAME and it setup Display name for the service.

  17. Run the service with name:YOUR_NAME and it setup name for the service.

  18. Run the service with start-immediately:(true|false) to start service immediately after install. Defaults to true.

  19. You can find the complete example in PeterKottas.DotNetCore.Example project.

  20. Install the service using powershell: dotnet.exe $serviceDllPath action:install

Created and sponsored by

  • GuestBell - Customer centric online POS for Hotels and short terms stays.

Contributing

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :D

License

MIT

Credit

Huge thanks goes to @dasMulli the guy behind a useful lib which is one of the dependecies for this library.

dotnetcore.windowsservice's People

Contributors

andymac4182 avatar bigtimenet avatar bishopsmove avatar dmitry-pavlov avatar holyone avatar japerr avatar jaybz avatar justintoth avatar kelvinschutz avatar kindread21 avatar peterkottas avatar ragnarol avatar robvanuden avatar rs-kymmcgain avatar saibamen avatar tanhe avatar xakepbean avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dotnetcore.windowsservice's Issues

Nancy with .NET Core and this repo

I'm wanting to run my .NET Core web API as a windows service which targets netcoreapp 1.1. The api uses the Nancy framework which has some custom startup hooks and dependency injections. Will it be possible to integrate your helper classes with Nancy?

For reference Program.cs, Startup.cs, and a Module.cs which is the REST API. These files look like this:

Program.cs

public class Program
    {
        public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseContentRoot(Directory.GetCurrentDirectory())
                .UseIISIntegration()
                .UseStartup<Startup>()
                .UseApplicationInsights()
                .UseUrls("http://localhost:5100")
                .Build();
            host.Run();
        }
    }
}

Startup.cs
public class Startup
    {
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app)
        {
            var logger = ConfigureLogger();
            app.UseOwin()
                .UseMonitoringAndLogging(logger, HealthCheck)
                .UseNancy(opt => opt.Bootstrapper = new Bootstrapper(logger));
        }

        private ILogger ConfigureLogger()
        {
            MicroservicePlatform.Configure(
              tokenUrl: "http://localhost:5001/",
              clientName: "registrar_microservice",
              clientSecret: "secret");
            return new LoggerConfiguration()
              .Enrich.FromLogContext()
              .WriteTo.ColoredConsole(
                LogEventLevel.Verbose,
                "{NewLine}{Timestamp:HH:mm:ss} [{Level}] ({CorrelationToken}) {Message}{NewLine}{Exception}")
              .CreateLogger();
        }
        private static Task<bool> HealthCheck()
        {
            return Task.FromResult(true);
        }
    }

    public class Bootstrapper : DefaultNancyBootstrapper
    {
        private ILogger logger;
        public Bootstrapper(ILogger logger)
        {
            this.logger = logger;
        }
        protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines)
        {
            base.ApplicationStartup(container, pipelines);
            container.Register(logger);
            container.UseHttpClientFactory(new NancyContext());
        }

        protected override void RequestStartup(
          TinyIoCContainer container,
          IPipelines pipelines,
          NancyContext context)
        {
            base.RequestStartup(container, pipelines, context);
            container.UseHttpClientFactory(context);
        }
    }
}

Module.cs
public class RegistrarModule : NancyModule
   {
      private readonly RegistrationDbContext registrationDb = new RegistrationDbContext();
      private readonly RegistrationModelDefaultContext registrationDbDefaults = new RegistrationModelDefaultContext();
      public RegistrarModule()
      {
         Get("/", _ => "Registrar is good");
         Post("/HealthService", _ =>
         {
            var microserviceInfo = RequestStream.FromStream(Request.Body).AsString();
            var content = JsonConvert.DeserializeObject<RegistrationModel>(microserviceInfo);
            if (content._guid == Guid.Empty)
            {
               content._guid = Guid.NewGuid();
               content.guid = content._guid.ToString();
            }

            var result = registrationDb.RegisteredMicroservices.Where(b => b.guid == content.guid).FirstOrDefault();
            if (result == null)
            {
               content.secret = "secret";
               content.timeToLive = 5000;
               registrationDb.Add(content);
            }
            else
            {
               content.timeToLive = 5000;
            }
            registrationDb.SaveChanges();
            return Response.AsJson(content);
         });
      }
   }
}

Installing/Publishing

Hello, I'm trying to publish/install my service but I'm facing some problems.

When I run it directly from VS2017 it works fine.

When I try to "publish" I recieve only errors.

When I rebuild in "Release" and try to install from a powershell (admin) using the command
(The rebuild doesn't create a .exe"

New-Service -Name MyService.TesteService -BinaryPathName "C:\Users\Luk\Desktop\MyCustomService action:run" -StartupType Automatic

The service install but stoped, When I try to run I receive an error of "Access declined"

appsettings.json

  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Warning"
    }
  },

  "frameworks": {
    "netcoreapp1.1": {
      "dependencies": { "Microsoft.NETCore.App": { "version": "1.1.0" } },
      "imports": "dnxcore50"
    },
    "dnx451": {
    },
    "imports": [ "dotnet5.6", "dnxcore50", "portable-net45+win8" ]
  },

  "runtimes": {
    "win81-x64": {},
    "win7-x64": {},
    "win10-x64": {},
    "win10-x86": {}
  }

Is there anything I should do before it ?

----- EDITED

Ok, managed to get an .exe of my service.

If I run the exe, the service executes correct.

When I try to run "MyService.exe action:install" it install a service but cant startup, it gives me the following error

Error 1053: The service did not respond to the start or control request in a timely manner.

IOEccption with example code


Timers.Start("Poller", 1000, () =>
            {
                File.AppendAllText(fileName, string.Format("Polling at {0}\n", DateTime.Now.ToString("o")));
            });
Console.WriteLine("I started");
File.AppendAllText(fileName, "Started\n");

Timers.Start and FileAppendAllText in different process,while one of then create /begin write,the another process may throw an exception of 'The process cannot access the file 'xxx\yyy\log.txt' because it is being used by another process'.
i think user-code with different namespace makes it happend.

Install using powershell

It would be nice to be able to run:
New-Service -BinaryPathName $serviceExeFullPath -Name $serviceName -DisplayName $serviceName -StartupType Automatic
from powershell. This is supported by Topshelf.
The action options work well but this different interface causes issues when deploying different services, we need to know which windows service library was used.

If I use New-Service to install the service using this library the service will fail to start up.

Can't run action:install

I've used the sample the sample template that's provided but when I've tried running the command dotnet ConsoleApp1.dll action:install it returns

"Service ConsoleApp1.ExampleService errored with exception : Access is denied"
image

Having trouble running with action:run

When I attempt to start my service without any parameters, it runs fine, but when I use action:run I get the following errors:

PS C:\Projects\pts.betasystems\src\PTS.BetaSystems.Web\bin\Release\PublishOutput> dotnet .\PTS.BetaSystems.Web.dll action:run

Service PTS.BetaSystems.Web.Program+ExampleService errored with exception : The service process could not connect to the service controller

I get this error even if I comment out any of my own code in my start method.

Here's my project.json file:

{
"userSecretsId": "aspnet-WebApplication1-f8dd4d00-7f76-4595-97e6-5aa03aa0aa63",

"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.1.0",
"type": "platform"
},
"Microsoft.AspNetCore.Mvc": "1.1.0",
"Microsoft.AspNetCore.Routing": "1.1.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
"Microsoft.Extensions.Configuration.FileExtensions": "1.1.0",
"Microsoft.Extensions.Configuration.Json": "1.1.0",
"Microsoft.Extensions.Logging.Console": "1.1.0",
"Microsoft.Extensions.Logging.Debug": "1.1.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
"Microsoft.AspNetCore.StaticFiles": "1.1.0",
"Microsoft.AspNetCore.SpaServices": "1.0.0-beta-000019",
"Microsoft.AspNetCore.Antiforgery": "1.1.0",
"Microsoft.AspNetCore.Diagnostics": "1.1.0",
"Microsoft.AspNetCore.Authentication.Cookies": "1.1.0",
"Microsoft.AspNetCore.Authentication": "1.1.0",
"NLog.Extensions.Logging": "1.0.0-rtm-beta2",
"Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.Extensions.Configuration.UserSecrets": "1.1.0",
"Microsoft.Extensions.Logging": "1.1.0-*",
"Microsoft.VisualStudio.Web.BrowserLink.Loader": "14.0.0",
"Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.VisualStudio.Web.CodeGenerators.Mvc": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Swashbuckle.AspNetCore": "1.0.0-rc1",
"Hangfire": "1.6.12",
"NLog.Web.AspNetCore": "4.3.1",
"Hangfire.MemoryStorage": "1.5.0"
},

"tools": {
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.1.0-preview4-final"
},

"frameworks": {
  "netcoreapp1.0": {
    "imports": [
      "dotnet5.6",
      "portable-net45+win8"
    ]
  }
},

"buildOptions": {
  "emitEntryPoint": true,
  "preserveCompilationContext": true
},

"runtimeOptions": {
  "configProperties": {
    "System.GC.Server": true
  }
},

"publishOptions": {
  "include": [
    "wwwroot",
    "web.config",
    "Views",
    "nlog.config",
    "devices.json"

  ]
},

"scripts": {
  "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}

}

Hello, find a question in action:install

dotnet LoggerService.dll action:install
Service LoggerService.ExampleService errored with exception : The service did not respond in time to initiate or control the request.

dotnet LoggerService.dll action:start
Service LoggerService.ExampleService errored with exception : Cannot start service LoggerService.ExampleService on computer '.'.

namespace LoggerService
{
class Program
{
static void Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
ServiceRunner.Run(config =>
{
var name = config.GetDefaultName();
config.Service(serviceConfig =>
{
serviceConfig.ServiceFactory((list, extraArguments) =>
{
return new ExampleService();
});
serviceConfig.OnStart((service, extraArguments) =>
{
Console.WriteLine("Service {0} started", name);
service.Start();
});

                serviceConfig.OnStop(service =>
                {
                    Console.WriteLine("Service {0} stopped", name);
                    service.Stop();
                });

                serviceConfig.OnError(e =>
                {
                    Console.WriteLine("Service {0} errored with exception : {1}", name, e.Message);
                });
            });
            config.SetDescription($"{name},Description");
            config.SetDisplayName($"{name},DisplayName");
            config.SetName(name);
        });
        Console.ReadLine();
    }
}
public class ExampleService : IMicroService
{
    readonly EventConsumer _eventConsumer = KafkaConsumer.Consumer(Guid.NewGuid().ToString(), new string[] { "LoggerTopic" });
    public void Start()
    {
        KafkaConsumer.Start(_eventConsumer);
        Console.WriteLine("I started");
    }

    public void Stop()
    {
        KafkaConsumer.Stop(_eventConsumer);
        Console.WriteLine("I stopped");
    }
}

}

Can't extra run arguments

Is there any way to send a custom parameter on action:install so that the action:run passes it every time the service is started?

What it supports:
dotnet.exe C:\Path\Service.dll action:install -> dotnet.exe C:\Path\Service.dll action:run

What I need:
dotnet.exe C:\Path\Service.dll param action:install -> dotnet.exe C:\Path\Service.dll param action:run

What it currently does when I try to pass the param:
dotnet.exe C:\Path\Service.dll param action:install -> dotnet.exe C:\Path\Service.dll action:run

The installed service did not respond to the start or control request in a timely fashion.

Hi Peter.

Thank you in advance for your help.

I have installed your tool. The example service is working properly as console application. I can also successfully create window service using following command in administrator mode:

D:\Applications\DotNetCoreWindowService\DotNetCore.WindowsService\Source\PeterKottas.DotNetCore.Example\bin\Debug\netcoreapp1.1\win10-x64>sc create PeterKottas binPath= "C:\Program Files\dotnet\dotnet.exe D:\Applications\DotNetCoreWindowService\DotNetCore.WindowsService\Source\PeterKottas.DotNetCore.Example\bin\Debug\netcoreapp1.1\win10-x64\PeterKottas.DotNetCore.Example.dll --run-as-service"

[SC] CreateService SUCCESS

When I am trying run the service by command
sc start PeterKottas (Administrator Mode)

I have the following error:

[SC] StartService FAILED 1053:
The service did not respond to the start or control request in a timely fashion.

My working environment

  • Microsoft Windows 10 Pro
  • Visual Studio Professional 2015
    Version 14.0.25422.01 Update 3
  • Microsoft .Net Framework Version 4..6.01586
    Any help will be appreciated.

Best Regards,
Vladimir

Uninstall error missing dll api-ms-win-service-core-l1-1-1.dll

Hello Peter, thank you very much for creating this. In executing dotnet run action:install everything worked fine. However when I do action:uninstall I am getting:
Service eAchieveBatchReports.EAchieveReportService errored with exception: Unable to load DLL 'api-ms-win-service-core-l1-1-1.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
Stack Trace: at Interop.mincore.EnumServicesStatusEx(IntPtr databaseHandle, I
nt32 infolevel, Int32 serviceType, Int32 serviceState, IntPtr status, Int32 size
, Int32& bytesNeeded, Int32& servicesReturned, Int32& resumeHandle, String group
)
at System.ServiceProcess.ServiceController.GenerateNames()
at System.ServiceProcess.ServiceController.GetServiceHandle(Int32 desiredAcce
ss)
at System.ServiceProcess.ServiceController.GenerateStatus()
at PeterKottas.DotNetCore.WindowsService.ServiceRunner1.Uninstall(HostConfig uration1 config, ServiceController sc)
at PeterKottas.DotNetCore.WindowsService.ServiceRunner1.UsingServiceControll er(HostConfiguration1 config, Action2 action) at PeterKottas.DotNetCore.WindowsService.ServiceRunner1.Run(Action`1 runActi
on)

Do you know where I can find this missing DLL?

Also, how would I later deploy this to a production server? Not an issue, question, sorry.

Revise or Eliminate Step 18?

Thanx for putting this lib together, Peter. I'm using it to try and get a netcoreapp2.0 project running as a Windows service.

I ran into the same "the service is not starting up in a timely fashion" reported in another issue, after trying to install the netcore dll produced in the example project as a service.

Might I suggest deleting or revising step 18 in the Usage section on the home page? That's what I prompted me to go the way I did. But apparently, based on your response in that other issue, that's not the way to install services based on the library.

Uninstall error

Hi, when i do dotnet xxxxx.dll action:uninstall, errored with exception: ’Service xxxxx with exception : Cannot stop xxxxx service on computer '.'.

Do you know how to solve it?

Help!

Hi,

When you have the below, does OnStart / service.Start need to block so the console app doesnt just stop after its gone through ServiceRunner.Run

 public static void Main(string[] args)
        {
            ServiceRunner<MyService>.Run(config =>
            {
                var name = "My Service";
                config.SetName(name.Replace(" ", ""), true);
                config.SetDisplayName(name, true);
                config.SetDescription(name, true);

                config.Service(serviceConfig =>
                {
                    serviceConfig.ServiceFactory((extraArguments) =>
                    {
                        return new MyService();
                    });

                    serviceConfig.OnStart((service, extraArguments) =>
                    {
                        Console.WriteLine("Service {0} started", name);
                        service.Start();
                    });

                    serviceConfig.OnStop(service =>
                    {
                        Console.WriteLine("Service {0} stopped", name);
                        service.Stop();
                    });

                    serviceConfig.OnError(e =>
                    {
                        var location = Path.Combine(Directory.GetCurrentDirectory(), string.Format("{0:yyyy-MM-dd_hh-mm-ss-tt}_vqportal.err", DateTime.Now));
                        var errorString = $"An {e.GetType()} exception has occured: {Environment.NewLine}\t{e.Message}{Environment.NewLine}\t{e.StackTrace}";
                        Console.WriteLine(errorString);
                        File.WriteAllText(location, errorString);
                    });
                });
            }); 
        }

Not able to start a .net core service

Hi Peter,

Nice work.

Is it possible to start a .net core project from Start() , like this,

var host = new WebHostBuilder()
.UseKestrel(options => { options.AddServerHeader = false; })
.UseContentRoot(Directory.GetCurrentDirectory())
.UseUrls("http://*:5000")
.UseIISIntegration()
.UseStartup()
.Build();

        host.Run();

I tried this, a service is created . But unfortunately if i try accessing http://localhost:5000 it didnt work.

I am struck on it and any help is really appreciated.

Non-service (i.e., interactive or console) service host quits immediately

Hi! I apologise in advance if I'm mis-understanding the purpose or function of the library, but I am struggling to understand how the interactive/console version of the service runner is intended to function.

Recreating your example service (https://gist.github.com/peitschie/56b95a33cf5822cb598271ddbe54f183), it all runs as desired when installed and run as a Windows service. However, it quits immediately if I run it directly via F5 from within Visual Studio, or even as a console app (e.g., dotnet NetCoreWindowsService.dll), only displaying:

Service NetCoreWindowsService.Service started
Main exited

I had assumed that the intention was it should not exit if run via a console, and somehow wait for the service termination to complete. Alternatively, should the IMicroService.Start method block when started interactively? If the latter, what's the correct way to read whether the service is RunInteractive, as this property doesn't appear to be exposed via any of the configurations?

Many thanks for this library regardless... even with this small hiccup, this has certainly made it easier for me to get started!

[WIX] Cannot run service after installing (error 1053)

Hi!
I hope you can help me. I used your library to create a service using dotnet core. I built WIX installation which installs windows service (using typically ServiceInstall and ServiceControl without arguments), then installed the service with administration privilages. Unfortunately I cannot run the service from services.msc. I am always getting error 1053 ("The service did not respond in a timely fashion").
Any idea how to install such a service using WIX and can start and stop service normally via Services.msc?
I would be grateful for helping.

Stucking Inside One Of My Method


{
    public class Operations_Collection
    {
        static Alerts alert = new Alerts();
        private ILogger logger;

        private Timer _timer;

        private readonly AlertsDataBaseContext _context = new AlertsDataBaseContext();

        UpdateDatabase updateDataBase = new UpdateDatabase();

        SendMail _sendEmailcs = new SendMail(alert);

        private static readonly object Locker = new object();

        private string fileName = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "Oparation.txt");

        public void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {

            File.AppendAllText(fileName, string.Format("------------ {0}\n", DateTime.Now.ToString("o")));

            lock (Locker)
            {

                File.AppendAllText(fileName, string.Format("Inside locker--------", DateTime.Now.ToString("o")));
                Console.WriteLine("Çalışıyor.....");


                if (true)
                {
                    File.AppendAllText(fileName, string.Format("inside if--------", DateTime.Now.ToString("o")));
 -------->     List<Alerts> alertList = GetList();
                    File.AppendAllText(fileName, string.Format("inside if--------", DateTime.Now.ToString("o")+"alertlistcount====="+alertList.Count+"--------"));
                    foreach (var alert in alertList)
                    {
                        File.AppendAllText(fileName, string.Format("inside foreach--------", DateTime.Now.ToString("o")));
                        _sendEmailcs.Send(alert);

                        try
                        {
                            File.AppendAllText(fileName, string.Format("inside try--------", DateTime.Now.ToString("o")));
                            updateDataBase.Update(alert.AlertId, _sendEmailcs.Statement);
                        }

                        catch (Exception exception)
                        {
                            continue;
                        }

                    }
                }
            }
        }
        private List<Alerts> GetList()
        {

              File.AppendAllText(fileName, string.Format("inside getlist--------", DateTime.Now.ToString() ));
 -------> var mylist = _context.Alerts.Where(x => x.IsMailSent == false).ToList();
            File.AppendAllText(fileName, string.Format("GetList ortası--------", DateTime.Now.ToString("o")+mylist.Count));
            var top3Query = mylist.OrderBy(x => x.AlertId).Take(3);
            
            File.AppendAllText(fileName, string.Format("end of getlist--------", DateTime.Now.ToString("o")+top3Query.Count()));
            return top3Query.ToList();

        }
    }

Dear Peter,
Thanks for great project,
I am asking this you folks because ı have no place to go.I wrote a project and started as console app on .net core and it worked fine. But when ı successfully install that console app as service , It stucked inside a method, I showed the methods with arrow above. The last thing serviec doing is writing in a text file that "inside getlist" Do you have any suggestion?

.net CLI template

Would you be interested in maintaining a CLI template called "winservice" or something along those lines? This would probably require maintenance of a project and Nuget package, but I think it would get used a lot!

Reference: https://github.com/dotnet/templating

Deny access

excuse me, I'm using for my .net core project,I'm can't understand how to use extraArguments

1

It's right??? but the result is deny access the following
1

I don't know how to solve ,I hope to get your reply thanks in advance

How to register a global exception handler. Such as An equivalent to AppDomain.UnhandledException

I am getting errors like

Error 1053: The service did not respond to the start or control request in a timely fashion.

Upon examining the 'Event Log', I could see

Faulting module path: C:\windows\system32\KERNELBASE.dll 

Exception code: 0xe0434352

This illustrates that I have not registered a global exception handler such as listening to the AppDomain.UnhandledException Or ThreadPool.UnhandledException

How do i register for these events ?

wrapping up the ServiceRunner<ServiceApp>.Run inside a try - catch does not capture the details of this 0xe0434352 exception. Looks like the catch block itself is not executed. This is the only try-catch block i have. The code is not swallowing any exceptions..

try
{
	ServiceRunner<ServiceApp>.Run(config =>
	...
}
catch (Exception ex)
{
	var path = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "logs\\service-error.txt");
	File.WriteAllText(path, e.StackTrace);
}

Using it on Windows Server 2008R2

Thank you for your hint on StackOverflow.

I used your library and it works like charm. Thank you for your great work.

Unfortunatly I tried to run it on Windows Server 2008 R2 too and there it seems the service does not start/run.

The service gets installed and started but it seem it is exiting the Main method immediatly without starting/running the service.

Do you have information if it should run on R2 too?

Stopping the service from code

Hi Peter,

Really like your library!

I would like to control the service and stop it when, for example an Exception in the Service.Start() method is raised. The serviceConfig.OnError callback is triggered upon the error, but I cannot figure out how to make the service stop.

In a regular .NET application I would have used ServiceBase.Stop() method to achive this.

Is it possible to stop the service from within the code?

Thanks
Martin Lund

update readme example to csproj

Would you be open to updating the readme example to csproj? I see your example project does this already, and if you only have time to reply here, I could probably make a pull request.

Dependency Injection on Ctor of Service

Hello !

I'm trying to use your lib to create a XML import service, but I have to do dependency injection on my service.

The problem is, I can't call

serviceConfig.ServiceFactory((extraArguments) => { return new CustomerXmlService(); });
because CustomerXmlService have a lots of ctor reqs

Any ideas of a workaround ?

displayName arg doesn't work

Display name is never set when passed in via the command line. For example:
myservice.exe action:install displayName:DoStuff

I believe the issue has to do with the following line:
https://github.com/PeterKottas/DotNetCore.CmdArgParser/blob/f5d012866e08bd7cf4e677bc55c5cf030d95665f/Source/PeterKottas.DotNetCore.CmdArgParser/Parser.cs#L39
This results in "displayname".StartsWith("displayName") which evaluates to false.

I noticed this is the only camel cased argument, while others are kebab cased. Perhaps this is the reason for this issue? Would it be possible to use "display-name" or "displayname" instead? I'm happy to throw together a pr, but I wanted to make sure that the change was in the desired direction first.

Using power shell to install service creates issues.

Hello,

I am facing a mix of issues while trying to install the service using power shell. Once the script completes, the service is appearing in the services.msc GUI. but gets into 'stopped' state. this is the output i got as result of the posh script. I made sure to invoke the shell using "Run as Administrator"

PS C:\Apps\ServiceApp> .\install.ps1
service does not exists
installing service

Status   Name               DisplayName
------   ----               -----------
Stopped  ServiceApp... ServiceApp
installation completed

I am using a service account to run this service. The credentials for the service account are provided in the install.ps1. (Attaching its contents at the end).

When i tried to 'start' the service manually, I am getting

Error 1053: The service did not respond to the start or control request in a timely fashion.

Upon examining the 'Event Log', I could see

Faulting module path: C:\windows\system32\KERNELBASE.dll 

Exception code: 0xe0434352

Upon further research, it turns out that I have to register for AppDomain.UnhandledException event, which i have "no idea" how to do it. Im still on .net core 1.1.

I tried Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "logs\\service-stop.txt") to write files on 'serviceConfig.ServiceFactory', 'serviceConfig.OnStart, OnStop, and OnError' but those files never were written. I hope this indicates something is wrong.

The "only time" it works is when i used a batch file with the command "dotnet ServiceApp.dll action:install" But I have no way to specify the service account to use. And i have to manually go to the servies.msc to change the Logon property of the service. Which is an overkill and more manual intervention every time i need to deploy a new version of the service.

Having said that, I am looking for a solution to solve the issues mentioned. And here is the contents of the install.ps1 and the code for the service configuration.

install.ps1

$serviceName = "ServiceApp"

# verify if the service already exists, and if yes remove it first
if (Get-Service $serviceName -ErrorAction SilentlyContinue)
{
	# using WMI to remove Windows service because PowerShell does not have CmdLet for this
    $serviceToRemove = Get-WmiObject -Class Win32_Service -Filter "name='$serviceName'"
    $serviceToRemove.delete()
    "service removed"
}
else
{
	# just do nothing
    "service does not exists"
}

"installing service"
# creating credentials which can be used to run my windows service
$secpasswd = ConvertTo-SecureString "somepassword" -AsPlainText -Force
$mycreds = New-Object System.Management.Automation.PSCredential ("[email protected]", $secpasswd)
$binaryPath = "C:\Apps\ServiceApp\ServiceApp.Console.dll"
# creating widnows service using all provided parameters
New-Service -name $serviceName -binaryPathName "$binaryPath action:run" -startupType Automatic -credential $mycreds

"installation completed" 

Service configuration:

try
{
	ServiceRunner<ServiceApp>.Run(config =>
	{
		config.SetName("ServiceApp");
		config.SetDisplayName("ServiceApp");
		config.SetDescription("ServiceApp");
		config.Service(serviceConfig =>
		{
			serviceConfig.ServiceFactory((extraArguments, controller) =>
			{
				//logger.Information("Initializing service factory");
				var path = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "logs\\service-init.txt");
				File.WriteAllText(path, "service is initializing");
				return new ServiceApp(serviceProvider.GetService<DeliveriesProcessor>(),
					serviceProvider.GetService<PickupsProcessor>(),
					serviceProvider.GetService<MockedForTestingProcessor>(),                                
					serviceProvider.GetService<ILoggerFactory>().CreateLogger<ServiceApp>(),
					serviceProvider.GetService<IOptions<ServiceOptions>>());
			});

			serviceConfig.OnStart((service, extraParams) =>
			{
				var path = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "logs\\service-start.txt");
				File.WriteAllText(path, "service is starting");
				//logger.Information("Starting service.. ");
				service.Start();
			});

			serviceConfig.OnStop(service =>
			{
				//logger.Information("Stopping service.. ");
				var path = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "logs\\service-stop.txt");
				File.WriteAllText(path, "service is stopping");
				service.Stop();
			});

			serviceConfig.OnError(e =>
			{
				//logger.Error(string.Format("An error occurred while running the service: {0}", e.Message));
				//logger.Error(e.StackTrace);
				var path = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "logs\\service-error.txt");
				File.WriteAllText(path, e.StackTrace);
			});
		
		});
	});
}
catch (Exception ex)
{
	//logger.Error(string.Format("An error occurred while configuring the service. {0}", ex.Message));
	//logger.Error(ex.StackTrace);

        var path = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath, "logs\\exception.txt");
        File.WriteAllText(path, ex.StackTrace);
}

Special Characters In Password Not Working

I created a service and deployed it to the server.

I ran the following command:
.\myApp.exe username:MyUsername password:MyPassword!$?# action:install

I received the following errors:

The service did not start due to a logon failure

When I open the Windows Services Manager the service is installed with the correct username but it is not running. I right click > Properties > LogOn > Copy And Paste Password from command line, everything works correctly and the service starts.

Are special characters such as !, $, ?, and # not supported in the password field?

Trouble Running as a Service (action:run)

Hi Peter,

I have three services I have written that make use of your library. When I deploy any of them - deployed to Windows 10, Windows Server 2012 R2 and Windows Server 2016 - the service installs fine but does nothing when it runs - it only ever enters the Main method once right after install and never again.

If I try to run it at the console with the "action:run" parameter it gives me the following error:

Service [my service name] errored with exception : The service process could not connect to the service controller

If I run it from the console without the action parameter, it runs fine.

Thoughts?
Thanks!

Error 1053:The service did not respond to the start or control request in a timely fashion when trying to install service

Hi, @PeterKottas.

When I try to execute the command dotnet <my_service>.dll action:install, the following error occurs:

Exception: System.ComponentModel.Win32Exception: O serviço não respondeu à requisição de início ou controle em tempo hábil
at DasMulli.Win32.ServiceUtils.ServiceHandle.Start()
at DasMulli.Win32.ServiceUtils.Win32ServiceManager.CreateService(String serviceName, String displayName, String description, String binaryPath, Win32ServiceCredentials credentials, Boolean autoStart, Boolean startImmediately, ErrorSeverity errorSeverity)
at PeterKottas.DotNetCore.WindowsService.ServiceRunner1.Install(HostConfiguration1 config, ServiceController sc, Int32 counter)
at PeterKottas.DotNetCore.WindowsService.ServiceRunner1.UsingServiceController(HostConfiguration1 config, Action2 action) at PeterKottas.DotNetCore.WindowsService.ServiceRunner1.Run(Action`1 runAction).

Can you help me?
Tks.
Rafaela.

ConsoleHost shutdown timeout too short

When running as a console application, shutdown is only given 150ms to complete. I have a very simple application and all I'm doing in shutdown is starting an async stop of an aspnet core application and it takes about 170ms to complete.

The ServiceHost gives a 1000ms timeout here in this case. I would recommend minimally making the timeouts match in the ConsoleHost. Ideally, all of these timeouts would be configurable. I believe the win32 service api allows an application to request additional startup/shutdown time if these timeouts were to be made significantly larger.

Running in docker

Do you know why I'd get a PlatformNotSupportedException when running your example inside a docker container using microsoft/dotnet:1.1.0-runtime image?

It throws this exception after the service factory returns a new instance of my service (which is empty and inherited from IMicroservice). The exact example you have.

Error while installing service on windows 10

I am getting the below mentioned error while running application from command prompt.

Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'System.Runtime, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified. at System.ModuleHandle.ResolveType(RuntimeModule module, Int32 typeToken, IntPtr* typeInstArgs, Int32 typeInstCount, IntPtr* methodInstArgs, Int32 methodInstCount, ObjectHandleOnStack type) at System.ModuleHandle.ResolveTypeHandleInternal(RuntimeModule module, Int32 typeToken, RuntimeTypeHandle[] typeInstantiationContext, RuntimeTypeHandle[] methodInstantiationContext) at System.Reflection.RuntimeModule.ResolveType(Int32 metadataToken, Type[] genericTypeArguments, Type[] genericMethodArguments) at System.Reflection.CustomAttribute.FilterCustomAttributeRecord(CustomAttributeRecord caRecord, MetadataImport scope, Assembly& lastAptcaOkAssembly, RuntimeModule decoratedModule, MetadataToken decoratedToken, RuntimeType attributeFilterType, Boolean mustBeInheritable, Object[] attributes, IList derivedAttributes, RuntimeType& attributeType, IRuntimeMethodInfo& ctor, Boolean& ctorHasParameters, Boolean& isVarArg) at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeModule decoratedModule, Int32 decoratedMetadataToken, Int32 pcaCount, RuntimeType attributeFilterType, Boolean mustBeInheritable, IList derivedAttributes, Boolean isDecoratedTargetSecurityTransparent) at System.Reflection.CustomAttribute.GetCustomAttributes(RuntimeAssembly assembly, RuntimeType caType) at System.Attribute.GetCustomAttributes(Assembly element, Type attributeType, Boolean inherit) at System.AppDomain.GetTargetFrameworkName()

My Service class is as:

`
namespace DataHunterService
{
public class HunterService : IMicroService
{
private IMicroServiceController Controller;

    public HunterService()
    {
        Controller = null;
    }

    public HunterService(IMicroServiceController controller)
    {
        Controller = controller;
    }

    public void Start()
    {
        Thread t = new Thread(new ThreadStart(this.DoWork));
        t.Start();
    }

    public void Stop()
    {
        System.Threading.Thread.Sleep(1000);
    }

    public void DoWork()
    {
        try
        {
            CustomLogger.Logger.LogInfo("Called DataHunterHost....!");
            var host = new DataHunterHost();
            host.Start();
        }
        catch (Exception)
        {

            Stop();
        }

    }
}

}
`

My Program.cs is as:

`
public class Program
{
public static void Main(string[] args)
{
try
{
ServiceRunner.Run(config =>
{
var name = config.GetDefaultName();
config.Service(serviceConfig =>
{
serviceConfig.ServiceFactory((extraArguments, controller) => new HunterService(controller));

                    serviceConfig.OnStart((service, extraParams) =>
                    {
                        CustomLogger.Logger.LogInfo("Service {0} started", name);
                        service.Start();
                    });

                    serviceConfig.OnStop(service =>
                    {

                        CustomLogger.Logger.LogInfo("Service {0} stopped", name);
                        service.Stop();
                    });

                    serviceConfig.OnError(e =>
                    {

                        CustomLogger.Logger.LogInfo("Service {0} errored with exception : {1}", name, e.Message);
                    });
                });
            });

        
        }
        catch (Exception e)
        {

            CustomLogger.Logger.LogInfo("Service errored with exception : {0}", e.Message);
        }

    }

`

And my project.json is as:

`
{
"version": "1.0.0-*",
"buildOptions": {
"emitEntryPoint": true,
"copyToOutput": {
"includeFiles": [ "appsettings.json", "datahunters.json" ]
}
},

"dependencies": {
"Microsoft.NETCore.App": {
"type": "platform",
"version": "1.0.1"
},
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",
"Quartz": "3.0.0-alpha3",
"DataHunter.Models": {
"target": "project",
"version": "1.0.0-"
},
"CustomLogger": {
"target": "project",
"version": "1.0.0-
"
},
"DataHunter": {
"target": "project",
"version": "1.0.0-*"
},
"PeterKottas.DotNetCore.WindowsService": "2.0.0",
"System.Runtime": "4.3.0"
},

"frameworks": {
"netcoreapp1.0": {
"imports": "dnxcore50"
}
}
}
`

Please help to resolve this.

Wix Installation

Because .net core console application is a dll file and it needs dotnet.exe to run,
I am confused about how to register it as a service with a wix installation script.

Can you provide an example or give a more clear example how to install the dll file as service from the command line ? thanks

OnStop not called intentionaly when system (Win7) shuts down?

Hi there.

Still love your library. :-)

Using your library I created a windows service running on my Win7 work machine. It does some brute force calculation stuff which is not complex but long running (brute force sudoku generating). Therefor I created it as windows service so each time the machine starts it starts automatically calculating some new sudokus.

The behaviour I experienced was that ,I implemented a function persisting the state of the generator and gets called when OnStop() is called. It works when I stop the service but OnStop() seems not get called when windows is shut down.

Is that behavior intended? (using the latest version of your library as downloaded today)

A side question: anyway to get notified when I close the console window (when not run as service but as console application)?

ExampleService works if I run through VS, but not with dotnet command

Hello,

I'm having an issue when I install your ExampleService (non-timer version to simplify it). If I edit the ServiceRunner, line 18 to manually specify ActionEnum.Install, I can get the ExampleService to install and run on my Windows 10 box. However, I have an issue when I attempt to install and run the ExampleService via dotnet commands. Here's what I'm doing:

Steps

  1. Open Admin command prompt and navigate to the folder PeterKottas.DotNetCore.Example on my harddrive.
  2. Issue dotnet publish command while in that directory
  3. Subsequently nav down to ..\bin\Debug\netcoreapp1.1\win81-x64\publish (where thePeterKottas.DotNetCore.Example.dll) is located
  4. Issue dotnet PeterKottas.DotNetCore.Example.dll action:install command

Result
The service installs and shows up in the Services mmc. However, it won't start. The error I receive is "The service did not respond to the start or control request in a timely fashion". I thought it might be a permissions issue, but if I use box admin credentials manually on the installed service, it still won't start.

Any ideas?

.net core 2

Downloaded the project and built it. I don't see any exe file being produced.

Service Name/Description

Hi Peter,

I'am using this library and I do struggle a little to setup this service.

I got it to install my service and start the service. The service name / description I provide gets ignored if I provide it like below.

public static void Main(string[] args)
{
ServiceRunner.Run(config =>
{
config.SetName("MY Service");
config.SetDescription("This service host a WebAPI");
}
}

if I run my install command as follows it does have the correct name / description but converted to all lower case (when viewed in local services - via control panel):
dotnet run action:install name:"MY CAPS Service" description:"UpperCase description of MY Service"

another question is when the service is already installed and started and I try to "install" it again I get a dotnet already inuse exception. If I stop the service manually before I run the install command it works.
my command I use to install:
dotnet run action:install

uninstall command:
dotnet run action:uninstall

Thank you

Severity Code Description Project File Line Suppression State Error Could not install package 'PeterKottas.DotNetCore.WindowsService 2.0.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.6.1', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.

we are trying to make a console application written in DOTNET CORE function as a service. This used to work in previous dotnet versions. Currently, when we create a service using sc create, the service gets created. But it goes into a stopped state. When we try and start it, we get the 1053 error that it didn't start up in a timely fashion.

After a lot of looking around, I came across your NUGET that helps convert the code into a service. I am trying to include your NUGET Package via
Install-Package PeterKottas.DotNetCore.WindowsService
But we are getting the error
Severity Code Description Project File Line Suppression State Error Could not install package 'PeterKottas.DotNetCore.WindowsService 2.0.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.6.1', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.

My questions are

  1. Why are we facing this issue with Windows services
  2. How do we overcome the error to incorporate into 4.6.1

"Time out has expired and the operation has not been completed" with the Example project

Hi!

I read #8 and tried to get the example project running. I got the following result:

C:\Users\dharmaturtle\Downloads\DotNetCore.WindowsService-master\Source\PeterKottas.DotNetCore.WindowsService.Example\bin\Debug\netcoreapp2.0>dotnet PeterKottas.DotNetCore.WindowsService.Example.dll action:install
Successfully registered and started service "PeterKottas.DotNetCore.WindowsService.Example.ExampleService" ("No description")
C:\Users\dharmaturtle\Downloads\DotNetCore.WindowsService-master\Source\PeterKottas.DotNetCore.WindowsService.Example\bin\Debug\netcoreapp2.0>dotnet PeterKottas.DotNetCore.WindowsService.Example.dll action:start
Service PeterKottas.DotNetCore.WindowsService.Example.ExampleService errored with exception : Time out has expired and the operation has not been completed.

I am running cmd as admin. Google isn't much help, though I did find this. I extended the timeout to 10 seconds and the same error occurs. There's nothing in the eventlog.

Anyone have any ideas? Thanks!

Service did not respond to the start or control request in a timely fashion

I am having issues starting my service on Windows Server 2008 R2.

Installed it via
dotnet .\MyWindowsServiceApplication.dll action:install name:MyWindowsServiceApplication displayName:MyWindowsServiceApplication description:"My windows service application."

And it shows up, when i try to start it I instantly get Error 1053 service did not respond to the start or control request in a timely fashion

When I run in manually through powershell via "dotnet .\MyWindowsServiceApplication.dll action:start" I get the following error through my logging around the ServiceRunner.Run:

2017-03-23 18:51:16.1887 ERROR Program - System.InvalidOperationException: Cannot start service MyWindowsServiceApplication on computer '.'. ---> System.ComponentModel.Win32Exception: The service did not respond to the start or control request in a timely fashion --- End of inner exception stack trace --- at System.ServiceProcess.ServiceController.Start(String[] args) at PeterKottas.DotNetCore.WindowsService.ServiceRunner1.StartService(HostConfiguration1 config, ServiceController sc) at PeterKottas.DotNetCore.WindowsService.ServiceRunner1.ConfigureService(HostConfiguration1 config) at PeterKottas.DotNetCore.WindowsService.ServiceRunner1.Run(Action1 runAction)

I can't tell what is going on as I get no other exception anywhere, any ideas?

I have managed to get this running locally on my computer which is the annoying part, just not on the server.

Is it possible to target netcoreapp1.0?

I have a netcoreapp1.0 which runs on AWS Lambda and also running on premise kit as well. It would be great if this could target 1.0 as well.

Any reason this project can't target netstandard1.6 or lower?

Run as network service

I'm looking to use .NET Core for a new windows service and the biggest hold off on switching to core was the lack of topshelf.

I love how your library looks and feels like topshelf, one thing I'm stuck on is how to get the service to log in as Network Service like Topshelf lets you.

Also is there any trick on getting this to work with IoCs?

Space in dotnet path causes service startup to fail?

Dotnet is installed in "C:\Program Files\dotnet\dotnet.exe", resulting in the following execution path for the service:

C:\Program Files\dotnet\dotnet.exe "<path>\MyService.dll" action:run

... where <path> is the unimportant (in this case) path to the dll. This fails because it attempts to execute "c:\Program" and treats the rest as arguments. Via the much easier to understand command line:

C:> C:\Program Files\dotnet\dotnet.exe "<path>\MyService.dll" action:run
'C:\Program' is not recognized as an internal or external command, operable program or batch file.
C:>

Technically, if the executable path (or any string argument) has a space in it, then and only then should it be encapsulated in double quotes. In practice, it seems fine to always put them there, however.

This issue is caused by the code in ServiceRunner.cs, specifically ServiceRunner.GetServiceCommand():

private static string GetServiceCommand(List<string> extraArguments)
        {
            var host = Process.GetCurrentProcess().MainModule.FileName;
            if (host.EndsWith("dotnet.exe", StringComparison.OrdinalIgnoreCase))
            {
                var appPath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath,
                    PlatformServices.Default.Application.ApplicationName + ".dll");
                host = string.Format("{0} \"{1}\"", host, appPath);
            }
            if (!host.EndsWith("dotnet.exe", StringComparison.OrdinalIgnoreCase))
            {
                //For self-contained apps, skip the dll path
                extraArguments = extraArguments.Skip(1).ToList();
            }

            var fullServiceCommand = string.Format("{0} {1} {2}", host, string.Join(" ", extraArguments), "action:run");
            return fullServiceCommand;
}

Perhaps this could be corrected with this:

private static string GetServiceCommand(List<string> extraArguments)
        {
            var host = Process.GetCurrentProcess().MainModule.FileName;
            bool hostIsDotnet = false;
            if (host.EndsWith("dotnet.exe", StringComparison.OrdinalIgnoreCase))
            {
                hostIsDotnet = true;
            }

            // Check for whitespace in the host string, encapsulate it if required
            if (Regex.IsMatch(host, "\\s"))
            {
                host = "\"" + host + "\"";
            }

            if(hostIsDotnet) { 
                var appPath = Path.Combine(PlatformServices.Default.Application.ApplicationBasePath,
                    PlatformServices.Default.Application.ApplicationName + ".dll");
                host = string.Format("{0} \"{1}\"", host, appPath);
            }
            else
            {
                //For self-contained apps, skip the dll path
                extraArguments = extraArguments.Skip(1).ToList();
            }

            var fullServiceCommand = string.Format("{0} {1} {2}", host, string.Join(" ", extraArguments), "action:run");
            return fullServiceCommand;
        }

Though perhaps looking for ANY whitespace is overkill; if(host.Contains(" ")) would work as well.

... or just always encapsulating it ought to work too.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.