Bir Windows hizmetinde hata ayıklamanın daha kolay yolu


325

Windows Hizmet Denetim Yöneticisi aracılığıyla hizmeti başlatmak ve daha sonra hata ayıklayıcı iş parçacığına eklemek için kodu adım atmanın daha kolay bir yolu var mı? Bu biraz hantal ve daha basit bir yaklaşım olup olmadığını merak ediyorum.


Bu User Voice biletini oluşturdum. Bunun için oy vermeyi düşünün: visualstudio.uservoice.com/forums/121579-visual-studio-ide/…
David

Yanıtlar:


271

Hizmette hızlı bir şekilde hata ayıklamak istersem Debugger.Break(), oraya giriyorum. Bu çizgiye ulaşıldığında beni VS'ye geri götürecek. İşiniz bittiğinde bu satırı kaldırmayı unutmayın.

GÜNCELLEME:#if DEBUG Pragmalara alternatif olarak , Conditional("DEBUG_SERVICE")özniteliği de kullanabilirsiniz .

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

Üzerinde OnStart, sadece şu yöntemi çağırın:

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

Burada kod yalnızca Hata Ayıklama derlemeleri sırasında etkinleştirilir. Bu sırada, hizmet hata ayıklaması için ayrı bir Yapılandırma Yapılandırması oluşturmak yararlı olabilir.


45
Veya Debugger.Launch () yöntemini kullanarak The Systems.Diagnostics ad alanı için bir kullanım ifadesi eklemeniz gerekir.
Omar Kooheji

1
Blog yazınız gayet iyi çalıştı ve günümü kurtardı :) Ancak Debugger.Break () benim için çalışmadı. Net, bazı optimizasyon nedenleriyle DebugMode işlevini atlıyor gibi görünüyor.
Bizhan

3
Debugger.BLL () çalışmadığında Debugger.Launch () benim için çalışır. (İşlem 255 koduyla çıkar.)
Oliver Bock

Nasıl çalışıyorsunuz? Hiçbir şey olmuyor. Break () ve Launch () 'ı denedim.
4thSpace

13
@ 4thSpace: 1. Hizmetinizi yükleyebilmeniz için hizmetiniz için bir yükleyici oluşturun. 2. Debugger.Launch () satırını ekleyin; Ana () başlangıcında. 3. Kodunuzu Hata Ayıklama modunda oluşturun. 4. Yüklü dll'lerin üzerine debug-dll'lerin üzerine yazın. 5. Hizmeti Windows Hizmetleri panelinden başlatın. Şimdi sizden bir hata ayıklayıcıya bağlanmanızı isteyen bir açılır pencere belirir. Bu şekilde benim için çalıştı. Umarım senin için de.
ffonz

210

Ben de normal yürütme ve bir hizmet olarak ayrı bir "sürüm" olması düşünüyorum, ama gerçekten bu amaç için ayrı bir komut satırı anahtarı ayırmak gerekiyor mu?

Yapamaz mısın?

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

Bu, uygulamanıza doubleclick (gerçekten ihtiyacınız varsa Tamam) aracılığıyla başlatabileceğiniz ve F5Visual Studio'da (proje seçeneğini bu /consoleseçeneği içerecek şekilde değiştirmenize gerek kalmadan) vurabileceğiniz "fayda" olacaktır .

Teknik olarak, Environment.UserInteractiveBayrak'ın WSF_VISIBLEgeçerli pencere istasyonu için ayarlanıp ayarlanmadığını kontrol eder , ancak false(etkileşimli olmayan) bir hizmet olarak çalıştırılmak dışında geri dönmesinin başka bir nedeni var mı?


Harika! Daha önce hata ayıklama, başka bir hizmet olarak uygulama olarak başlatmak için bir "if #debug" yöntemi kullandım. Bu, uygulamanın hata ayıklamak istiyorsanız bir hizmet olarak çalıştırılamamasına yol açar, ancak çözümünüz bunu çözer ve hizmet / uygulama ve sürüm / hata ayıklamanın dört kombinasyonunda da çalıştırılabilir olmasına izin verir.
Jonas

29
Programın çift tıklatıldığında çalışmasını istemiyorsanız (kullanıcılar karışabilir ve birkaç örneği çalıştırabilir vb.), System.Diagnostics.Debugger.IsAttachedBunun yerine kullanabilirsiniz Environment.UserInteractive.
Blorgbeard

