Cara yang lebih mudah untuk men-debug layanan Windows

325

Apakah ada cara yang lebih mudah untuk melangkah melalui kode daripada memulai layanan melalui Windows Service Control Manager dan kemudian melampirkan debugger ke utas? Agak rumit dan saya bertanya-tanya apakah ada pendekatan yang lebih langsung.

Matthias
sumber
Saya membuat tiket Suara Pengguna ini. Pertimbangkan untuk memilihnya
David

Jawaban:

271

Jika saya ingin dengan cepat men-debug layanan, saya hanya masuk Debugger.Break()di sana. Ketika garis itu tercapai, itu akan menurunkan saya kembali ke VS. Jangan lupa untuk menghapus garis itu ketika Anda selesai.

UPDATE: Sebagai alternatif untuk #if DEBUGpragma, Anda juga dapat menggunakan Conditional("DEBUG_SERVICE")atribut.

[Conditional("DEBUG_SERVICE")]
private static void DebugMode()
{
    Debugger.Break();
}

Pada Anda OnStart, panggil saja metode ini:

public override void OnStart()
{
     DebugMode();
     /* ... do the rest */
}

Di sana, kode hanya akan diaktifkan selama pembuatan Debug. Sementara Anda melakukannya, mungkin berguna untuk membuat Konfigurasi Bangun terpisah untuk debugging layanan.

pel
sumber
45
Atau Anda bisa menggunakan Debugger.Launch () Anda harus menyertakan pernyataan menggunakan untuk namespace Systems.Diagnostics.
Omar Kooheji
1
Posting blog Anda berfungsi dengan baik dan menyelamatkan hari saya :) namun Debugger.Break () tidak bekerja untuk saya. tampaknya .Net melewatkan fungsi DebugMode untuk beberapa alasan terkait optimasi.
Bizhan
3
Debugger.Launch () berfungsi untuk saya ketika Debugger.Break () tidak. (Proses keluar dengan kode 255.)
Oliver Bock
Bagaimana kalian membuat ini bekerja? Tidak ada yang terjadi. Saya sudah mencoba Break () dan Launch ().
4thSpace
13
@ 4thSpace: 1. buat penginstal untuk layanan Anda, sehingga Anda dapat menginstal layanan Anda. 2. Tambahkan baris Debugger.Launch (); di awal Main Anda (). 3. Bangun kode Anda dalam mode Debug. 4. Timpa dll yang diinstal dengan debug-dll. 5. Mulai layanan dari panel Layanan Windows. Sekarang muncul sembulan untuk meminta Anda melampirkan debugger. Cara ini bekerja untuk saya. Semoga untuk Anda juga.
ffonz
210

Saya juga berpikir memiliki "versi" terpisah untuk eksekusi normal dan sebagai layanan adalah cara untuk pergi, tetapi apakah itu benar-benar diperlukan untuk mendedikasikan saklar baris perintah terpisah untuk tujuan itu?

Tidak bisakah Anda melakukannya:

public static int Main(string[] args)
{
  if (!Environment.UserInteractive)
  {
    // Startup as service.
  }
  else
  {
    // Startup as application
  }
}

Itu akan memiliki "manfaat", bahwa Anda hanya dapat memulai aplikasi Anda melalui klik dua kali (OK, jika Anda benar-benar membutuhkannya) dan Anda dapat menekan F5di Visual Studio (tanpa perlu mengubah pengaturan proyek untuk memasukkan /consoleOpsi itu).

Secara teknis, Environment.UserInteractivepemeriksaan jika WSF_VISIBLEBendera diatur untuk stasiun jendela saat ini, tetapi apakah ada alasan lain di mana ia akan kembali false, selain dijalankan sebagai layanan (non-interaktif)?

