Làm cách nào để gỡ lỗi các dịch vụ Windows trong Visual Studio?


85

Có thể gỡ lỗi các dịch vụ Windows trong Visual Studio không?

Tôi đã sử dụng mã như

System.Diagnostics.Debugger.Break();

nhưng nó đang đưa ra một số lỗi mã như:

Tôi gặp hai lỗi sự kiện: eventID 4096 VsJITDebugger và "Dịch vụ không phản hồi kịp thời yêu cầu bắt đầu hoặc kiểm soát."

Câu trả lời:


124

Sử dụng mã sau trong OnStartphương thức dịch vụ :

System.Diagnostics.Debugger.Launch();

Chọn tùy chọn Visual Studio từ thông báo bật lên.

Lưu ý: Để chỉ sử dụng nó trong chế độ Gỡ lỗi, #if DEBUGcó thể sử dụng chỉ thị trình biên dịch, như sau. Điều này sẽ ngăn việc tình cờ hoặc gỡ lỗi trong chế độ phát hành trên máy chủ sản xuất.

#if DEBUG
    System.Diagnostics.Debugger.Launch();
#endif

9
Hãy nhớ chạy VS với tư cách Quản trị viên. Sau đó, nó sẽ có sẵn trong danh sách.
Michael

1
Ai đó có thể làm rõ ý nghĩa của thông báo Cửa sổ bật lên không? Điều đó xuất hiện khi nào / như thế nào?
Mike

@Mike, cài đặt và khởi động dịch vụ, nó sẽ xuất hiện.
Harshit

@Mike, hộp thoại Windows của nó bật lên trên màn hình tương tác (đã đăng nhập) và hỏi bạn có muốn chọn một ứng dụng để gỡ lỗi quy trình không. Nếu bạn chọn VS nó sẽ khởi chạy trình gỡ lỗi và đính kèm để quá trình này
Chris Johnson

63

Bạn cũng có thể thử điều này.

  1. Tạo dịch vụ Windows của bạn và cài đặt và bắt đầu…. Đó là, các dịch vụ Windows phải đang chạy trong hệ thống của bạn.
  2. Trong khi dịch vụ của bạn đang chạy, hãy chuyển đến menu Gỡ lỗi , nhấp vào Đính kèm quy trình (hoặc xử lý trong Visual Studio cũ)
  3. Tìm dịch vụ đang chạy của bạn, sau đó đảm bảo rằng quá trình Hiển thị từ tất cả người dùngHiển thị quá trình trong tất cả các phiên được chọn, nếu không, hãy chọn nó.

nhập mô tả hình ảnh ở đây

  1. Nhấp vào nút Đính kèm
  2. Bấm OK
  3. Bấm Đóng
  4. Đặt điểm ngắt đến vị trí mong muốn của bạn và chờ thực thi. Nó sẽ tự động gỡ lỗi bất cứ khi nào mã của bạn đạt đến điểm đó.
  5. Hãy nhớ rằng, hãy đặt điểm ngắt của bạn ở nơi có thể truy cập , nếu nó là onStart (), sau đó dừng và bắt đầu lại dịch vụ

(Sau rất nhiều googling, tôi đã tìm thấy điều này trong "Cách gỡ lỗi Windows Services trong Visual Studio".)