5
ancak (etkileşimli olmayan) bir hizmet olarak çalıştırılmak dışında yanlış döndürülmesinin başka bir nedeni var mı? Birini düşünebilirim: Bir konsola eklenmeyen zamanlanmış bir görev.
Hogan

7
Bu durumda komut satırı parametrelerini kullanıyorum. - servisi yüklemek için install, hizmeti kaldırmak için ununinstall ve uygulamayı uygulama olarak çalıştırmak için interaktif. i add - proje seçenekleri için etkileşimli (Hata Ayıklama> Komut Bağımsız Değişkenleri). Böylece kolayca VS hata ayıklama yapabilirsiniz. --interactive gerektiği için çift tıklama istenmeyen çalışan bir örnek oluşturmaz. sadece 2 sentim.
Emir Akaydın

@ EmirAkaydın Evet, aslında komut satırı parametrelerini de "yedekleme" olarak kullanıyorum. Ancak, aslında çift ​​tıklama ve değil "interaktif" bir örnek ve bir hizmet bu şekilde başlatılamıyor gerçeği hakkında hata mesajı istedim . Değişen hedefleri sanırım ;-)
Christian.K

123

Birkaç hafta önce yeni bir hizmet projesi kurduğumda bu yazıyı buldum. Birçok harika öneri olsa da, hala istediğim çözümü bulamadım: Servis sınıflarında herhangi bir değişiklik yapmadan servis sınıflarını OnStartve OnStopyöntemlerini çağırma imkanı .

Geldiğim çözüm Environment.Interactive, bu gönderinin diğer cevaplarının önerdiği gibi, seçili çalışma modunu kullanıyor .

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

RunInteractiveYardımcı korumalı çağırmak için yansıma kullanır OnStartve OnStopyöntemler:

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

Bu gerekli tüm kod, ama ben de açıklamalar ile izlenim yazdı .


Bu, ServiceBase [] için iyi bir uzantı yöntemi yapar. Çözümümde Program.cs için ortak bir temel sınıf yerine birden çok hizmetim var, sadece servicesToRun.RunInteractive (args) diyorum. Güzel çözüm @Anders!
David Keaveny

3
Gerçekten harika bir çözüm. David'in hizmetleri yalnızca bir kod satırında çalıştırmasına izin verdiği gibi ServiceBase [] için basit bir uzantı oluşturdum: pastebin.com/F0fhhG2R
Funbit