Christian.K
sumber
Bagus! Saya sebelumnya menggunakan metode "jika #debug" untuk memulai sebagai aplikasi jika debugging, atau layanan. Ini mengarah ke aplikasi yang tidak dapat dijalankan sebagai layanan jika Anda ingin men-debug-nya, tetapi solusi Anda menyelesaikannya dan menjadikannya bisa dijalankan di keempat kombinasi layanan / aplikasi dan rilis / debug.
Jonas
29
Jika Anda tidak ingin program untuk menjalankan ketika itu mengklik ganda (pengguna mungkin akan bingung dan menjalankan beberapa contoh dll), maka Anda dapat menggunakan System.Diagnostics.Debugger.IsAttachedbukan Environment.UserInteractive.
Blorgbeard keluar
5
tetapi apakah ada alasan lain di mana ia akan kembali palsu, selain dijalankan sebagai layanan (non-interaktif)? Saya bisa memikirkan satu: Tugas terjadwal yang tidak dilampirkan ke konsol.
Hogan
7
saya menggunakan parameter baris perintah untuk kasus ini. --Instal untuk menginstal layanan, --uninstall untuk menghapus layanan dan --interaktif untuk menjalankan layanan sebagai aplikasi. saya menambahkan --interaktif ke opsi proyek (Debugging> Argumen Perintah). Jadi saya dapat dengan mudah men-debug dari VS. mengklik ganda tidak akan membuat instance berjalan yang tidak diinginkan karena --interaktif diperlukan. hanya 2 sen saya.
Emir Akaydın
@ EmirAkaydın Ya, sebenarnya saya memiliki parameter baris perintah sebagai "cadangan" juga. Namun, saya sebenarnya ingin memiliki contoh "interaktif" ketika mengklik dua kali dan bukan dan pesan kesalahan tentang fakta bahwa layanan tidak dapat dimulai dengan cara itu. Memvariasikan gol, saya kira ;-)
Christian.K
123

Ketika saya membuat proyek layanan baru beberapa minggu yang lalu saya menemukan posting ini. Meskipun ada banyak saran bagus, saya masih tidak menemukan solusi yang saya inginkan: Kemungkinan untuk memanggil kelas layanan OnStartdan OnStopmetode tanpa modifikasi ke kelas layanan.

Solusi yang saya buat menggunakan Environment.Interactivemode pilih berjalan, seperti yang disarankan oleh jawaban lain untuk posting ini.

static void Main()
{
    ServiceBase[] servicesToRun;
    servicesToRun = new ServiceBase[] 
    {
        new MyService()
    };
    if (Environment.UserInteractive)
    {
        RunInteractive(servicesToRun);
    }
    else
    {
        ServiceBase.Run(servicesToRun);
    }
}

The RunInteractivehelper menggunakan refleksi untuk memanggil dilindungi OnStartdan OnStopmetode:

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);
}

Ini semua kode yang diperlukan, tetapi saya juga menulis panduan dengan penjelasan.

Anders Abel
sumber
Ini membuat metode ekstensi yang bagus untuk ServiceBase []. Saya memiliki beberapa layanan dalam solusi saya jadi daripada memiliki kelas dasar umum untuk Program.cs, saya hanya memanggil servicesToRun.RunInteractive (args). Solusi bagus @Anders!
David Keaveny
3
Solusi hebat memang. Saya membuat ekstensi sederhana untuk ServiceBase [] seperti yang disarankan David yang memungkinkan untuk menjalankan layanan hanya dalam satu baris kode: pastebin.com/F0fhhG2R
Funbit
4
+1 Mantan kolega saya membuat kelas dasar "EasyRunService" (yang mewarisi ServiceProcess) yang melakukan hal yang hampir sama, tetapi tanpa perlu refleksi (karena OnStart sekarang berada di kelas dasar). Itu benar-benar membuat debug layanan windows sangat mudah.
sondergard
3
@ Chazt3n Pastikan bahwa tipe keluaran proyek Anda diatur ke "Aplikasi Konsol". Adapun instalasi layanan, Tidak masalah tipe output mana yang dipilih, tingkah lakunya sama.
Funbit
2
Masih solusi hebat! Satu-satunya hal yang akan saya tambahkan (seperti yang ditunjukkan dalam walk through) adalah untuk memastikan Anda masuk ke properti proyek dan mengubah tipe output Console Applicationsebelum Anda mencoba untuk mengkompilasi dan menjalankan. Menemukannya di Project Properties -> Application -> Output type -> Console Application. Juga, agar ini berfungsi dengan baik untuk saya, saya akhirnya harus menjalankan aplikasi menggunakan startperintah. Mis: C:\"my app name.exe" -servicetidak akan bekerja untuk saya. Sebagai gantinya saya menggunakanC:\start /wait "" "my app name.exe" -service
Arvo Bowen
47

