Tạo một dịch vụ cho Windows trong .NET 8

Trang Cập Nhật :
Ngày tạo trang :

Môi trường hoạt động

Visual Studio
  • Visual Studio 2022
.MẠNG
  • .NET 8
Windows
  • cửa sổ 11

Điều kiện tiên quyết

Visual Studio
  • Visual Studio 2022
.MẠNG
  • .NET 8
Windows
  • cửa sổ 10
  • cửa sổ 11
Máy chủ Windows
  • Windows 2012 trở lên

Điều kiện tiên quyết

  • Visual Studio đã được cài đặt

Lúc đầu

Khi tôi cố gắng tạo một dịch vụ Windows trong Visual Studio .NET, chỉ có các mẫu .NET Framework. Nó cũng có thể được tạo trong .NET (Core) và mẫu được đặt tên là "Worker Service".

Trong bài viết này, tôi sẽ giải thích cách sử dụng điều này để tạo, đăng ký và chạy dịch vụ Windows. Nội dung xử lý là tối thiểu, vì vậy nếu bạn có thể xác nhận rằng nó đang chạy dưới dạng dịch vụ Windows, vui lòng tạo hàm.

Tạo dự án

Khởi động Visual Studio. Chọn Tạo dự án mới.

Nhập vào サービス trường tìm kiếm ở trên, sau đó chọn Dịch vụ Nhân viên từ danh sách. "Dịch vụ Windows" là phiên bản .NET Framework, không có phiên bản .NET.

Tên dự án và vị trí có thể tùy ý. Nó không ảnh hưởng đến dịch vụ bạn đang đăng ký.

「. NET 8.0 được chọn và để mặc định để tạo nó.

Dự án đã được tạo ra.

Thêm thư viện

Ở trạng thái ban đầu, nó chỉ có chức năng "dịch vụ" và không có chức năng dành riêng cho Windows. Thêm thư viện có thể được sử dụng bởi dịch vụ Windows từ NuGet.

Nhấp chuột phải vào Dependencies và chọn Manage NuGet Packages.

Chọn tab Duyệt qua và nhập vào Microsoft.Extensions.Hosting.WindowsServices trường tìm kiếm. Nó sẽ xuất hiện trong danh sách, vì vậy hãy cài đặt nó.

Nhấp vào Áp dụng.

Nó đã được thêm vào như một gói.

Chỉnh sửa chương trình

Lần này, tôi sẽ tạo một dịch vụ định kỳ thêm văn bản vào tệp văn bản với tư cách là Ông / Bà.

Program.cs

Thêm chức năng của dịch vụ Windows như sau:

var builder = Host.CreateApplicationBuilder(args);
// ↓ここから追加
builder.Services.AddWindowsService();
// ↑ここまで追加
builder.Services.AddHostedService<Worker>();

var host = builder.Build();
host.Run();

Worker.cs

Bạn có thể thay đổi tên lớp một cách tùy ý, nhưng trong thời gian này, chúng tôi sẽ để mặc định.

Theo mặc định, chỉ có các phương thức được ExecuteAsync xử lý khi dịch vụ được thực thi, nhưng hãy thay đổi nó như sau:

public class Worker : BackgroundService
{
  private readonly ILogger<Worker> _logger;

  /// <summary>ログの出力先フォルダパス。</summary>
  private const string OutputLogFolderPath = @"C:\Temporary\";

  /// <summary>ログの出力先ファイルパス。</summary>
  private const string OutputLogFilePath = @$"{OutputLogFolderPath}Test.log";


  public Worker(ILogger<Worker> logger)
  {
    _logger = logger;
  }

  /// <summary>
  /// サービスが開始されたときに呼ばれます。
  /// </summary>
  /// <param name="stoppingToken"></param>
  /// <returns></returns>
  public override async Task StartAsync(CancellationToken stoppingToken)
  {
    if (Directory.Exists(OutputLogFolderPath) == false)
    {
      Directory.CreateDirectory(OutputLogFolderPath);
    }
    File.AppendAllText(OutputLogFilePath, $"StartAsync サービスを開始しました。\r\n");

    await base.StartAsync(stoppingToken);
  }