4
+1 Eski bir meslektaşım, hemen hemen aynı şeyi yapan, ancak düşünmeye gerek kalmadan bir "EasyRunService" temel sınıfı (ServiceProcess'i devralır) yarattı (çünkü OnStart artık temel sınıfta). Gerçekten bir Windows hizmeti hata ayıklama bir esinti yapar.
sondergard

3
@ Chazt3n Proje çıktı türünüzün "Konsol Uygulaması" olarak ayarlandığından emin olun. Hizmet kurulumuna gelince, hangi çıktı türünün seçildiği önemli değildir, davranış aynıdır.
Funbit

2
Hala harika bir çözüm! Ekleyeceğim tek şey (gösterildiği gibi walk through), Console Applicationderlemeye ve çalıştırmaya çalışmadan önce projenin özelliklerine gittiğinizden ve çıktı türünü değiştirdiğinizden emin olmaktır . Adresinde bulabilirsiniz Project Properties -> Application -> Output type -> Console Application. Ayrıca, bunun benim için düzgün çalışması için startkomutu kullanarak uygulamayı çalıştırmak zorunda sona erdi . Örn: C:\"my app name.exe" -servicebenim için işe yaramaz. Bunun yerine kullandımC:\start /wait "" "my app name.exe" -service
Arvo Bowen

47

Bazen hizmetin başlatılması sırasında neler olup bittiğini analiz etmek önemlidir . İşleme başlarken burada yardımcı olmaz, çünkü hizmet başlatılırken hata ayıklayıcıyı takmak için yeterince hızlı değilsiniz.

Kısa cevap, bunu yapmak için aşağıdaki 4 kod satırını kullanıyorum :

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

Bunlar OnStart, hizmet yöntemine aşağıdaki gibi eklenir :

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

Daha önce yapmayanlar için, aşağıda ayrıntılı ipuçları ekledim , çünkü kolayca takılabilirsin. Aşağıdaki ipuçları Windows 7x64 ve Visual Studio 2010 Team Edition ile ilgilidir , ancak diğer ortamlar için de geçerli olmalıdır.


Önemli: Hizmeti "manuel" modda dağıtın ( InstallUtilVS komut isteminden yardımcı programı kullanarak veya hazırladığınız bir hizmet yükleyici projesini çalıştırın). Hizmeti başlatmadan önce Visual Studio'yu açın ve hizmetin kaynak kodunu içeren çözümü yükleyin - Visual Studio'da istediğiniz gibi ek kesme noktaları ayarlayın - hizmeti Hizmet Denetim Masası'ndan başlatın .

Debugger.LaunchKod nedeniyle bu, " Servicename.exe dosyasında işlenmeyen bir Microsoft .NET Framework özel durumu oluştu" iletişim kutusuna neden olur . görünmek. Ekran görüntüsünde gösterildiği gibi tıklayın :Elevate Yes, debug Servicename.exe
FrameworkException

Daha sonra, özellikle Windows 7 UAC'de yönetici kimlik bilgilerini girmenizi isteyebilir. Onları girin ve şunlarla devam edin Yes:

UACPrompt

Bundan sonra, tanınmış Visual Studio Just-In-Time Debugger penceresi görünür. Seçilen hata ayıklayıcıyı kullanarak hata ayıklamak isteyip istemediğinizi sorar. Tıklamadan önce Yes, yeni bir örnek açmak istemediğinizi seçin (2. seçenek) - burada yeni bir örnek yardımcı olmaz, çünkü kaynak kodu görüntülenmez. Böylece, daha önce açtığınız Visual Studio örneğini seçersiniz: VSDebuggerPrompt

Tıklamanızdan sonra Yes, nerede bir sonraki Visual Studio ederken doğrultusunda sarı ok hakkını gösterecektir Debugger.Launchifadesi olduğunu ve (yöntemini kodunuzu hata ayıklamak edebiliyoruz MyInitOnStartsizin başlatma içeren,). VSDebuggerBreakpoint

Düğmesine basılmasıF5 , hazırladığınız bir sonraki kesme noktasına ulaşılana kadar derhal yürütmeye devam eder .

İpucu: Hizmeti çalışır durumda tutmak için Hata Ayıkla -> Tümünü ayır'ı seçin . Bu, doğru başlatıldıktan ve başlangıç ​​kodunda hata ayıklamayı bitirdikten sonra hizmetle iletişim kuran bir istemci çalıştırmanıza olanak tanır. Shift+F5 (Hata ayıklamayı durdur) düğmesine basarsanız , hizmet sona erer. Bunu yapmak yerine, Hizmet Kontrol Panelini durdurmak için kullanmalısınız.

Not olduğunu

  • Eğer bir inşa edersen Release, daha sonra ayıklama kodu otomatik olarak çıkarılır ve servis normal çalışıyor.

  • Ben kullanıyorum Debugger.Launch(), hangi başlar ve bir hata ayıklayıcı ekler . Ben test ettik Debugger.Break()ki, sıra çalışma vermedi hiçbir üzerinde takılı ayıklayıcı henüz hizmet başlangıç olduğundan, (neden "Hata 1067: süreç beklenmedik şekilde sonlandırıldı." ).

  • RequestAdditionalTimeDaha uzun setleri hizmet başlatma için zaman aşımını (o olduğu değil kodu kendisini geciktirmek ama hemen devam edecektir Debugger.Launchaçıklamada). Aksi takdirde, base.Onstart(args)hata ayıklayıcıdan yeterince hızlı arama yapmazsanız, hizmeti başlatmak için varsayılan zaman aşımı süresi çok kısadır ve hizmeti başlatmak başarısız olur . Pratik olarak, 10 dakikalık bir zaman aşımı , hata ayıklayıcı başlatıldıktan hemen sonra "hizmet yanıt vermedi ..." iletisini görmenizi engeller .

  • Buna alıştığınızda, bu yöntem çok kolaydır, çünkü mevcut bir servis koduna 4 satır eklemenizi gerektirir , böylece hızlı bir şekilde kontrol ve hata ayıklama elde etmenizi sağlar.


1
Merakla, Debugger.Launch () kullanıcı istemi ile kullanıcı etkileşimi için bir zaman aşımı olup olmadığını biliyor musunuz?
Shiv

1
Açıklandığı gibi base.RequestAdditionalTime(600000), hizmet kontrolünün bu süre içinde aramadığı takdirde hizmeti 10 dakika boyunca sonlandırmasını önleyecektir base.OnStart(args)). Bunun dışında, bir süre sonra yönetici kimlik bilgilerini girmezseniz UAC'nin de iptal edeceğini hatırlıyorum (Tam olarak kaç saniye olduğunu bilmiyorum, ancak bir dakika içinde girmeniz gerektiğini düşünüyorum, aksi takdirde UAC iptal ediyor) , hata ayıklama oturumunu sonlandıracaktır.
Matt