Terkadang penting untuk menganalisis apa yang terjadi selama dimulainya layanan. Melampirkan ke proses tidak membantu di sini, karena Anda tidak cukup cepat untuk melampirkan debugger saat layanan dimulai.

Jawaban singkatnya adalah, saya menggunakan 4 baris kode berikut untuk melakukan ini:

#if DEBUG
    base.RequestAdditionalTime(600000); // 600*1000ms = 10 minutes timeout
    Debugger.Launch(); // launch and attach debugger
#endif

Ini dimasukkan ke dalam OnStartmetode layanan sebagai berikut:

protected override void OnStart(string[] args)
{
    #if DEBUG
       base.RequestAdditionalTime(600000); // 10 minutes timeout for startup
       Debugger.Launch(); // launch and attach debugger
    #endif
    MyInitOnstart(); // my individual initialization code for the service
    // allow the base class to perform any work it needs to do
    base.OnStart(args);
}

Bagi mereka yang belum pernah melakukannya, saya telah memasukkan petunjuk rinci di bawah ini , karena Anda dapat dengan mudah terjebak. Petunjuk berikut merujuk ke Windows 7x64 dan Visual Studio 2010 Team Edition , tetapi juga berlaku untuk lingkungan lain.


Penting: Menyebarkan layanan dalam mode "manual" (menggunakan InstallUtilutilitas dari command prompt VS atau menjalankan proyek installer layanan yang telah Anda siapkan). Buka Visual Studio sebelum Anda memulai layanan dan memuat solusi yang berisi kode sumber layanan - mengatur breakpoint tambahan seperti yang Anda butuhkan di Visual Studio - kemudian mulai layanan melalui Panel Kontrol Layanan.

Karena Debugger.Launchkode, ini akan menyebabkan dialog "Pengecualian Microsoft .NET Framework tidak tertangani terjadi di Servicename.exe ." muncul. Klik seperti yang ditunjukkan pada tangkapan layar:Elevate Yes, debug Servicename.exe
FrameworkException

Setelah itu, khususnya di Windows 7 UAC mungkin meminta Anda untuk memasukkan kredensial admin. Masukkan mereka dan melanjutkan dengan Yes:

UACPrompt

Setelah itu, jendela Debugger Visual Studio Just-In-Time yang terkenal muncul. Ia bertanya apakah Anda ingin men-debug menggunakan debugger yang dihapus. Sebelum Anda mengklik Yes, pilih bahwa Anda tidak ingin membuka instance baru (opsi ke-2) - instance baru tidak akan membantu di sini, karena kode sumber tidak akan ditampilkan. Jadi Anda memilih contoh Visual Studio yang telah Anda buka sebelumnya sebagai gantinya: VSDebuggerPrompt

Setelah Anda mengklik Yes, setelah beberapa saat Visual Studio akan menunjukkan panah kuning tepat di baris di mana Debugger.Launchpernyataan itu dan Anda dapat men-debug kode Anda (metode MyInitOnStart, yang berisi inisialisasi Anda). VSDebuggerBreakpoint

Menekan F5melanjutkan eksekusi segera, hingga breakpoint berikutnya yang Anda siapkan tercapai.

Petunjuk: Agar layanan tetap berjalan, pilih Debug -> Lepaskan semua . Ini memungkinkan Anda menjalankan klien yang berkomunikasi dengan layanan setelah layanan dimulai dengan benar dan Anda selesai men-debug kode startup. Jika Anda menekan Shift+F5 (menghentikan debugging), ini akan menghentikan layanan. Alih-alih melakukan ini, Anda harus menggunakan Panel Kontrol Layanan untuk menghentikannya.

Catat itu

  • Jika Anda membuat Rilis, maka kode debug dihapus secara otomatis dan layanan berjalan secara normal.

  • Saya menggunakan Debugger.Launch(), yang memulai dan melampirkan debugger . Saya telah menguji Debugger.Break()juga, yang tidak berhasil , karena belum ada debugger yang terpasang saat memulai layanan (menyebabkan "Kesalahan 1067: Proses dihentikan tiba-tiba." ).

  • RequestAdditionalTimemenetapkan batas waktu lebih lama untuk memulai layanan (itu bukan menunda kode itu sendiri, tetapi akan segera melanjutkan dengan Debugger.Launchpernyataan). Kalau tidak, batas waktu default untuk memulai layanan terlalu pendek dan memulai layanan gagal jika Anda tidak base.Onstart(args)cukup cepat menelepon dari debugger. Praktis, batas waktu 10 menit menghindari Anda melihat pesan " layanan tidak merespons ..." segera setelah debugger dimulai.

  • Setelah Anda terbiasa, metode ini sangat mudah karena hanya mengharuskan Anda untuk menambahkan 4 baris ke kode layanan yang ada, yang memungkinkan Anda dengan cepat mendapatkan kontrol dan debug.

