Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.net core hosted as windows service - How to use configuration files?

I have a .Net Core 2 WebAPI which I wish run as a Windows service. By default, the service runs on http://localhost:5000. When I run it locally I'm using a hosting.json file to set the IP and Port there but for some reason, the service won't start when I try to use the configuration files.

Here is my code:

public static void Main(string[] args)
{
    var config = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
        .AddJsonFile("hosting.json", optional: false, reloadOnChange: true)
        .AddCommandLine(args)
        .Build();

    if (Debugger.IsAttached || args.Contains("--console"))
        BuildWebHost(config, args).Run();
    else
        BuildServiceWebHost(config, args).RunAsService();
}

public static IWebHost BuildWebHost(IConfigurationRoot config, string[] args)
{
    return WebHost.CreateDefaultBuilder(args)
        .UseConfiguration(config)
        .UseStartup<Startup>()
        .Build();
}

public static IWebHost BuildServiceWebHost(IConfigurationRoot config, string[] args)
{
    var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
    var pathToContentRoot = Path.GetDirectoryName(pathToExe);

    var webHostArgs = args.Where(arg => arg != "--console").ToArray();

    return WebHost.CreateDefaultBuilder(webHostArgs)
        .UseConfiguration(config)
        .UseContentRoot(pathToContentRoot)
        .UseStartup<Startup>()
        .Build();
}

It runs on Debug (e.g. not as service), but when I set it as a windows service sc create MyService binPath="..." and try to run it I'm getting this error:

Windows could not start the MyService service on Local Computer.

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

I checked the Event Viewer and found this error: Exception Info: System.IO.FileNotFoundException: The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'C:\WINDOWS\system32\appsettings.json'.

How do I set the config file's path to be the same as the .exe when running as a service?

like image 922
Liran Friedman Avatar asked Jul 12 '18 11:07

Liran Friedman


People also ask

Can you use app config in .NET Core?

Application configuration in ASP.NET Core is performed using one or more configuration providers. Configuration providers read configuration data from key-value pairs using a variety of configuration sources: Settings files, such as appsettings. json.

How do I configure services in NET Core?

The ConfigureServices method is a place where you can register your dependent classes with the built-in IoC container. After registering dependent class, it can be used anywhere in the application. You just need to include it in the parameter of the constructor of a class where you want to use it.


1 Answers

I've managed to solve this issue in the following way:

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.ServiceProcess;

namespace WebAPI
{
    public class Program
    {
        public static void Main(string[] args)
        {
            if (Debugger.IsAttached || args.Contains("--console"))
                BuildWebHost(args).Run();
            else
            {
                var webHost = BuildServiceWebHost(args);

                var webHostService = new CustomWebHostService(webHost);
                ServiceBase.Run(webHostService);
            }
        }

        public static IWebHost BuildWebHost(string[] args)
        {
            var config = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile("hosting.json", optional: false, reloadOnChange: true)
                .AddCommandLine(args)
                .Build();

            return WebHost.CreateDefaultBuilder(args)
                .UseConfiguration(config)
                .UseStartup<Startup>()
                .Build();
        }

        public static IWebHost BuildServiceWebHost(string[] args)
        {
            var pathToExe = Process.GetCurrentProcess().MainModule.FileName;
            var pathToContentRoot = Path.GetDirectoryName(pathToExe);

            var webHostArgs = args.Where(arg => arg != "--console").ToArray();

            JObject hosting = JsonConvert.DeserializeObject<JObject>(File.ReadAllText($"{pathToContentRoot}/hosting.json"));
            return WebHost.CreateDefaultBuilder(webHostArgs)
                .UseUrls(hosting.Value<string>("server.urls"))
                .UseContentRoot(pathToContentRoot)
                .UseStartup<Startup>()
                .Build();
        }
    }
}

Hope this can help others struggling the same issue.

like image 174
Liran Friedman Avatar answered Sep 22 '22 15:09

Liran Friedman