  /// <summary>
  /// サービスが終了したときに呼ばれます。
  /// </summary>
  /// <param name="stoppingToken"></param>
  /// <returns></returns>
  public override async Task StopAsync(CancellationToken stoppingToken)
  {
    File.AppendAllText(OutputLogFilePath, $"StopAsync サービスを終了しました。\r\n");
    File.AppendAllText(OutputLogFilePath, $"------------------------------\r\n");

    await base.StopAsync(stoppingToken);
  }

  /// <summary>
  /// サービスが実行されたときに呼ばれます。
  /// </summary>
  /// <param name="stoppingToken">サービスの非同期キャンセルトークン。</param>
  /// <returns></returns>
  protected override async Task ExecuteAsync(CancellationToken stoppingToken)
  {
    while (!stoppingToken.IsCancellationRequested)
    {
      File.AppendAllText(OutputLogFilePath, $"{DateTime.Now}\r\n");

      if (_logger.IsEnabled(LogLevel.Information))
      {
        _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
      }
      await Task.Delay(1000 * 60, stoppingToken);
    }
  }
}

Chúng tôi đã thêm một phương thức mới và StopAsync một phương thức mớiStartAsync. Như tên của nó, các phương thức này được gọi khi dịch vụ được khởi động và khi nó bị dừng. Nội dung của quá trình chỉ đơn giản là tạo thư mục và viết văn bản, vì vậy tôi sẽ bỏ qua lời giải thích.

ExecuteAsync Phương thức tiếp tục lặp lại với stoppingToken cho đến khi while nó được gắn cờ để hủy. Thêm những gì while bạn muốn được xử lý trong khi dịch vụ đang chạy. Tuy nhiên, nếu bạn chỉ viết quá trình bạn muốn di chuyển, dịch vụ sẽ chạy hết công suất, vì vậy Task.Delay điều cơ bản là phải di chuyển nó trong khi chờ đợi một thời gian nhất định với phương thức. Theo mặc định, nó được đặt thành 1 giây (1000ms), vì vậy vui lòng viết lại bất cứ lúc nào.

Gỡ lỗi

Bạn có thể gỡ lỗi từ Visual Studio. Hãy yên tâm rằng bạn sẽ không thực sự được đăng ký với dịch vụ.

Khi bạn chạy nó, bảng điều khiển sẽ xuất hiện.

Nếu quá trình là chính xác, bạn có thể thấy rằng các tập tin đã được tạo.

Nếu bạn muốn dừng gỡ lỗi, hãy đóng bảng điều khiển.

Nếu bạn kiểm tra nhật ký, bạn có thể thấy rằng quá trình khởi động dịch vụ đã qua, nhưng quá trình chấm dứt thì không. Để xem việc chấm dứt, bạn cần thực sự đăng ký với dịch vụ Windows để xác minh nó.

phát

Để có thể đăng ký với dịch vụ Windows, bạn phải xuất bản chương trình. Bấm chuột phải vào dự án và chọn Phát hành.

Chọn Thư mục.

Vị trí thư mục là tốt đẹp theo mặc định.

Cài đặt xuất bản sẽ được tạo, vì vậy hãy chọn "Hiển thị tất cả cài đặt".

Thiết lập nó như sau:

Tên tham số: Nhận xét giá trị
cấu hình Phát hành (mặc định)
Khung mục tiêu net8.0 (mặc định)
Chế độ triển khai Phụ thuộc khung Riêng cho môi trường đăng ký dịch vụ. Nếu bạn đang cài đặt thời gian chạy NEt 8, cài đặt này là OK.
Thời gian chạy mục tiêu Chiến thắng-x64 Nếu HĐH là môi trường 32 bit, hãy chọn win-x86
Vị trí mục tiêu Mặc định
Tạo một tệp duy nhất TRÊN
Biên dịch ReadyToRun tùy tiện