Mat
sumber
1
Karena penasaran, apakah Anda tahu jika ada waktu habis untuk interaksi pengguna dengan pengguna Debugger.Launch ()?
Shiv
1
Seperti yang dijelaskan, base.RequestAdditionalTime(600000)akan mencegah kontrol layanan menghentikan layanan selama 10 menit jika tidak memanggil base.OnStart(args)dalam rentang waktu tersebut). Terlepas dari itu, saya ingat bahwa UAC juga akan dibatalkan jika Anda tidak memasukkan kredensial admin setelah beberapa saat (saya tidak tahu berapa detik tepatnya, tetapi saya pikir Anda harus memasukkannya dalam satu menit, kalau tidak, UAC dibatalkan) , yang akan mengakhiri sesi debug.
Matt
2
Saya menemukan ini sebagai metode terbaik untuk men-debug pesan CustomCommand. +1.
Justin
40

Apa yang biasanya saya lakukan adalah merangkum logika layanan dalam kelas yang terpisah dan memulainya dari kelas 'pelari'. Kelas pelari ini dapat berupa layanan aktual atau hanya aplikasi konsol. Jadi solusi Anda memiliki (minimal) 3 proyek:

/ConsoleRunner
   /....
/ServiceRunner
   /....
/ApplicationLogic
   /....
Paul van Brenk
sumber
1
Saya dulu menggunakan pendekatan ini juga, tetapi saya pikir kombinasi dari ini dan jawaban di atas berfungsi dengan baik.
RobS
27

Video YouTube ini oleh Fabio Scopel menjelaskan cara men-debug layanan Windows dengan cukup baik ... metode sebenarnya untuk melakukannya dimulai pada 4:45 dalam video ...

Berikut adalah kode yang dijelaskan dalam video ... di file Program.cs Anda, tambahkan hal-hal untuk bagian Debug ...

namespace YourNamespace
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main()
        {
#if DEBUG
            Service1 myService = new Service1();
            myService.OnDebug();
            System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new Service1()
            };
            ServiceBase.Run(ServicesToRun);
#endif

        }
    }
}

Di file Service1.cs Anda, tambahkan metode OnDebug () ...

    public Service1()
    {
        InitializeComponent();
    }

    public void OnDebug()
    {
        OnStart(null);
    }

    protected override void OnStart(string[] args)
    {
        // your code to do something
    }

    protected override void OnStop()
    {
    }

Bagaimana itu bekerja

Pada dasarnya Anda harus membuat public void OnDebug()panggilan OnStart(string[] args)yang dilindungi dan tidak dapat diakses di luar. The void Main()Program ditambahkan dengan #ifpreprocessor dengan#DEBUG .

Visual Studio mendefinisikan DEBUGjika proyek dikompilasi dalam mode Debug. Ini akan memungkinkan bagian debug (di bawah) untuk mengeksekusi ketika kondisinya benar

Service1 myService = new Service1();
myService.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);

Dan itu akan berjalan seperti aplikasi konsol, setelah semuanya berjalan baik Anda dapat mengubah mode Releasedan bagian reguler elseakan memicu logika

Jason Miller
sumber
Saya mencari jawaban ini, tidak tahu mengapa peringkatnya sangat rendah. Menjelaskan kode untuk membantu orang lain atau mungkin lebih banyak komentar;)
Vinod Srivastav
14

MEMPERBARUI

Sejauh ini pendekatan ini paling mudah:

http://www.codeproject.com/KB/dotnet/DebugWinServices.aspx

Saya meninggalkan jawaban asli saya di bawah untuk keturunan.


Layanan saya cenderung memiliki kelas yang merangkum Timer karena saya ingin layanan memeriksa secara berkala apakah ada pekerjaan yang harus dilakukan.