2
Không thể nhìn thấy tùy chọn này trong VS2013 Update 5. :(
talabathula sandeep

1
Nhưng bạn cần phải chạy Vs-2017 của mình với tư cách quản trị viên
chozha rajan

1
Tôi đã thử cái này. Nó làm việc với một breakpoint trong onStop nhưng không phải trên onStart vì khi dịch vụ dừng debugger được tự do
KansaiRobot

22

Bạn nên tách tất cả mã sẽ thực hiện công việc từ dự án dịch vụ thành một dự án riêng biệt, sau đó tạo một ứng dụng thử nghiệm mà bạn có thể chạy và gỡ lỗi bình thường.

Dự án dịch vụ sẽ chỉ là phần vỏ cần thiết để thực hiện phần dịch vụ của nó.


RỒI !! ctrl + C rồi đến ctrl + V, ý tôi là với dự án mới. Ya mà chỉ tôi đang làm. Không thể đính kèm bất kỳ quy trình nào để gỡ lỗi hoặc bất kỳ tùy chọn nào khác thay vì dự án riêng biệt.?
PawanS

1
Tất nhiên là có thể, nhưng việc phát triển dịch vụ windows sẽ dễ dàng hơn nhiều nếu bạn loại bỏ phần dịch vụ trong quá trình phát triển.
Lasse V. Karlsen

hmmm ... đó là cách tốt nhưng đơn giản là nó tăng gấp đôi công việc. Tôi nghĩ bất kỳ cách nào khác sẽ tồn tại.
PawanS

9
Tôi không hiểu nó sẽ "nhân đôi" công việc như thế nào. Chắc chắn, nó sẽ thêm một chút chi phí nhỏ trong việc tạo dự án bổ sung và tách mã trong dịch vụ sang một dự án thứ ba, nhưng khác với điều đó, bạn sẽ không tạo một bản sao của mã, bạn sẽ di chuyển nó, và tham chiếu dự án đó.
Lasse V. Karlsen

3
^ + 1. Nó tăng gấp đôi công việc để quản lý dịch vụ, vốn là con số không về thời gian phát triển và bạn chỉ làm một lần. Gỡ lỗi một serice là ĐAU - thay vì làm cho nó bắt đầu kép dưới dạng dòng lệnh. Kiểm tra google để biết các lớp trình bao bọc được xác định trước cho phép thực hiện điều này (họ sử dụng phản chiếu để mô phỏng lớp dịch vụ start / stop no teh). một giờ làm việc, tiết kiệm hàng tấn, lỗ ròng: âm - bạn có thời gian.
TomTom

14

Đó là theo đề xuất của Lasse V. Karlsen hoặc thiết lập một vòng lặp trong dịch vụ của bạn sẽ đợi trình gỡ lỗi đính kèm. Đơn giản nhất là

while (!Debugger.IsAttached)
{
    Thread.Sleep(1000);
}

... continue with code

Bằng cách đó, bạn có thể khởi động dịch vụ và bên trong Visual Studio, bạn chọn "Đính kèm vào Quy trình ..." và đính kèm vào dịch vụ của bạn, sau đó sẽ tiếp tục hoạt động bình thường.


nơi tôi nên đặt mã trên ... và trong quá trình đính kèm Tôi nhận được dịch vụ của tôi tên là disable
PawanS

3
chúng tôi cũng sử dụng mã như thế này if (Environment.UserInteractive) { InteractiveRun(args); } else { Service instance = new Service(); ServiceBase[] servicesToRun = new ServiceBase[] { instance }; ServiceBase.Run(servicesToRun); }
Kirill Kovalenko

mã đó phải càng sớm càng tốt trước khi bất kỳ mã nào có thể chạy mà bạn muốn gỡ lỗi.
Pauli Østerø

@Pawan: Vào Start/ OnStart()tôi đoán
abatishchev

@Kirill: Sử dụng dấu ngã mã nổi bật bên trong bình luận, ví dụ:foo(bar)
abatishchev

7

Cho rằng ServiceBase.OnStartprotectedkhả năng hiển thị, tôi đã đi xuống tuyến đường phản chiếu để gỡ lỗi.

private static void Main(string[] args)
{
    var serviceBases = new ServiceBase[] {new Service() /* ... */ };

#if DEBUG
    if (Environment.UserInteractive)
    {
        const BindingFlags bindingFlags =
            BindingFlags.Instance | BindingFlags.NonPublic;

        foreach (var serviceBase in serviceBases)
        {
            var serviceType = serviceBase.GetType();
            var methodInfo = serviceType.GetMethod("OnStart", bindingFlags);

            new Thread(service => methodInfo.Invoke(service, new object[] {args})).Start(serviceBase);
        }

        return;
    }
#endif

    ServiceBase.Run(serviceBases);
}

Lưu ý rằng Thread, theo mặc định, là một chuỗi nền trước. returning từ Mainkhi các chuỗi dịch vụ giả đang chạy sẽ không kết thúc quá trình.


Vì OnStart được cho là sẽ quay trở lại nhanh chóng, bạn không cần phải làm điều đó trong một chuỗi khác. Tuy nhiên, nếu dịch vụ không bắt đầu một chuỗi khác, quy trình của bạn sẽ thoát ngay lập tức.
Matt Connolly

@MattConnolly Ở phần sau: nếu cần, tôi thay đổi đoạn mã trên để bắt đầu một chuỗi nền trước ngủ mãi mãi (trước khi xử lý bình thường).
ta.speot.is

Đây phải là một câu trả lời thực sự. Hoạt động đẹp!
lentyai

4

Bài viết của Microsoft giải thích cách gỡ lỗi dịch vụ Windows tại đây và phần nào mà mọi người có thể bỏ lỡ nếu họ gỡ lỗi bằng cách đính kèm vào một quy trình.

Dưới đây là mã làm việc của tôi. Tôi đã làm theo cách tiếp cận do Microsoft đề xuất.

Thêm mã này vào program.cs:

static void Main(string[] args)
{
    // 'If' block will execute when launched through Visual Studio
    if (Environment.UserInteractive)
    {
        ServiceMonitor serviceRequest = new ServiceMonitor();
        serviceRequest.TestOnStartAndOnStop(args);
    }
    else // This block will execute when code is compiled as a Windows application
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[]
        {
            new ServiceMonitor()
        };
        ServiceBase.Run(ServicesToRun);
    }
}

