问题
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.
回答1:
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();
回答2:
Try this.
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
回答3:
If you're using Task Scheduler, you can write the directory you want into
Action Tab --> Edit --> Start in
So the program will start running from that directory.
来源:https://stackoverflow.com/questions/56956349/asp-net-core-2-1-application-cannot-find-appsettings-json-when-ran-as-a-windows