Kami baru kelas dan panggilan StartEventLoop () selama layanan start-up. (Kelas ini dapat dengan mudah digunakan dari aplikasi konsol juga.)

Efek samping yang bagus dari desain ini adalah bahwa argumen yang Anda gunakan untuk mengatur Timer dapat digunakan untuk menunda sebelum layanan benar-benar mulai bekerja, sehingga Anda punya waktu untuk melampirkan debugger secara manual.

ps Bagaimana cara melampirkan debugger secara manual ke proses yang berjalan ...?

using System;
using System.Threading;
using System.Configuration;    

public class ServiceEventHandler
{
    Timer _timer;
    public ServiceEventHandler()
    {
        // get configuration etc.
        _timer = new Timer(
            new TimerCallback(EventTimerCallback)
            , null
            , Timeout.Infinite
            , Timeout.Infinite);
    }

    private void EventTimerCallback(object state)
    {
        // do something
    }

    public void StartEventLoop()
    {
        // wait a minute, then run every 30 minutes
        _timer.Change(TimeSpan.Parse("00:01:00"), TimeSpan.Parse("00:30:00");
    }
}

Saya juga biasa melakukan hal berikut (sudah disebutkan dalam jawaban sebelumnya tetapi dengan flag [#if] kompilator bersyarat untuk membantu menghindarinya dari rilis Release build).

Saya berhenti melakukannya dengan cara ini karena kadang-kadang kita akan lupa untuk membangun di Release dan memiliki istirahat debugger dalam aplikasi yang berjalan pada demo klien (memalukan!).

#if DEBUG
if (!System.Diagnostics.Debugger.IsAttached)
{
    System.Diagnostics.Debugger.Break();
}
#endif
rohancragg
sumber
Apa yang terjadi ketika // do somethingdibutuhkan lebih dari 30 menit untuk menyelesaikan?
Vinod Srivastav
13

static void Main()
{
#if DEBUG
                // Run as interactive exe in debug mode to allow easy
                // debugging.

                var service = new MyService();
                service.OnStart(null);

                // Sleep the main thread indefinitely while the service code
                // runs in .OnStart

                Thread.Sleep(Timeout.Infinite);
#else
                // Run normally as service in release mode.

                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[]{ new MyService() };
                ServiceBase.Run(ServicesToRun);
#endif
}
Thomas Bratt
sumber
[Maaf tentang tidak ada penjelasan dengan kode - masalah penurunan harga] Harus berjalan secara normal dari MS Visual Studio (F5) dalam build debug. Masih berjalan sebagai layanan normal dalam rilis build.
Thomas Bratt
Kombinasikan ini dengan solusi di atas oleh Christian K. untuk menggunakan properti "Environment.UserInteractive" dan solusinya benar-benar bersih dan sederhana.
Ben Robbins
OnStartadalah protecteddan Anda tidak dapat mengubah tingkat akses :(
Eduard Luca
10

Anda juga dapat memulai layanan melalui command prompt (sc.exe).

Secara pribadi, saya menjalankan kode sebagai program yang berdiri sendiri dalam fase debugging, dan ketika sebagian besar bug disetrika, ubah untuk menjalankan sebagai layanan.

aliasuppi
sumber
10

Apa yang saya lakukan adalah memiliki saklar baris perintah yang akan memulai program baik sebagai layanan atau sebagai aplikasi biasa. Kemudian, dalam IDE saya, saya akan mengatur sakelar sehingga saya bisa melangkah melalui kode saya.

Dengan beberapa bahasa Anda benar-benar dapat mendeteksi jika itu berjalan dalam IDE, dan melakukan pergantian ini secara otomatis.

Bahasa apa yang Anda gunakan?

BPR.
sumber
9

Gunakan perpustakaan TopShelf .

Buat aplikasi konsol lalu konfigurasikan pengaturan di Main Anda

class Program
    {
        static void Main(string[] args)
        {
            HostFactory.Run(x =>
            {

                // setup service start and stop.
                x.Service<Controller>(s =>
                {
                    s.ConstructUsing(name => new Controller());
                    s.WhenStarted(controller => controller.Start());
                    s.WhenStopped(controller => controller.Stop());
                });

                // setup recovery here
                x.EnableServiceRecovery(rc =>
                {
                    rc.RestartService(delayInMinutes: 0);
                    rc.SetResetPeriod(days: 0);
                });

                x.RunAsLocalSystem();
            });
        }
}

public class Controller
    {
        public void Start()
        {

        }

        public void Stop()
        {

        }
    }

Untuk men-debug layanan Anda, cukup tekan F5 di studio visual.

Untuk menginstal layanan, ketik cmd "install console.exe"

Anda kemudian dapat memulai dan menghentikan layanan di manajer layanan windows.

Misterhex
sumber
Lisensi mereka terlalu membingungkan untuk dipahami
l
Mereka menggunakan Lisensi Apache afaik. Topshelf adalah cara termudah yang saya gunakan untuk mengembangkan dan men-debug layanan windows. Sangat mudah digunakan. Berkembang sebagai aplikasi konsol. Instal sebagai layanan dengan satu sakelar baris perintah. Sangat dianjurkan.
merampas
TopShelf menghemat banyak waktu. Thx
L_7337
8

Saya pikir itu tergantung pada OS apa yang Anda gunakan, Vista jauh lebih sulit untuk dilampirkan ke Layanan, karena pemisahan antara sesi.

Dua opsi yang saya gunakan di masa lalu adalah:

  • Gunakan GFlags (di Alat Debugging untuk Windows) untuk menyiapkan debugger permanen untuk suatu proses. Ini ada dalam kunci registri "Opsi Eksekusi File Gambar" dan sangat berguna. Saya pikir Anda harus mengubah pengaturan Layanan untuk mengaktifkan "Berinteraksi dengan Desktop". Saya menggunakan ini untuk semua jenis debugging, bukan hanya layanan.
  • Pilihan lain, adalah untuk memisahkan kode sedikit, sehingga bagian layanan dapat dipertukarkan dengan startup aplikasi normal. Dengan begitu, Anda bisa menggunakan flag baris perintah sederhana, dan meluncurkan sebagai proses (bukan Layanan), yang membuatnya lebih mudah untuk debug.

Semoga ini membantu.

Kekayaan
sumber
+1 untuk GFlags. Ini sangat berguna jika Anda tidak dapat mengubah kode sumber (atau jika Anda tidak memilikinya).
Chris Gillum
6

Saya ingin dapat men-debug setiap aspek layanan saya, termasuk inisialisasi apa pun di OnStart (), sementara masih menjalankannya dengan perilaku layanan penuh dalam kerangka SCM ... tidak ada mode "konsol" atau "aplikasi".

Saya melakukan ini dengan membuat layanan kedua, dalam proyek yang sama, untuk digunakan untuk debugging. Layanan debug, ketika dimulai seperti biasa (yaitu dalam plugin layanan MMC), menciptakan proses host layanan. Ini memberi Anda proses untuk melampirkan debugger ke meskipun Anda belum memulai layanan nyata Anda. Setelah melampirkan debugger ke proses, mulai layanan nyata Anda dan Anda dapat membobolnya di mana saja dalam siklus hidup layanan, termasuk OnStart ().

Karena memerlukan intrusi kode yang sangat minimal, layanan debug dapat dengan mudah dimasukkan dalam proyek pengaturan layanan Anda, dan mudah dihapus dari rilis produksi Anda dengan mengomentari satu baris kode dan menghapus satu proyek installer.

Detail:

1) Dengan asumsi Anda menerapkan MyService, juga buat MyServiceDebug. Tambahkan keduanya ke dalam ServiceBasearray Program.csseperti ini:

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main()
    {
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
        { 
            new MyService(),
            new MyServiceDebug()
        };
        ServiceBase.Run(ServicesToRun);
    }

2) Tambahkan layanan nyata DAN layanan debug ke penginstal proyek untuk proyek layanan:

masukkan deskripsi gambar di sini

Kedua layanan (nyata dan debug) dimasukkan ketika Anda menambahkan output proyek layanan ke proyek pengaturan untuk layanan. Setelah instalasi, kedua layanan akan muncul di plugin MMC service.msc.

3) Mulai layanan debug di MMC.

4) Di Visual Studio, lampirkan debugger ke proses yang dimulai oleh layanan debug.

