สร้างบริการสําหรับ Windows ใน .NET 8
สภาพแวดล้อมในการทํางาน
- วิชวลสตูดิโอ
-
- วิชวลสตูดิโอ 2022
- ตาข่าย
-
- .NET 8
- หน้าต่าง
-
- หน้าต่าง 11
ข้อกําหนดเบื้องต้น
- วิชวลสตูดิโอ
-
- วิชวลสตูดิโอ 2022
- ตาข่าย
-
- .NET 8
- หน้าต่าง
-
- หน้าต่าง 10
- หน้าต่าง 11
- เซิร์ฟเวอร์ Windows
-
- Windows 2012 หรือใหม่กว่า
เงื่อนไขเบื้องต้น
- Visual Studio ได้รับการติดตั้งแล้ว
ทีแรก
เมื่อฉันพยายามสร้างบริการ Windows ใน Visual Studio .NET มีเฉพาะเทมเพลต .NET Framework เท่านั้น นอกจากนี้ยังสามารถสร้างใน .NET (Core) และเทมเพลตมีชื่อว่า "Worker Service"
ในบทความนี้ ฉันจะอธิบายวิธีใช้สิ่งนี้เพื่อสร้าง ลงทะเบียน และเรียกใช้บริการ Windows เนื้อหาการประมวลผลมีน้อยดังนั้นหากคุณสามารถยืนยันได้ว่ากําลังทํางานเป็นบริการ Windows โปรดสร้างฟังก์ชัน
สร้างโครงการ
เริ่ม Visual Studio เลือก สร้างโครงการใหม่
ป้อนในช่อง サービス
ค้นหาด้านบน แล้วเลือก บริการผู้ปฏิบัติงาน จากรายการ
"บริการ Windows" เป็นรุ่น .NET Framework ซึ่งไม่มีรุ่น .NET
ชื่อโครงการและที่ตั้งสามารถเป็นไปตามอําเภอใจ ไม่ส่งผลกระทบต่อบริการที่คุณกําลังลงทะเบียน
「. NET 8.0 ถูกเลือก และปล่อยให้ค่าเริ่มต้นเพื่อสร้าง
โครงการถูกสร้างขึ้นแล้ว
การเพิ่มไลบรารี
ในสถานะเริ่มต้น มีเพียงฟังก์ชัน "บริการ" และไม่มีฟังก์ชันเฉพาะของ Windows เพิ่มไลบรารีที่สามารถใช้ โดยบริการ Windows จาก NuGet
คลิกขวาที่ การขึ้นต่อกัน แล้วเลือก จัดการแพ็คเกจ NuGet
เลือกแท็บเรียกดูและป้อนในช่อง Microsoft.Extensions.Hosting.WindowsServices
ค้นหา
มันจะปรากฏในรายการดังนั้นติดตั้ง
คลิก นําไปใช้
มันถูกเพิ่มเป็นแพ็คเกจ
โปรแกรมการแก้ไข
คราวนี้ฉันจะสร้างบริการที่เพิ่มข้อความลงในไฟล์ข้อความเป็นระยะ ๆ ในฐานะ Mr./Ms.
Program.cs
เพิ่มฟังก์ชันการทํางานของบริการ Windows ดังนี้:
var builder = Host.CreateApplicationBuilder(args);
// ↓ここから追加
builder.Services.AddWindowsService();
// ↑ここまで追加
builder.Services.AddHostedService<Worker>();
var host = builder.Build();
host.Run();
Worker.cs
คุณสามารถเปลี่ยนชื่อคลาสได้ตามอําเภอใจ แต่ในครั้งนี้เราจะปล่อยให้เป็นค่าเริ่มต้น
โดยค่าเริ่มต้นจะมีเพียงวิธีการที่ประมวลผล ExecuteAsync
เมื่อเรียกใช้บริการ แต่ลองเปลี่ยนดังนี้:
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);
}
}
}
เราได้เพิ่มวิธีการใหม่และวิธีการStopAsync
ใหม่StartAsync
ตามชื่อที่สื่อถึง วิธีการเหล่านี้จะถูกเรียกเมื่อบริการเริ่มต้นและเมื่อหยุดให้บริการ
เนื้อหาของกระบวนการเป็นเพียงการสร้างโฟลเดอร์และเขียนข้อความดังนั้นฉันจะละเว้นคําอธิบาย
ExecuteAsync
เมธอดนี้ยังคงวนซ้ําด้วย stoppingToken จนกว่าจะ while
ถูกตั้งค่าสถานะให้ยกเลิก
เพิ่มสิ่งที่คุณต้องการ while
ให้ประมวลผลในขณะที่บริการกําลังทํางาน
อย่างไรก็ตาม หากคุณเขียนเฉพาะกระบวนการที่คุณต้องการย้าย บริการจะทํางานเต็มประสิทธิภาพ ดังนั้นจึง Task.Delay
เป็นเรื่องพื้นฐานที่จะย้ายในขณะที่รอเวลาหนึ่งด้วยวิธีการ
โดยค่าเริ่มต้น จะถูกตั้งค่าเป็น 1 วินาที (1000ms) ดังนั้นโปรดเขียนใหม่ได้ตลอดเวลา
ดีบัก
คุณสามารถดีบักจาก Visual Studio มั่นใจได้ว่าคุณจะไม่ได้ลงทะเบียนกับบริการจริงๆ
เมื่อคุณเรียกใช้คอนโซลจะปรากฏขึ้น
หากกระบวนการถูกต้อง คุณจะเห็นว่าไฟล์ถูกสร้างขึ้นแล้ว
หากคุณต้องการหยุดการดีบัก ให้ปิดคอนโซล
หากคุณตรวจสอบบันทึก คุณจะเห็นว่ากระบวนการเริ่มต้นบริการได้ผ่านไปแล้ว แต่กระบวนการยกเลิกยังไม่ผ่านไป หากต้องการดูการยกเลิก คุณต้องลงทะเบียนกับบริการ Windows เพื่อตรวจสอบ
ประเด็น
เพื่อให้สามารถลงทะเบียนกับบริการ Windows ได้ คุณต้องเผยแพร่โปรแกรม คลิกขวาที่โปรเจ็กต์แล้วเลือกเผยแพร่
เลือก โฟลเดอร์
ตําแหน่งโฟลเดอร์จะดีตามค่าเริ่มต้น
การตั้งค่าการเผยแพร่จะถูกสร้างขึ้น ดังนั้นเลือก "แสดงการตั้งค่าทั้งหมด"
ตั้งค่าดังนี้:
ชื่อพารามิเตอร์ ค่า | หมายเหตุ | |
---|---|---|
การกําหนดค่า | ปล่อย (ค่าเริ่มต้น) | |
กรอบเป้าหมาย | net8.0 (ค่าเริ่มต้น) | |
โหมดการปรับใช้ | การพึ่งพาเฟรมเวิร์ก | แยกต่างหากสําหรับสภาพแวดล้อมการลงทะเบียนบริการ หากคุณกําลังติดตั้งรันไทม์ NEt 8 การตั้งค่านี้ใช้ได้ |
รันไทม์เป้าหมาย | วิน-x64 | หากระบบปฏิบัติการเป็นสภาพแวดล้อม 32 บิต ให้เลือก win-x86 |
สถานที่เป้าหมาย | เริ่ม ต้น | |
การสร้างไฟล์เดียว | บน | |
การรวบรวม ReadyToRun | โดยพลการ |
หลังจากตั้งค่าแล้ว ให้คลิกปุ่ม "ส่ง"
หาก "การเผยแพร่สําเร็จ" แสดงที่มุมล่างซ้าย แสดงว่าเสร็จสมบูรณ์
สามารถเปิดไฟล์เอาต์พุตได้โดยคลิก "ตําแหน่งเป้าหมาย"
การจัดวางโปรแกรมและการลงทะเบียนในบริการ
เข้าสู่ระบบสภาพแวดล้อมที่คุณต้องการลงทะเบียนบริการ Windows ด้วยสิทธิ์ของผู้ดูแลระบบ
คัดลอกไฟล์ที่เผยแพร่ไปยังสภาพแวดล้อมที่คุณต้องการลงทะเบียนเป็นบริการของ Windows คุณสามารถวางไว้ในโฟลเดอร์ใดก็ได้ แต่โปรดทราบว่าบริการของ Windows จะอ้างถึงโปรแกรมในโฟลเดอร์นั้นเสมอ
นอกจากนี้ หากไฟล์ที่เผยแพร่มีไฟล์ นามสกุล .pdb
อย่าคัดลอกในสภาพแวดล้อมที่บุคคลที่ไม่ระบุสามารถมองเห็นได้ เนื่องจากมีข้อมูลการพัฒนา
เมื่อไฟล์เข้าที่แล้ว ให้ลงทะเบียนเป็นบริการของ Windows ใช้คําสั่งเพื่อลงทะเบียน คลิกขวาที่เมนูเริ่มแล้วเลือก "เทอร์มินัล (ผู้ดูแลระบบ)" Mr./Ms. กําลังทํางานในสภาพแวดล้อม Windows 11 แต่ในสภาพแวดล้อมอื่นๆ สามารถเปิดพรอมต์คําสั่งด้วยสิทธิ์ของผู้ดูแลระบบได้
ในกรณีของเทอร์มินัล PowerShell อาจเปิดขึ้นก่อน แต่ PowerShell อาจไม่สามารถตั้งค่าได้อย่างถูกต้องดังนั้นให้เปิด "พรอมต์คําสั่ง"
คุณสามารถลงทะเบียนกับบริการ Windows ได้ด้วยคําสั่งต่อไปนี้:
รูปแบบ
sc create "<サービス名>" start=auto binpath="<プログラム(.exe)のパス>"
ตัวอย่างอินพุต
sc create "WindowsServiceDotNet8" start=auto binpath="C:\Service\WindowsServiceDotNet8\WindowsServiceDotNet8.exe"
<サービス名>
คือชื่อที่ปรากฏในรายการบริการของ Windows คุณสามารถตั้งค่าชื่อที่แสดงแยกต่างหากได้ แต่ถ้าคุณไม่ได้ระบุชื่อที่แสดงชื่อนี้จะปรากฏขึ้น
นอกจากนี้ยังส่งผลต่อรีจิสทรี ดังนั้นจึงควรใช้ชื่อบริการที่เป็นตัวอักษรและตัวเลข
start=auto
เป็นการตั้งค่าเพื่อเริ่มบริการโดยอัตโนมัติเมื่อ Windows เริ่มทํางาน
หากคุณต้องการเริ่มต้นด้วยตนเอง ให้ลบคําอธิบายนี้
binpath
คือเส้นทางแบบเต็มของแฟ้มโปรแกรม
หากคุณดําเนินการคําสั่งและ [SC] CreateService SUCCESS
แสดง จะสําเร็จ
บริการที่คุณลงทะเบียนควรปรากฏในรายการ
เริ่มบริการและตรวจสอบการทํางาน
หากคุณต้องการเรียกใช้บริการคุณสามารถเริ่มบริการได้จากหน้าจอบริการหรือด้วยคําสั่งต่อไปนี้
sc start <サービス名>
คําสั่งหยุดมีดังนี้
sc stop <サービス名>
หากคุณหยุดบริการ คุณสามารถตรวจสอบได้ว่ากระบวนการปิดเครื่องกําลังทํางานอยู่
เพิ่มคําอธิบายให้กับบริการ
ฟิลด์คําอธิบายของบริการที่เพิ่มจะว่างเปล่า แต่คุณสามารถเพิ่มได้ด้วยคําสั่งต่อไปนี้
sc description <サービス名> "<説明文>"
การลบบริการ
หากคุณต้องการลบบริการ คุณสามารถทําได้ด้วยคําสั่งต่อไปนี้ คุณต้องมีสิทธิ์ของผู้ดูแลระบบที่พรอมต์คําสั่ง
sc delete <サービス名>