2
Bu CustomCommand iletileri hata ayıklama için en iyi yöntem olarak bulundu. +1.
Justin

40

Genellikle yaptığım hizmetin mantığını ayrı bir sınıfta kapsüllemek ve bunu 'koşucu' sınıfından başlatmaktır. Bu koşucu sınıfı gerçek hizmet veya sadece bir konsol uygulaması olabilir. Yani çözümünüzün (en az) 3 projesi var:

/ConsoleRunner
   /....
/ServiceRunner
   /....
/ApplicationLogic
   /....

1
Ben de bu yaklaşımı kullanıyordum, ama bunun bir kombinasyonu ve yukarıdaki cevabın bir tedavi olduğunu düşünüyorum.
RobS

27

Fabio Scopel tarafından hazırlanan bu YouTube videosu bir Windows hizmetinin oldukça güzel bir şekilde nasıl açıklıyor ... Bunu yapmanın gerçek yöntemi videoda 4:45'te başlıyor ...

İşte videoda açıklanan kod ... Program.cs dosyanızda, Hata Ayıklama bölümüne ilişkin öğeleri ekleyin ...

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

        }
    }
}

Service1.cs dosyanıza OnDebug () yöntemini ekleyin ...

    public Service1()
    {
        InitializeComponent();
    }

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

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

    protected override void OnStop()
    {
    }

Nasıl çalışır

Temel olarak, korumalı olduğu için dışarıda erişilemeyen bir public void OnDebug()çağrı oluşturmanız gerekir OnStart(string[] args). void Main()Program eklenir #ifile ön işlemci #DEBUG.

Visual Studio, DEBUGprojenin Hata Ayıklama modunda derlenmiş olup olmadığını tanımlar.Bu , koşul doğru olduğunda hata ayıklama bölümünün (aşağıda) yürütülmesine izin verir

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

Ve bir konsol uygulaması gibi çalışacak, işler tamamlandığında modu değiştirebilirsiniz Releaseve normal elsebölüm mantığı tetikleyecektir


Bu cevabı arıyordum, neden bu kadar düşük sıralandığını bilmiyorum. Başkalarına veya muhtemelen daha fazla yoruma yardımcı olmak için kod
açıklandı

14

GÜNCELLEME

Bu yaklaşım açık ara en kolay olanıdır:

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

Orijinal cevabımı aşağıda gelecek kuşaklar için bırakıyorum.


Hizmetlerim, yapmak için herhangi bir iş olup olmadığını düzenli aralıklarla kontrol etmesini istediğim için bir Zamanlayıcıyı kapsayan bir sınıfa sahip olma eğilimindedir.

Sınıfa yeni başladık ve hizmetin başlatılması sırasında StartEventLoop () öğesini çağırıyoruz. (Bu sınıf bir konsol uygulamasından da kolayca kullanılabilir.)

Bu tasarımın güzel yan etkisi, Zamanlayıcıyı ayarladığınız bağımsız değişkenlerin, hizmetin gerçekten çalışmaya başlamadan önce gecikmesi için kullanılabilmesidir, böylece bir hata ayıklayıcıyı manuel olarak eklemek için zamanınız vardır.

ps Hata ayıklayıcıyı çalışan bir işleme el ile nasıl eklerim ?

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