5) Mulai layanan nyata dan nikmati debugging.

BitMask777
sumber
5

Ketika saya menulis layanan, saya meletakkan semua logika layanan di proyek dll dan membuat dua "host" yang memanggil ke dll ini, satu adalah layanan Windows dan yang lainnya adalah aplikasi baris perintah.

Saya menggunakan aplikasi baris perintah untuk debugging dan melampirkan debugger ke layanan nyata hanya untuk bug saya tidak dapat mereproduksi dalam aplikasi baris perintah.

Saya menggunakan pendekatan ini hanya ingat bahwa Anda harus menguji semua kode saat menjalankan dalam layanan nyata, sedangkan alat baris perintah adalah bantuan debugging bagus itu lingkungan yang berbeda dan tidak berperilaku persis seperti layanan nyata.

Nir
sumber
4

Ketika mengembangkan dan men-debug layanan Windows, saya biasanya menjalankannya sebagai aplikasi konsol dengan menambahkan parameter startup / konsol dan memeriksa ini. Membuat hidup lebih mudah.

static void Main(string[] args) {
    if (Console.In != StreamReader.Null) {
        if (args.Length > 0 && args[0] == "/console") {
            // Start your service work.
        }
    }
}
Maurice
sumber
Sampai Anda harus men-debug masalah khusus layanan.
leppie
Benar, maka Anda harus melampirkan debugger ke proses layanan yang sebenarnya. Tetapi dalam banyak kasus bug akan muncul baik dan pengembangan jauh lebih mudah.
Maurice
4

