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?
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With