Thêm mã này vào lớp ServiceMonitor.

internal void TestOnStartAndOnStop(string[] args)
{
    this.OnStart(args);
    Console.ReadLine();
    this.OnStop();
}

Bây giờ đi đến Thuộc tính dự án , chọn tab "Ứng dụng" và chọn Loại đầu ra là "Ứng dụng bảng điều khiển" khi gỡ lỗi hoặc "Ứng dụng Windows" khi hoàn tất việc gỡ lỗi, biên dịch lại và cài đặt dịch vụ của bạn.

Nhập mô tả hình ảnh tại đây


có cách nào để đặt đầu ra cho Ứng dụng bảng điều khiển trong Ứng dụng gỡ lỗi và Cửa sổ được phát hành không?
kofifus

3

Bạn có thể tạo một ứng dụng bảng điều khiển. Tôi sử dụng mainchức năng này :

    static void Main(string[] args)
    {
        ImportFileService ws = new ImportFileService();
        ws.OnStart(args);
        while (true)
        {
            ConsoleKeyInfo key = System.Console.ReadKey();
            if (key.Key == ConsoleKey.Escape)
                break;
        }
        ws.OnStop();
    }

ImportFileServiceLớp của tôi giống hệt như trong ứng dụng dịch vụ Windows của tôi, ngoại trừ lớp kế thừa ( ServiceBase).


là nó trên cùng một dự án hoặc tôi một dự án khác cho ứng dụng giao diện điều khiển này
PawanS

Đó là 2 dự án khác biệt với các lớp tương tự. Trong trường hợp của tôi, đó là một dịch vụ đơn giản chỉ có lớp ImportFileService là trùng lặp. Khi tôi muốn phát triển / thử nghiệm, tôi sử dụng consoleapp, sau đó sao chép / dán. Giống như Lasse V. Karlsen đã nói, đó là một chương trình gỡ lỗi, tất cả logic (nghiệp vụ) là trên một dự án thứ ba.
kerrubin

OnStart không được bảo vệ?
Joe Phillips

Có, là. Đó là lý do tại sao tôi nói "ngoại trừ người thừa kế ( ServiceBase).". Tôi thấy việc gỡ lỗi trong Ứng dụng Console dễ dàng hơn, nhưng tôi hiểu nếu điều đó không thuyết phục được mọi người.
kerrubin

3

Tôi sử dụng một gói Nuget tuyệt vời có tên ServiceProcess.Helpers.

Và tôi trích dẫn ...

Nó giúp gỡ lỗi các dịch vụ windows bằng cách tạo giao diện người dùng play / stop / pause khi chạy với trình gỡ lỗi được đính kèm, nhưng cũng cho phép dịch vụ được cài đặt và chạy bởi môi trường máy chủ windows.

Tất cả điều này với một dòng mã.