Bagaimana dengan Debugger.Break () di baris pertama?

leppie
sumber
2

Untuk men-debug Layanan Windows saya menggabungkan GFlags dan file .reg yang dibuat oleh regedit.

  1. Jalankan GFlags, tentukan nama-exe dan vsjitdebugger
  2. Jalankan regedit dan pergi ke lokasi di mana GFlags mengatur opsinya
  3. Pilih "Kunci Ekspor" dari menu-file
  4. Simpan file itu di suatu tempat dengan ekstensi .reg
  5. Kapan saja Anda ingin men-debug layanan: klik dua kali pada file .reg
  6. Jika Anda ingin berhenti debug, klik dua kali pada file .reg kedua

Atau simpan cuplikan berikut dan ganti servicename.exe dengan nama yang dapat dieksekusi yang diinginkan.


debugon.reg:

Windows Registry Editor Versi 5.00

[HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Opsi Eksekusi File Gambar \ servicename.exe]
"GlobalFlag" = "0x00000000"
"Debugger" = "vsjitdebugger.exe"

debugoff.reg:

Windows Registry Editor Versi 5.00

[HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Opsi Eksekusi File Gambar \ servicename.exe]
"GlobalFlag" = "0x00000000"

sumber
Apakah ini masih berfungsi pada Win 7 / Win 2008? Ini pendekatan dari support.microsoft.com/kb/824344 tetapi bergantung pada layanan interaktif, dan saya pikir mereka terbunuh? Ini selalu digunakan untuk menjadi pilihan saya (karena masalah startup mungkin muncul dalam produksi, di mana memasukkan Debugger.Break () ke dalam kode mungkin bukan pilihan).
piers7
1

Untuk pemrograman hal-hal kecil yang rutin, saya telah melakukan trik yang sangat sederhana untuk dengan mudah men-debug layanan saya:

Pada awal layanan, saya memeriksa parameter baris perintah "/ debug". Jika layanan dipanggil dengan parameter ini, saya tidak melakukan startup layanan biasa, tetapi memulai semua pendengar dan hanya menampilkan kotak pesan "Debug dalam proses, tekan ok untuk mengakhiri".

Jadi jika layanan saya dimulai dengan cara biasa, itu akan mulai sebagai layanan, jika dimulai dengan parameter baris perintah / debug itu akan bertindak seperti program normal.

Dalam VS saya hanya akan menambahkan / debug sebagai parameter debugging dan memulai program layanan secara langsung.

Dengan cara ini saya dapat dengan mudah melakukan debug untuk sebagian besar masalah kecil. Tentu saja, beberapa hal masih perlu didebug sebagai layanan, tetapi untuk 99% ini cukup baik.

Sam
sumber
1
#if DEBUG
    System.Diagnostics.Debugger.Break();
#endif
Ervin Ter
sumber
1

