Приложение ASP.Net Core 2.1 не может найти appsettings.json при запуске в качестве службы Windows - PullRequest
0 голосов
/ 09 июля 2019

Я пытаюсь запустить приложение ASP.Net Core 2.1 в качестве службы в Windows 10. Мое приложение работает нормально при запуске с использованием VS2017 или при публикации в папке и последующем запуске из этой опубликованной папки с помощью -консольный аргументТем не менее, если я использую sc create для создания службы, получения результата Success, а затем пытаюсь ее запустить, в журнале приложений Windows появляется сообщение об ошибке ...

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)   

Я подтвердил, чтомой файл appsettings.json находится в опубликованной папке.В сообщении об ошибке говорится, что в папке C: \ WINDOWS \ system32 \ находится файл appsettings.json, а не опубликованная папка, в которой находится приложение .exe.Это заставляет меня думать, что проблема в том, как текущий каталог устанавливается при запуске в качестве службы, но у меня возникают проблемы с определением, почему он не работает.

Я настроил свой Program.cs, следуя инструкциям в этого документа Microsoft .Мой program.cs показан ниже;

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();

    }

Я попытался заменить ...

host.RunAsCustomeService();

на ...

host.RunAsService();

И я до сих порвозникла та же проблема.

Я выполняю команду sc следующим образом:

sc create casapi start= auto binPath= c:\deployments\casapi\casapi.exe

И я вижу службу casapi, указанную в службах Windows.Но если я запускаю команду sc ...

sc start casapi 

, я получаю ошибку, указанную выше.

Если я захожу в опубликованную папку в командной строке с повышенными правами и набираю ... casapi.exe --console Приложение запускается, как и ожидалось.

Служба casapi устанавливается для входа в систему каклокальная системная учетная запись.

1 Ответ

2 голосов
/ 10 июля 2019

Как Конфигурация приложения , нам нужно вызвать SetCurrentDirectory и использовать путь к опубликованному местоположению приложения.

Для вашей проблемы вы набираете Directory.GetCurrentDirectory(), прежде чем звонить Directory.SetCurrentDirectory(pathToContentRoot);, так как вы сначала звоните 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);
        }
    }
    ConfigureSerilog();
...