http://windowsservicehelper.codeplex.com/

Sau khi cài đặt và có dây, tất cả những gì bạn cần làm là đặt dự án dịch vụ windows của bạn làm dự án khởi động và nhấp vào bắt đầu trên trình gỡ lỗi của bạn.


Cám ơn vì đã chia sẻ! Đó là giải pháp đơn giản nhất cho đến nay!
Wellington Zanelli

2

Bạn cũng có thể thử phương thức System.Diagnostics.Debugger.Launch () . Nó giúp đưa con trỏ trình gỡ lỗi đến vị trí được chỉ định và sau đó bạn có thể gỡ lỗi mã của mình.

Trước bước này, vui lòng cài đặt service.exe của bạn bằng dòng lệnh của dấu nhắc lệnh Visual Studio - installutil projectervice.exe

Sau đó, khởi động dịch vụ của bạn từ Bảng điều khiển -> Công cụ quản trị -> Quản lý máy tính -> Dịch vụ và ứng dụng -> Dịch vụ -> Tên dịch vụ của bạn


2

Tôi vừa thêm mã này vào lớp dịch vụ của mình để có thể gián tiếp gọi OnStart, tương tự cho OnStop.

    public void MyOnStart(string[] args)
    {
        OnStart(args);
    }

2

Tôi đang sử dụng /Consoletham số trong dự án Visual Studio Gỡ lỗiTùy chọn bắt đầuĐối số dòng lệnh :

public static class Program
{
    [STAThread]
    public static void Main(string[] args)
    {
         var runMode = args.Contains(@"/Console")
             ? WindowsService.RunMode.Console
             : WindowsService.RunMode.WindowsService;
         new WinodwsService().Run(runMode);
    }
}


public class WindowsService : ServiceBase
{
    public enum RunMode
    {
        Console,
        WindowsService
    }

    public void Run(RunMode runMode)
    {
        if (runMode.Equals(RunMode.Console))
        {
            this.StartService();
            Console.WriteLine("Press <ENTER> to stop service...");
            Console.ReadLine();

            this.StopService();
            Console.WriteLine("Press <ENTER> to exit.");
            Console.ReadLine();
        }
        else if (runMode.Equals(RunMode.WindowsService))
        {
            ServiceBase.Run(new[] { this });
        }
    }

    protected override void OnStart(string[] args)
    {
        StartService(args);
    }

    protected override void OnStop()
    {
        StopService();
    }

    /// <summary>
    /// Logic to Start Service
    /// Public accessibility for running as a console application in Visual Studio debugging experience
    /// </summary>
    public virtual void StartService(params string[] args){ ... }

    /// <summary>
    /// Logic to Stop Service
    /// Public accessibility for running as a console application in Visual Studio debugging experience
    /// </summary>
    public virtual void StopService() {....}
}

2

Tôi đã tìm thấy câu hỏi này, nhưng tôi nghĩ rằng một câu trả lời rõ ràng và đơn giản còn thiếu.

Tôi không muốn đính kèm trình gỡ lỗi của mình vào một quy trình, nhưng tôi vẫn muốn có thể gọi dịch vụ OnStartOnStopphương thức. Tôi cũng muốn nó chạy dưới dạng ứng dụng bảng điều khiển để tôi có thể ghi thông tin từ NLog vào bảng điều khiển.

Tôi đã tìm thấy những hướng dẫn tuyệt vời này thực hiện điều này:

Bắt đầu bằng cách thay đổi các dự án Output typethành Console Application.

Nhập mô tả hình ảnh tại đây

Thay đổi của bạn Program.csđể trông như thế này:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        // Startup as service.
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[]
        {
            new Service1()
        };

        if (Environment.UserInteractive)
        {
            RunInteractive(ServicesToRun);
        }
        else
        {
            ServiceBase.Run(ServicesToRun);
        }
    }
}

Sau đó, thêm phương thức sau để cho phép các dịch vụ chạy ở chế độ tương tác.