Saya menggunakan variasi pada jawaban JOP. Menggunakan parameter baris perintah Anda dapat mengatur mode debugging di IDE dengan properti proyek atau melalui manajer layanan Windows.

protected override void OnStart(string[] args)
{
  if (args.Contains<string>("DEBUG_SERVICE"))
  {
    Debugger.Break();
  }
  ...
}
nh99
sumber
1

Cukup letakkan makan siang debugger Anda di mana saja dan lampirkan Visualstudio pada startup

#if DEBUG
    Debugger.Launch();
#endif

Anda juga perlu memulai VS sebagai Administrator dan Anda harus mengizinkan, bahwa suatu proses dapat secara otomatis di-debug oleh pengguna lain (seperti dijelaskan di sini ):

reg add "HKCR\AppID{E62A7A31-6025-408E-87F6-81AEB0DC9347}" /v AppIDFlags /t REG_DWORD /d 8 /f
wotanii
sumber
1

Gunakan proyek C # Template Layanan Windows untuk membuat aplikasi layanan baru https://github.com/HarpyWar/windows-service-template

Ada mode konsol / layanan yang terdeteksi secara otomatis, installer / deinstaller otomatis dari layanan Anda dan beberapa fitur yang paling sering digunakan.

HarpyWar
sumber
1

Berikut adalah metode sederhana yang saya gunakan untuk menguji layanan, tanpa metode "Debug" tambahan dan dengan Tes Unit VS terintegrasi.

[TestMethod]
public void TestMyService()
{
    MyService fs = new MyService();

    var OnStart = fs.GetType().BaseType.GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

    OnStart.Invoke(fs, new object[] { null });
}

// As an extension method
public static void Start(this ServiceBase service, List<string> parameters)
{
     string[] par = parameters == null ? null : parameters.ToArray();

     var OnStart = service.GetType().GetMethod("OnStart", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);

     OnStart.Invoke(service, new object[] { par });
}
MisterDr
sumber
1
static class Program
{
    static void Main()
    {
        #if DEBUG

        // TODO: Add code to start application here

        //    //If the mode is in debugging
        //    //create a new service instance
        Service1 myService = new Service1();

        //    //call the start method - this will start the Timer.
        myService.Start();

        //    //Set the Thread to sleep
        Thread.Sleep(300000);

        //    //Call the Stop method-this will stop the Timer.
        myService.Stop();

         #else
        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
        { 
            new Service1() 
        };

        ServiceBase.Run(ServicesToRun);
         #endif
    }
}
Mansoor
sumber
ini lebih mudah. cukup ubah pengaturan konfigurasi solusi ke debug, jalankan proyek / solusi, tambahkan breakpoint saat Anda melanjutkan.
Bahamut
0

Anda memiliki dua opsi untuk melakukan debugging.

  1. buat file log: Secara pribadi saya lebih suka file log terpisah seperti file teks daripada menggunakan aplikasi log atau event log. Tapi ini akan dikenakan biaya banyak atas nama waktu, karena masih sulit untuk mengetahui di mana lokasi kesalahan yang tepat adalah
  2. Konversikan aplikasi menjadi aplikasi konsol: ini akan memungkinkan Anda, semua alat debugging yang dapat kita gunakan di VS.

Silahkan lihat INI posting blog yang saya buat untuk topik.

Sandaru
sumber
0

Cukup tempel

Debugger.Break();

dimanapun dalam kode Anda.

Sebagai contoh ,

internal static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        private static void Main()
        {
            Debugger.Break();
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new Service1()
            };
            ServiceBase.Run(ServicesToRun);
        }
    }

Ini akan memukul Debugger.Break();ketika Anda menjalankan program Anda.

Chutipong Roobklom
sumber
0

Pilihan terbaik adalah menggunakan namespace ' System.Diagnostics '.

Lampirkan kode Anda jika ada yang memblokir mode debug dan mode rilis seperti yang ditunjukkan di bawah ini untuk beralih antara mode debug dan rilis di studio visual,

#if DEBUG  // for debug mode
       **Debugger.Launch();**  //debugger will hit here
       foreach (var job in JobFactory.GetJobs())
            {
                //do something 
            }

#else    // for release mode
      **Debugger.Launch();**  //debugger will hit here
     // write code here to do something in Release mode.

#endif
Amey P Naik
sumber