Ayrıca aşağıdakileri yapıyordum (önceki cevaplarda zaten belirtilmişti, ancak bir Sürüm derlemesinde ateşlenmesini önlemek için koşullu derleyici [#if] bayrakları ile).

Bu şekilde yapmayı bıraktım çünkü bazen Release'de oluşturmayı ve bir istemci demosunda (utanç verici!) Çalışan bir uygulamada bir hata ayıklayıcı molası vermeyi unuturduk.

#if DEBUG
if (!System.Diagnostics.Debugger.IsAttached)
{
    System.Diagnostics.Debugger.Break();
}
#endif

// do somethingTamamlanması 30 dakikadan fazla sürerse ne olur ?
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
}

[Kod işaretleme sorunları ile hiçbir açıklama için üzgünüm] Hata ayıklama yapılarında MS Visual Studio (F5) normal çalışmalıdır. Sürüm derlemelerinde hala normal bir hizmet olarak çalışır.
Thomas Bratt

"Çevre.UserInteractive" özelliğini kullanmak için yukarıdaki Christian K. çözümüyle birleştirin ve çözüm gerçekten temiz ve basittir.
Ben Robbins

OnStartolduğu protectedve erişim düzeyini :( değiştiremez
Eduard Luca

10

Hizmeti komut isteminden (sc.exe) da başlatabilirsiniz.

Şahsen, kodu hata ayıklama aşamasında tek başına bir program olarak çalıştırırdım ve çoğu hata ütülenirse, hizmet olarak çalışmayı değiştiririm.


10

Eskiden programı bir hizmet olarak ya da normal bir uygulama olarak başlatan bir komut satırı anahtarına sahip olmaktı. Sonra, IDE benim anahtarı benim kod üzerinden adım böylece ayarlayın.

Bazı dillerde, bir IDE'de çalışıp çalışmadığını gerçekten algılayabilir ve bu anahtarı otomatik olarak gerçekleştirebilirsiniz.

Hangi dili kullanıyorsun


9

TopShelf kütüphanesini kullanın .

Bir konsol uygulaması oluşturun ve ardından Ana Ekranınızdaki kurulumu yapılandırın

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()
        {

        }
    }

Hizmetinizde hata ayıklamak için görsel stüdyoda F5'e basın.

Hizmeti yüklemek için cmd "console.exe install" yazın

Daha sonra hizmeti Windows hizmet yöneticisinden başlatabilir ve durdurabilirsiniz.


Onların lisanslarını anlamak çok kafa karıştırıcıydı
l --''''''--------- '' '' '' '' '' ''

Apache License afaik kullanıyorlar. Topshelf, Windows hizmetlerini geliştirmek ve hata ayıklamak için kullandığım en kolay yoldur. Süper kullanımı kolay. Bir konsol uygulaması olarak geliştirin. Bir komut satırı anahtarıyla hizmet olarak yükleyin. Şiddetle tavsiye edilir.
soyuyor

TopShelf bana tonlarca zaman kazandırdı. Thx
L_7337

8

Bence hangi işletim sistemini kullandığınıza bağlı, oturumlar arasındaki ayrım nedeniyle Vista'nın Hizmetlere bağlanması çok daha zor.

Geçmişte kullandığım iki seçenek:

  • Bir işlem için kalıcı bir hata ayıklayıcı ayarlamak için GFlags'ı (Windows için Hata Ayıklama Araçları'nda) kullanın. Bu, "Görüntü Dosyası Yürütme Seçenekleri" kayıt defteri anahtarında bulunur ve inanılmaz derecede kullanışlıdır. "Masaüstü ile Etkileşim" özelliğini etkinleştirmek için Hizmet ayarlarını değiştirmeniz gerektiğini düşünüyorum. Bunu sadece hizmetler için değil, tüm hata ayıklama türleri için kullanıyorum.
  • Diğer seçenek, kodu biraz ayırmaktır, böylece servis kısmı normal bir uygulama başlangıcı ile değiştirilebilir. Bu şekilde, basit bir komut satırı işaretini kullanabilir ve hata ayıklamayı çok daha kolay hale getiren bir işlem (Hizmet yerine) başlatabilirsiniz.

Bu yardımcı olur umarım.


GFlags için +1. Bu özellikle kaynak kodunu değiştiremiyorsanız (veya kodunuz yoksa) kullanışlıdır.
Chris Gillum

6

Ben hala SCM ... hiçbir "konsol" veya "uygulama" modu çerçevesinde tam hizmet davranışı ile yürütürken, OnStart () herhangi bir başlatma da dahil olmak üzere, hizmetimin her yönüyle hata ayıklamak istiyorum.

