sc.exe 启动后后台服务停止工作

问题描述 投票:0回答:1

我正在为后台服务编写代码,旨在通过OPC UA协议收集数据。在我决定重构以符合现代模式 (DI) 之前,服务按预期工作。

在重构服务的主要部分(while 循环例程)之前,我尝试重构 FileLogger 以将其用作服务,以便将其构造函数注入到我的托管服务中。

当我尝试在容器中注册服务时出现问题。首先,当我将日志目录的路径传递给构造函数时,我将其硬编码为日志目录的路径(worker 的第一次迭代使用了

@$"{System.AppContext.BaseDirectory}\logs"
路径),但它无法启动。

我将一段代码放入

StartAsync
方法中:

using (StreamWriter writer = new("path to file", true)) {
  await writer.WriteLineAsync(message);
}

没有创建文件,我的服务已退出游戏。看起来

StartAsync
根本没有启动,并且在创建主机时抛出了未处理的异常。

文件记录服务的结构:

using System.Globalization;
using System.Text.RegularExpressions;

namespace OpcService.Services;

internal interface IOpcLogger
{
  Task<bool> AppendMessage(string message, DateTime timestamp);

  Task<bool> AppendMessageList(List<string> messages, DateTime timestamp);

  bool DeleteMessagesBeforeToday(byte daysBeforeToday);
}

internal class OpcFileLogger : IOpcLogger
{
  private const string TIMESTAMP_FORMAT = "HH:mm:ss"; 
  
  public string MessageDirectory { get; }
  
  public OpcFileLogger(string messageDirectory) 
    => MessageDirectory = (string.IsNullOrWhiteSpace(messageDirectory)) 
      ? messageDirectory
      : throw new ArgumentException($"{nameof(messageDirectory)} cannot be null/empty/whitespace.");

  public async Task<bool> AppendMessage(string message, DateTime timestamp)
  {
    try {
      if (string.IsNullOrWhiteSpace(message)) {
        throw new ArgumentException($"{nameof(message)} cannot be null/empty/whitespace.", nameof(message));
      }
      if (!Directory.Exists(MessageDirectory)) {
        Directory.CreateDirectory(MessageDirectory);
      }
      message = $"[{timestamp.ToString(TIMESTAMP_FORMAT)}] {message}";
      using (StreamWriter writer = new(@$"{MessageDirectory}\{timestamp.ToString("ddMMyyyy")}.txt", true)) {
        await writer.WriteLineAsync(message);
      }
      return true;
    } catch {  
      return false;
    }
  }
  // other methods
}

依赖类:

internal class OpcUaWorker : BackgroundService 
{
  private WorkerSettings? ServiceSettings { get; set; }

  private readonly IOpcLogger _opcLogger; 

  private string WorkerFilePath { get; } = @$"{System.AppContext.BaseDirectory}\worker.json";

  private string DBConfigFilePath { get; } = @$"{System.AppContext.BaseDirectory}\db.config";

  // private string LogsDirectoryPath { get; } = @$"{System.AppContext.BaseDirectory}\logs";

  public OpcUaWorker(IOpcLogger opcLogger) 
    => _opcLogger = opcLogger;

  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    // opc session
  }

  public override async Task StartAsync(CancellationToken stoppingToken)
  {
    await _opcLogger.AppendMessage("Module is starting...\n", DateTime.Now);
    await base.StartAsync(stoppingToken);
  }

  public override async Task StopAsync(CancellationToken stoppingToken) 
  {
    await _opcLogger.AppendMessage("Module is stopping...\n", DateTime.Now);
    await base.StopAsync(stoppingToken); 
  }
}

注射器程序:

using OpcService;
using OpcService.Services;

IHost host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args)
  .UseWindowsService()
  .ConfigureServices(services => {
    services.AddSingleton<IOpcLogger, OpcFileLogger>(provider => new OpcFileLogger(@"d:\Projects\OpcUaWorker\logs"));
    services.AddHostedService<OpcUaWorker>();
  })
  .Build();
await host.RunAsync();

仅当使用

services.AddSingleton<IOpcLogger, OpcFileLogger>();
并且不使用参数化构造函数 (
public string MessageDirectory { get; } = @"d:\Projects\OpcUaWorker\logs";
) 时,它才有效。

按照评论中的建议,我在事件视图中发现以下错误记录:

Application: OpcUaWorker.exe
CoreCLR Version: 6.0.1122.52304
.NET Version: 6.0.11
Description: The process was terminated due to an unhandled exception.
Exception Info: System.InvalidOperationException: Unable to resolve service for type 'OpcService.Services.IOpcLogger' while attempting to activate 'OpcService.OpcUaWorker'.
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
c# dependency-injection windows-services .net-6.0 background-service
1个回答
0
投票

我通过查看事件查看器在评论部分的推荐的帮助下制定了解决方案。在我尝试使用不带

await host.RunAsync();
的 VSCode 调试代码(来自同一用户的另一个提示)后,我意识到我的对象没有使用正确的参数初始化,因此查看
OpcUaWorker
构造函数使我发现:

public OpcFileLogger(string messageDirectory) 
    => MessageDirectory = (string.IsNullOrWhiteSpace(messageDirectory)) 
      ? throw new ArgumentException($"{nameof(messageDirectory)} cannot be null/empty/whitespace.")
      : messageDirectory;
© www.soinside.com 2019 - 2024. All rights reserved.