static void RunInteractive(ServiceBase[] servicesToRun)
{
    Console.WriteLine("Services running in interactive mode.");
    Console.WriteLine();

    MethodInfo onStartMethod = typeof(ServiceBase).GetMethod("OnStart",
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Starting {0}...", service.ServiceName);
        onStartMethod.Invoke(service, new object[] { new string[] { } });
        Console.Write("Started");
    }

    Console.WriteLine();
    Console.WriteLine();
    Console.WriteLine(
        "Press any key to stop the services and end the process...");
    Console.ReadKey();
    Console.WriteLine();

    MethodInfo onStopMethod = typeof(ServiceBase).GetMethod("OnStop",
        BindingFlags.Instance | BindingFlags.NonPublic);
    foreach (ServiceBase service in servicesToRun)
    {
        Console.Write("Stopping {0}...", service.ServiceName);
        onStopMethod.Invoke(service, null);
        Console.WriteLine("Stopped");
    }

    Console.WriteLine("All services stopped.");
    // Keep the console alive for a second to allow the user to see the message.
    Thread.Sleep(1000);
}

Mã tuyệt vời! Đơn giản, hiệu quả. +1. Nhưng thật dễ dàng, tôi đã biến đây thành một ứng dụng Biểu mẫu. Tôi thực sự ghét các ứng dụng bảng điều khiển. Ngoài ra, bạn có thể dễ dàng triển khai Nút biểu mẫu cho mỗi sự kiện dịch vụ.
Roland

1

Thật không may, nếu bạn đang cố gắng gỡ lỗi một cái gì đó ngay khi bắt đầu hoạt động Dịch vụ Windows, thì "đính kèm" vào quá trình đang chạy sẽ không hoạt động. Tôi đã thử sử dụng Debugger.Break () trong OnStart procecdure, nhưng với ứng dụng biên dịch 64-bit, Visual Studio 2010, lệnh break chỉ gây ra lỗi như sau:

System error 1067 has occurred.

Tại thời điểm đó, bạn cần thiết lập tùy chọn "Thực thi tệp hình ảnh" trong sổ đăng ký để tệp thực thi của bạn. Phải mất năm phút để thiết lập và nó hoạt động rất tốt. Đây là một bài viết của Microsoft, trong đó có các chi tiết:

Cách thực hiện: Tự động khởi chạy trình gỡ lỗi


1

Hãy thử dòng lệnh sự kiện sau xây dựng rất riêng của Visual Studio .

Cố gắng thêm điều này vào hậu xây dựng:

@echo off
sc query "ServiceName" > nul
if errorlevel 1060 goto install
goto stop

:delete
echo delete
sc delete "ServiceName" > nul
echo %errorlevel%
goto install

:install
echo install
sc create "ServiceName" displayname= "Service Display Name" binpath= "$(TargetPath)" start= auto > nul
echo %errorlevel%
goto start

:start
echo start
sc start "ServiceName" > nul
echo %errorlevel%
goto end

:stop
echo stop
sc stop "ServiceName" > nul
echo %errorlevel%
goto delete

:end

Nếu lỗi bản dựng với một thông báo như Error 1 The command "@echo off sc query "ServiceName" > nulvậy,Ctrl + Cthì Ctrl+ Vthông báo lỗi vào Notepad và xem câu cuối cùng của thông báo.

Nó có thể nói exited with code x . Tìm mã trong một số lỗi phổ biến ở đây và xem cách giải quyết.

1072 -- Marked for deletion → Close all applications that maybe using the service including services.msc and Windows event log.
1058 -- Can't be started because disabled or has no enabled associated devices → just delete it.
1060 -- Doesn't exist → just delete it.
1062 -- Has not been started → just delete it.
1053 -- Didn't respond to start or control → see event log (if logged to event log). It may be the service itself throwing an exception.
1056 -- Service is already running → stop the service, and then delete.

Tìm hiểu thêm về mã lỗi tại đây .

Và nếu lỗi bản dựng với thông báo như thế này,

Error    11    Could not copy "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". Exceeded retry count of 10. Failed.    ServiceName
Error    12    Unable to copy file "obj\x86\Debug\ServiceName.exe" to "bin\Debug\ServiceName.exe". The process cannot access the file 'bin\Debug\ServiceName.exe' because it is being used by another process.    ServiceName

mở cmd và sau đó cố gắng loại bỏ nó trước bằng taskkill /fi "services eq ServiceName" /f