Bunu aynı projede hata ayıklama için kullanmak üzere ikinci bir hizmet oluşturarak yapıyorum. Hata ayıklama hizmeti, her zamanki gibi başlatıldığında (örneğin, hizmetler MMC eklentisinde), hizmet ana bilgisayarı işlemini oluşturur. Bu, gerçek hizmetinizi henüz başlatmamış olsanız bile hata ayıklayıcıyı bağlama işlemi sağlar. Hata ayıklayıcıyı işleme ekledikten sonra, gerçek hizmetinizi başlatın ve OnStart () dahil olmak üzere hizmet yaşam döngüsünde herhangi bir yere girebilirsiniz.

Çok az kod girişi gerektirdiğinden, hata ayıklama hizmeti servis kurulum projenize kolayca dahil edilebilir ve tek bir kod satırını yorumlayıp tek bir proje yükleyicisini silerek üretim sürümünüzden kolayca kaldırılabilir.

Detaylar:

1) Uyguladığınızı varsayarak MyServiceda oluşturun MyServiceDebug. Her ikisini de ServiceBasediziye şu şekilde ekleyin Program.cs:

    /// <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) Hizmet projesi için proje yükleyicisine gerçek hizmeti VE hata ayıklama hizmetini ekleyin:

resim açıklamasını buraya girin

Hizmet proje çıktısını hizmetin kurulum projesine eklediğinizde her iki hizmet de (gerçek ve hata ayıklama) dahil edilir. Kurulumdan sonra, her iki servis de service.msc MMC eklentisinde görünecektir.

3) MMC'de hata ayıklama hizmetini başlatın.

4) Visual Studio'da, hata ayıklayıcısını hata ayıklama hizmeti tarafından başlatılan işleme ekleyin.

5) Gerçek hizmeti başlatın ve hata ayıklamanın tadını çıkarın.


5

Bir hizmet yazdığımda bir dll projesine tüm hizmet mantığını koymak ve bu dll içine çağrı iki "ana" oluşturmak, biri bir Windows hizmeti ve diğeri bir komut satırı uygulaması.

Komut satırı uygulamasını hata ayıklama için kullanıyorum ve hata ayıklayıcıyı gerçek hizmete yalnızca komut satırı uygulamasında üretemediğim hatalar için ekliyorum.

Komut satırı aracı güzel bir hata ayıklama yardımı farklı bir ortam ve tam olarak gerçek bir hizmet gibi davranmazken, bu yaklaşımı sadece gerçek bir hizmette çalışırken tüm kodu test etmeniz gerektiğini hatırlıyorum.


4

Bir Windows hizmeti geliştirirken ve hata ayıklarken, genellikle / console startup parametresi ekleyerek ve bunu kontrol ederek bir konsol uygulaması olarak çalıştırırım. Hayatı kolaylaştırır.

static void Main(string[] args) {
    if (Console.In != StreamReader.Null) {
        if (args.Length > 0 && args[0] == "/console") {
            // Start your service work.
        }
    }
}

Hizmete özgü sorunları ayıklamak zorunda kalana kadar.
leppie

Doğru, o zaman hata ayıklayıcıyı gerçek hizmet sürecine iliştirmeniz gerekir. Ancak çoğu durumda hatalar her iki şekilde de ortaya çıkacak ve geliştirme çok daha kolay.
Maurice


2

Windows Hizmetlerinde hata ayıklamak için GFlags ve regedit tarafından oluşturulan bir .reg dosyasını birleştiriyorum.

  1. Exe adını ve vsjitdebugger'ı belirterek GFlags'ı çalıştırın
  2. Regedit'i çalıştırın ve GFlags'ın seçeneklerini ayarladığı yere gidin
  3. Dosya menüsünden "Anahtarı Dışa Aktar" ı seçin
  4. Bu dosyayı .reg uzantılı bir yere kaydedin
  5. Hizmette her zaman hata ayıklamak istediğinizde: .reg dosyasına çift tıklayın
  6. Hata ayıklamayı durdurmak istiyorsanız, ikinci .reg dosyasına çift tıklayın

Veya aşağıdaki kod parçacıklarını kaydedin ve servicename.exe dosyasını istediğiniz yürütülebilir adla değiştirin.


debugon.reg:

Windows Kayıt Defteri Düzenleyicisi Sürüm 5.00

[HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Görüntü Dosyası Yürütme Seçenekleri \ servicename.exe]
"GlobalFlag" = "0x00000000"
"Debugger" = "vsjitdebugger.exe"

debugoff.reg:

Windows Kayıt Defteri Düzenleyicisi Sürüm 5.00

[HKEY_LOCAL_MACHINE \ SOFTWARE \ Microsoft \ Windows NT \ CurrentVersion \ Görüntü Dosyası Yürütme Seçenekleri \ servicename.exe]
"GlobalFlag" = "0x00000000"

Bu hala Win 7 / Win 2008 üzerinde çalışıyor mu? Bu, support.microsoft.com/kb/824344 adresindeki yaklaşımdır, ancak etkileşimli hizmetlere dayanır ve öldürüldüklerini düşündüm? Her zaman benim tercih ettiğim seçenek olurdu (koda Debugger.Break () eklemenin bir seçenek olmayabileceği başlangıç ​​sorunları üretimde ortaya çıkabileceğinden).
piers7

1

Rutin küçük şeyler programlama için servisimde kolayca hata ayıklamak için çok basit bir hile yaptım:

Hizmetin başlangıcında, "/ debug" komut satırı parametresini kontrol ediyorum. Hizmet bu parametre ile çağrılırsa, her zamanki hizmet başlangıcı yapmıyorum, bunun yerine tüm dinleyicileri başlatıyorum ve "Hata ayıklama devam ediyor, sonlandırmak için Tamam'a basın" iletisini görüntüler.

Eğer servisim normal şekilde başlatılırsa, servis olarak başlar, komut satırı parametresi / debug ile başlatılırsa normal bir program gibi davranacaktır.

VS'de sadece hata ayıklama parametresi olarak / debug ekleyeceğim ve doğrudan servis programını başlatacağım.

Bu şekilde çoğu küçük tür problem için kolayca hata ayıklayabilirim. Tabii ki, bazı şeylerin hala hizmet olarak hata ayıklanması gerekiyor, ancak% 99 için bu yeterince iyi.



1

JOP'un cevabında bir varyasyon kullanıyorum. Komut satırı parametrelerini kullanarak IDE'de hata ayıklama modunu proje özellikleriyle veya Windows hizmet yöneticisi aracılığıyla ayarlayabilirsiniz.

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


1

Hata ayıklayıcı öğle yemeğinizi herhangi bir yere koyun ve başlangıçta Visualstudio ekleyin

#if DEBUG
    Debugger.Launch();
#endif

Ayrıca VS'yi Administatrator olarak başlatmanız ve bir sürecin farklı bir kullanıcı tarafından otomatik olarak hata ayıklanabilmesine izin vermeniz gerekir ( burada açıklandığı gibi ):

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


1

İşte herhangi bir ek "Hata Ayıklama" yöntemi olmadan ve entegre VS Birim Testleri ile hizmeti test etmek için kullandığım basit yöntem.

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

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

bu daha kolay. sadece hata ayıklamak için çözüm yapılandırma ayarını değiştirin, proje / çözümü çalıştırın, giderken kesme noktaları ekleyin.
Bahamut

0

Hata ayıklamayı yapmak için iki seçeneğiniz vardır.

  1. günlük dosyası oluşturmak: Şahsen ben uygulama günlüğü veya olay günlüğü kullanmak yerine metin dosyası gibi ayrı bir günlük dosyasını tercih ederim.Ama bu zaman adına çok pahalıya mal olacak, çünkü hala tam hata konumunun nerede olduğunu anlaması zor
  2. Uygulamayı konsol uygulamasına dönüştürün: bu, VS'de kullanabileceğimiz tüm hata ayıklama araçlarını sağlayacaktır.

Lütfen konu için oluşturduğum BU blog yazısına bakın .


0

Sadece yapıştır

Debugger.Break();

herhangi bir yerde kod.

Örneğin ,

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

Debugger.Break();Programınızı çalıştırdığınızda vurulur .


0

En iyi seçenek ' System.Diagnostics ' ad alanını kullanmaktır.

Visual Studio'da hata ayıklama ve serbest bırakma modu arasında geçiş yapmak için hata ayıklama modu ve serbest bırakma modu için engelleme yaparsanız kodunuzu içine alın,

#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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.