Sau khi cài đặt, nhấp vào nút "Gửi".

Nếu "Xuất bản thành công" được hiển thị ở góc dưới bên trái, nó đã hoàn tất.

Tệp đầu ra có thể được mở bằng cách nhấp vào "Vị trí mục tiêu".

Vị trí chương trình và ghi danh vào các dịch vụ

Đăng nhập vào môi trường mà bạn muốn đăng ký dịch vụ Windows với đặc quyền quản trị viên.

Sao chép tệp đã phát hành vào môi trường mà bạn muốn đăng ký làm dịch vụ Windows. Bạn có thể đặt nó trong bất kỳ thư mục nào, nhưng hãy nhớ rằng dịch vụ Windows sẽ luôn tham chiếu đến chương trình trong thư mục đó.

Ngoài ra, nếu tệp được xuất bản chứa tệp có phần mở rộng .pdb , không sao chép nó trong môi trường mà một người không xác định có thể nhìn thấy nó vì nó chứa thông tin phát triển.

Khi tệp đã sẵn sàng, hãy đăng ký nó dưới dạng dịch vụ Windows. Sử dụng lệnh để đăng ký. Nhấp chuột phải vào menu Bắt đầu và chọn "Thiết bị đầu cuối (Quản trị viên)". Ông / Bà đang chạy trong môi trường Windows 11, nhưng trong các môi trường khác, bạn có thể mở dấu nhắc lệnh với đặc quyền quản trị viên.

Trong trường hợp thiết bị đầu cuối, PowerShell có thể được mở trước, nhưng PowerShell có thể không thiết lập được chính xác, vì vậy hãy mở "Dấu nhắc lệnh".

Bạn có thể đăng ký nó với dịch vụ Windows bằng lệnh sau:

định dạng

sc create "<サービス名>" start=auto binpath="<プログラム(.exe)のパス>"

Ví dụ đầu vào

sc create "WindowsServiceDotNet8" start=auto binpath="C:\Service\WindowsServiceDotNet8\WindowsServiceDotNet8.exe"

<サービス名> là tên xuất hiện trong danh sách các dịch vụ Windows. Bạn có thể đặt tên hiển thị riêng, nhưng nếu bạn không chỉ định tên hiển thị, tên này sẽ được hiển thị. Nó cũng ảnh hưởng đến sổ đăng ký, vì vậy tên dịch vụ chữ và số được ưu tiên.

start=auto là cài đặt để tự động khởi động dịch vụ khi Windows khởi động. Nếu bạn muốn khởi động thủ công, hãy xóa mô tả này.

binpath là đường dẫn đầy đủ của các tệp chương trình.

Nếu bạn thực hiện lệnh và [SC] CreateService SUCCESS hiển thị, nó đã thành công.

Các dịch vụ bạn đã đăng ký sẽ xuất hiện trong danh sách.

Khởi động dịch vụ và kiểm tra hoạt động của nó

Nếu bạn muốn chạy dịch vụ, bạn có thể khởi động nó từ màn hình dịch vụ hoặc bằng lệnh sau.

sc start <サービス名>

Lệnh dừng như sau.

sc stop <サービス名>

Nếu bạn dừng dịch vụ, bạn có thể xác minh rằng quá trình tắt máy đang chạy.

Thêm mô tả vào dịch vụ

Trường mô tả của dịch vụ được thêm vào trống, nhưng bạn có thể thêm nó bằng lệnh sau.

sc description <サービス名> "<説明文>"

Xóa dịch vụ

Nếu bạn muốn xóa dịch vụ, bạn có thể làm như vậy bằng lệnh sau. Bạn phải có đặc quyền quản trị viên tại dấu nhắc lệnh.

sc delete <サービス名>