1. Tạo dự án dịch vụ Windows
(1)
(2) Tên dịch vụ mặc định là "Service1". Nhấp đúp vào dịch vụ, chuyển đến chế độ "Thiết kế", nhấp chuột phải chọn "Thuộc tính" và có thể đổi tên dịch vụ trong cửa sổ thuộc tính.
Trong mã xử lý nghiệp vụ, hai phương thức OnStart và OnStop thường được ghi đè để quản lý khởi động và dừng hoạt động của các thành phần:
/// <summary>
/// Khởi động dịch vụ
/// </summary>
/// <param name="args"></param>
protected override void OnStart(string[] args)
{
LogHelper.GhiLog("Dịch vụ Demo đã khởi động");
// TODO: Xử lý nghiệp vụ
}
/// <summary>
/// Dừng dịch vụ
/// </summary>
protected override void OnStop()
{
LogHelper.GhiLog("Dịch vụ Demo đã dừng");
}
(3) Thêm trình cài đặt
(4) Cấu hình trình cài đặt
Lưu ý:
- Thiết lập Account thành LocalService.
- ServiceName cần khớp với tên lớp dịch vụ, ví dụ "DemoService".
- StartType nên là Automatic để tự động khởi động.
- Description dùng để mô tả dịch vụ, hiển thị trong cột mô tả của bảng điều khiển dịch vụ.
- DisplayName có thể khác ServiceName, đây là tên hiển thị trên bảng điều khiển dịch vụ.
2. Gỡ lỗi dịch vụ - Chạy dịch vụ Windows như ứng dụng console
(1) Thêm một phương thức mới để chạy OnStart và OnStop:
internal void TestStartupAndStop(string[] args)
{
this.OnStart(args);
Console.ReadLine();
this.OnStop();
}
(2) Sửa lại phương thức Main như sau:
static void Main(string[] args)
{
if (Environment.UserInteractive)
{
var service = new MyCustomService();
service.TestStartupAndStop(args);
}
else
{
// Nội dung cũ của phương thức Main
}
}
(3) Trong tab "Ứng dụng" của thuộc tính dự án, thiết lập "Kiểu đầu ra" thành "Ứng dụng Console".
(4) Bắt đầu gỡ lỗi (F5).
(5) Để chạy chương trình lại dưới dạng dịch vụ Windows, chỉ cần cài đặt và khởi động nó như cách thông thường mà không cần khôi phục các thay đổi này.
Trong một số trường hợp, bạn sẽ cần sử dụng công cụ gỡ lỗi Windows khi muốn kiểm tra các vấn đề xảy ra khi hệ thống khởi động.
3. Tạo giao diện quản lý dịch vụ trực quan
Xem mã nguồn
#region
const string tenDichVu = "MyService";
string duongDanDichVu = Application.StartupPath + "\\My_WindowsService.exe";
// Sự kiện: Cài đặt dịch vụ
private void btnCaiDat_Click(object sender, EventArgs e)
{
try
{
if (this.KiemTraTonTaiDichVu(tenDichVu))
{
this.GiaiBoDichVu(tenDichVu);
}
this.CaiDatDichVu(duongDanDichVu);
Thread.Sleep(200);
MessageBox.Show("Dịch vụ đã được cài đặt.", "Thông báo");
}
catch (Exception ex)
{
MessageBox.Show("Lỗi! " + ex.Message, "Thông tin lỗi", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// Sự kiện: Khởi động dịch vụ
private void btnKhoiDong_Click(object sender, EventArgs e)
{
try
{
if (this.KiemTraTonTaiDichVu(tenDichVu))
{
this.KhoiChayDichVu(tenDichVu);
MessageBox.Show("Dịch vụ đã khởi động.", "Thông báo");
btnKhoiDong.Enabled = false;
btnTat.Enabled = true;
}
else
{
MessageBox.Show("Dịch vụ không tồn tại.", "Thông báo");
}
}
catch (Exception ex)
{
MessageBox.Show("Lỗi! " + ex.Message, "Thông tin lỗi", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// Sự kiện: Dừng dịch vụ
private void btnTat_Click(object sender, EventArgs e)
{
try
{
if (this.KiemTraTonTaiDichVu(tenDichVu))
{
this.DungDichVu(tenDichVu);
MessageBox.Show("Dịch vụ đã dừng.", "Thông báo");
btnKhoiDong.Enabled = true;
btnTat.Enabled = false;
}
else
{
MessageBox.Show("Dịch vụ không tồn tại.", "Thông báo");
}
}
catch (Exception ex)
{
MessageBox.Show("Lỗi! " + ex.Message, "Thông tin lỗi", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// Sự kiện: Gỡ bỏ dịch vụ
private void btnGiaiBo_Click(object sender, EventArgs e)
{
try
{
if (this.KiemTraTonTaiDichVu(tenDichVu))
{
this.DungDichVu(tenDichVu);
this.GiaiBoDichVu(duongDanDichVu);
MessageBox.Show("Dịch vụ đã được gỡ bỏ.", "Thông báo");
}
else
{
MessageBox.Show("Dịch vụ không tồn tại.", "Thông báo");
}
}
catch (Exception ex)
{
MessageBox.Show("Lỗi! " + ex.Message, "Thông tin lỗi", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// Kiểm tra sự tồn tại của dịch vụ
private bool KiemTraTonTaiDichVu(string tenDichVu)
{
foreach (var dichVu in ServiceController.GetServices())
{
if (dichVu.ServiceName.Equals(tenDichVu, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
// Cài đặt dịch vụ
private void CaiDatDichVu(string duongDanDichVu)
{
using (var lopCaiDat = new AssemblyInstaller())
{
lopCaiDat.UseNewContext = true;
lopCaiDat.Path = duongDanDichVu;
IDictionary trangThaiLuu = new Hashtable();
lopCaiDat.Install(trangThaiLuu);
lopCaiDat.Commit(trangThaiLuu);
}
}
// Gỡ bỏ dịch vụ
private void GiaiBoDichVu(string duongDanDichVu)
{
using (var lopCaiDat = new AssemblyInstaller())
{
lopCaiDat.UseNewContext = true;
lopCaiDat.Path = duongDanDichVu;
lopCaiDat.Uninstall(null);
}
}
// Khởi chạy dịch vụ
private void KhoiChayDichVu(string tenDichVu)
{
using (var dieuKhien = new ServiceController(tenDichVu))
{
if (dieuKhien.Status == ServiceControllerStatus.Stopped)
{
dieuKhien.Start();
}
}
}
// Dừng dịch vụ
private void DungDichVu(string tenDichVu)
{
using (var dieuKhien = new ServiceController(tenDichVu))
{
if (dieuKhien.Status == ServiceControllerStatus.Running)
{
dieuKhien.Stop();
}
}
}
#endregion
Lưu ý: Nếu chưa thực hiện các bước sau, khi vận hành "Quản lý dịch vụ", bạn cần mở bằng quyền quản trị viên.
Do yêu cầu cài đặt dịch vụ, cần sử dụng quyền Administrator từ UAC. Nhấp chuột phải vào dự án, thêm "Tệp manifest ứng dụng" mới và sửa dòng <requestedExecutionLevel level="asInvoker" uiAccess="false" /> thành <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />.
4. Các vấn đề gặp phải
Vấn đề: Dịch vụ không thể dừng.
Giải pháp:
Mở cửa sổ lệnh với quyền quản trị viên, chạy lệnh sc queryex để lấy PID của dịch vụ (hoặc tìm trong Trình quản lý tác vụ), sau đó sử dụng lệnh taskkill để kết thúc nó.
| 12345678910111213141516 | C:\>sc queryex PlatformMessageService``SERVICE_NAME: PlatformMessageService``TYPE : 10 WIN32_OWN_PROCESS``STATE : 2 START_PENDING``(NOT_STOPPABLE, NOT_PAUSABLE, IGNORES_SHUTDOWN))``WIN32_EXIT_CODE : 0 (0x0)``SERVICE_EXIT_CODE : 0 (0x0)``CHECKPOINT : 0x1``WAIT_HINT : 0xbb8``PID : 524``FLAGS :``C:\>taskkill ``/PID 524 ``/F``THÀNH CÔNG: Quá trình có PID 3756 đã bị chấm dứt. |
|---|