Nếu tất cả đều tốt, F5sẽ đủ để gỡ lỗi nó.


0

Trong OnStartphương pháp, hãy làm như sau.

protected override void OnStart(string[] args)
{
    try
    {
        RequestAdditionalTime(600000);
        System.Diagnostics.Debugger.Launch(); // Put breakpoint here.

        .... Your code
    }
    catch (Exception ex)
    {
        .... Your exception code
    }
}

Sau đó, chạy một dấu nhắc lệnh với tư cách là quản trị viên và nhập các thông tin sau:

c:\> sc create test-xyzService binPath= <ProjectPath>\bin\debug\service.exe type= own start= demand

Dòng trên sẽ tạo test-xyzService trong danh sách dịch vụ.

Để bắt đầu dịch vụ, điều này sẽ nhắc bạn đính kèm để ra mắt trong Visual Studio hoặc không.

c:\> sc start text-xyzService

Để dừng dịch vụ:

c:\> sc stop test-xyzService

Để xóa hoặc gỡ cài đặt:

c:\> sc delete text-xyzService

0

Gỡ lỗi Dịch vụ Windows qua http (được thử nghiệm với VS 2015 Update 3 và .Net FW 4.6)

Đầu tiên, bạn phải tạo Dự án bảng điều khiển trong Giải pháp VS của bạn (Thêm -> Dự án mới -> Ứng dụng bảng điều khiển).

Trong dự án mới, tạo một lớp "ConsoleHost" với mã đó:

class ConsoleHost : IDisposable
{
    public static Uri BaseAddress = new Uri(http://localhost:8161/MyService/mex);
    private ServiceHost host;

    public void Start(Uri baseAddress)
    {
        if (host != null) return;

        host = new ServiceHost(typeof(MyService), baseAddress ?? BaseAddress);

        //binding
        var binding = new BasicHttpBinding()
        {
            Name = "MyService",
            MessageEncoding = WSMessageEncoding.Text,
            TextEncoding = Encoding.UTF8,
            MaxBufferPoolSize = 2147483647,
            MaxBufferSize = 2147483647,
            MaxReceivedMessageSize = 2147483647
        };

        host.Description.Endpoints.Clear();
        host.AddServiceEndpoint(typeof(IMyService), binding, baseAddress ?? BaseAddress);

        // Enable metadata publishing.
        var smb = new ServiceMetadataBehavior
        {
            HttpGetEnabled = true,
            MetadataExporter = { PolicyVersion = PolicyVersion.Policy15 },
        };

        host.Description.Behaviors.Add(smb);

        var defaultBehaviour = host.Description.Behaviors.OfType<ServiceDebugBehavior>().FirstOrDefault();
        if (defaultBehaviour != null)
        {
            defaultBehaviour.IncludeExceptionDetailInFaults = true;
        }

        host.Open();
    }

    public void Stop()
    {
        if (host == null)
            return;

        host.Close();
        host = null;
    }

    public void Dispose()
    {
        this.Stop();
    }
}

Và đây là mã cho lớp Program.cs:

public static class Program
{
    [STAThread]
    public static void Main(string[] args)
    {
        var baseAddress = new Uri(http://localhost:8161/MyService);
        var host = new ConsoleHost();
        host.Start(null);
        Console.WriteLine("The service is ready at {0}", baseAddress);
        Console.WriteLine("Press <Enter> to stop the service.");
        Console.ReadLine();
        host.Stop();
    }
}

Các cấu hình như các chuỗi kết nối phải được sao chép trong tệp App.config của dự án Console.

Để xây dựng bảng điều khiển, nhấp chuột phải vào dự án Console và nhấp vào Gỡ lỗi -> Bắt đầu phiên bản mới.


0

Chỉ cần thêm một contructor vào lớp dịch vụ của bạn (nếu bạn chưa có). Dưới đây, bạn có thể kiểm tra và làm ví dụ cho .net cơ bản trực quan.

Public Sub New()
   OnStart(Nothing) 
End Sub

Sau đó, nhấp chuột phải vào dự án và chọn " Gỡ lỗi -> Bắt đầu một phiên bản mới ".

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.