I am trying to run my ASP.Net Core 2.1 application as a service on Windows 10. My application runs fine when ran using VS2017 or if I publish to a folder and then start it from within that published folder with the --console arg. However, if I use sc create to create the service, getting a Success result, and then try to run it, I get an error in the Windows Application log stating...
System.IO.FileNotFoundException: The configuration file 'appsettings.json' was not found and is not optional. The physical path is 'C:\WINDOWS\system32\appsettings.json'.
at Microsoft.Extensions.Configuration.FileConfigurationProvider.Load(Boolean reload)
I have confirmed that my appsettings.json file exists in the published folder. The error message states that is is looking in the C:\WINDOWS\system32\ folder for the appsettings.json file rather than the published folder where the application .exe resides. This leads me to think the issue is with the way the current directory is being set when ran as a service, but I am having trouble identifying exactly why it is not working.
I have set up my Program.cs by following the instructions in this Microsoft document. My program.cs is shown below;
public class Program
{
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.AddUserSecrets<Startup>()
.Build();
public static void Main(string[] args)
{
ConfigureSerilog();
// Set up to run as a service if not in Debug mode or if a command line argument is not --console
var isService = !(Debugger.IsAttached || args.Contains("--console"));
if (isService)
{
var processModule = Process.GetCurrentProcess().MainModule;
if (processModule != null)
{
var pathToExe = processModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);
}
}
var builder = CreateWebHostBuilder(args.Where(arg => arg != "--console").ToArray());
var host = builder.Build();
if (isService)
{
host.RunAsCustomService();
}
else
{
try
{
Log.Information("Starting CAS API in Program.cs");
host.Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "CAS API Host terminated unexpectedly");
}
finally
{
Log.CloseAndFlush();
}
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) => { logging.AddEventSourceLogger(); })
.ConfigureAppConfiguration((context, config) =>
{
// Configure the app here.
})
.UseStartup<Startup>()
.UseSerilog()
.UseUrls("https://localhost:60026"); //This is only used when ran as a stand-alone service. Not in VisualStudio
private static void ConfigureSerilog()
{
// Set up Serilog
var connectionString = Configuration.GetConnectionString("CasDbConnectionString");
const string tableName = "Logs";
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Filter.ByExcluding(Matching.FromSource("Microsoft.EntityFrameworkCore.Query"))
.Enrich.FromLogContext()
.Enrich.WithMachineName()
.Enrich.WithThreadId()
.Enrich.WithUtcTimeStamp()
.Enrich.WithProperty("Application", $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}")
.Enrich.FromLogContext()
.CreateLogger();
}
I have tried replacing the...
host.RunAsCustomeService();
with ...
host.RunAsService();
And I still had the same problem.
I am running the sc command as follows;
sc create casapi start= auto binPath= c:\deployments\casapi\casapi.exe
And I see the casapi service listed in Windows Services. But if I run the sc command...
sc start casapi
I get the error indicated above.
If I go to the published folder in an elevated command prompt and type... casapi.exe --console The application runs as expected.
The casapi service is installed to Log On as a local system account.
NET Core and . NET 5+, developers who relied on . NET Framework could create Windows Services to perform background tasks or execute long-running processes. This functionality is still available and you can create Worker Services that run as a Windows Service.
Add Json File After adding the file, right click on appsettings. json and select properties. Then set “Copy to Ouptut Directory” option to Copy Always. Add few settings to json file, so that you can verify that those settings are loaded.
It means you can host a Web API in console application or windows service or OWIN or any other process that is managed by . NET framework. You need to do following steps in order to self-host a web API. Let's see how to host a simple Web API in console application.
As App configuration, we need to call SetCurrentDirectory and use a path to the app's published location.
For your issue, you access Directory.GetCurrentDirectory()
before calling Directory.SetCurrentDirectory(pathToContentRoot);
as you call ConfigureSerilog();
first.
Try to change the order like
// Set up to run as a service if not in Debug mode or if a command line argument is not --console
var isService = !(Debugger.IsAttached || args.Contains("--console"));
if (isService)
{
var processModule = Process.GetCurrentProcess().MainModule;
if (processModule != null)
{
var pathToExe = processModule.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);
}
}
ConfigureSerilog();
Try this.
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
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