54 votes

Est-ce que je cours en tant que service

Je suis en train d'écrire un peu de code d'amorçage pour un service qui peut être exécuté dans la console. Il se résume essentiellement à l'appel de la OnStart() la méthode au lieu d'utiliser le ServiceBase pour démarrer et arrêter le service (car il ne veut pas exécuter l'application si elle n'est pas installé comme un service et permet de déboguer un cauchemar).

Droit maintenant, je suis en utilisant le Débogueur.Les isattached à déterminer si je dois utiliser la ServiceBase.Exécuter ou [service].OnStart, mais je sais que ce n'est pas la meilleure idée, parce que, à certains moments, les utilisateurs finaux souhaitez exécuter le service dans une console (voir la sortie etc. en temps réel).

Des idées sur comment je pourrais déterminer si le service Windows contrôleur de démarrage "moi", ou si l'utilisateur a commencé à " moi " dans la console? Apparemment, L'Environnement.IsUserInteractive n'est pas la réponse. J'ai pensé à utiliser la ligne de commande args, mais qui paraît "sale".

J'ai toujours pu voir sur une instruction try-catch autour de ServiceBase.Exécuter, mais qui semble sale. Edit: Essayez de capture ne fonctionne pas.

J'ai une solution: mettre en place ici pour tous les autres intéressés gerbeurs:

    public void Run()
    {
        if (Debugger.IsAttached || Environment.GetCommandLineArgs().Contains<string>("-console"))
        {
            RunAllServices();
        }
        else
        {
            try
            {
                string temp = Console.Title;
                ServiceBase.Run((ServiceBase[])ComponentsToRun);
            }
            catch
            {
                RunAllServices();
            }
        }
    } // void Run

    private void RunAllServices()
    {
        foreach (ConsoleService component in ComponentsToRun)
        {
            component.Start();
        }
        WaitForCTRLC();
        foreach (ConsoleService component in ComponentsToRun)
        {
            component.Stop();
        }
    }

EDIT: Il y a une autre question sur StackOverflow où le gars avait des problèmes avec l'Environnement.CurrentDirectory être "C:\Windows\System32" on dirait que peut être la réponse. Je vais le tester aujourd'hui.

27voto

rnr_never_dies Points 71

Une autre solution de contournement .. peut donc être exécuté en tant que WinForm ou en tant que service Windows

 var backend = new Backend();

if (Environment.UserInteractive)
{
     backend.OnStart();
     Application.EnableVisualStyles();
     Application.SetCompatibleTextRenderingDefault(false);
     Application.Run(new Fronend(backend));
     backend.OnStop();
}
else
{
     var ServicesToRun = new ServiceBase[] {backend};
     ServiceBase.Run(ServicesToRun);
}
 

22voto

Sean Points 22088

J'utilise généralement le service Windows pour signaler qu'il s'agit d'une application console utilisant un paramètre de ligne de commande "-console" pour s'exécuter en tant que console. Sinon, il s'exécutera en tant que service. Pour déboguer, il suffit de définir les paramètres de ligne de commande dans les options du projet sur "-console" et c'est parti!

Cela facilite le débogage et signifie que l'application fonctionne comme un service par défaut, c'est ce que vous voulez.

18voto

gyrolf Points 890

Ce qui fonctionne pour moi:

  • La classe effectuant le travail de service réel s'exécute dans un thread séparé.
  • Ce thread est démarré à partir de la méthode OnStart () et arrêté à partir de OnStop ().
  • La décision entre le mode service et le mode console dépend de Environment.UserInteractive

Exemple de code:

 class MyService : ServiceBase
{
    private static void Main()
    {
        if (Environment.UserInteractive)
        {
            startWorkerThread();
            Console.WriteLine ("======  Press ENTER to stop threads  ======");
            Console.ReadLine();
            stopWorkerThread() ;
            Console.WriteLine ("======  Press ENTER to quit  ======");
            Console.ReadLine();
        }
        else
        {
            Run (this) ;
        }
    }

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

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

16voto

Kramii Points 3203

Comme la Cendre, j'écris tous les réels de traitement de code dans une classe distincte de la bibliothèque de l'assemblée, qui a ensuite été référencé par le service windows exécutable, ainsi que d'une application console.

Cependant, il ya des occasions où il est utile de savoir si la bibliothèque de classe est en cours d'exécution dans le contexte de l'exécutable du service ou de l'application de console. La façon dont je le fais c'est de réfléchir sur la classe de base de l'application d'hébergement. (Désolé pour la VB, mais j'imagine que la suite pourrait être c#-identifiés assez facilement):

Public Class ExecutionContext
    ''' <summary>
    ''' Gets a value indicating whether the application is a windows service.
    ''' </summary>
    ''' <value>
    ''' <c>true</c> if this instance is service; otherwise, <c>false</c>.
    ''' </value>
    Public Shared ReadOnly Property IsService() As Boolean
        Get
            ' Determining whether or not the host application is a service is
            ' an expensive operation (it uses reflection), so we cache the
            ' result of the first call to this method so that we don't have to
            ' recalculate it every call.

            ' If we have not already determined whether or not the application
            ' is running as a service...
            If IsNothing(_isService) Then

                ' Get details of the host assembly.
                Dim entryAssembly As Reflection.Assembly = Reflection.Assembly.GetEntryAssembly

                ' Get the method that was called to enter the host assembly.
                Dim entryPoint As System.Reflection.MethodInfo = entryAssembly.EntryPoint

                ' If the base type of the host assembly inherits from the
                ' "ServiceBase" class, it must be a windows service. We store
                ' the result ready for the next caller of this method.
                _isService = (entryPoint.ReflectedType.BaseType.FullName = "System.ServiceProcess.ServiceBase")

            End If

            ' Return the cached result.
            Return CBool(_isService)
        End Get
    End Property

    Private Shared _isService As Nullable(Of Boolean) = Nothing
#End Region
End Class

10voto

Ash Points 31541

Jonathan, pas exactement la réponse à votre question, mais je viens de terminer l'écriture d'un service de windows, et a également noté la difficulté de débogage et de test.

Résolu: il suffit d'écrire tout réel de traitement de code dans une classe distincte de la bibliothèque de l'assemblée, qui a ensuite été référencé par le service windows exécutable, ainsi qu'une application console et un harnais de test.

Outre les règles de base de la minuterie de logique, tous les plus complexes de traitement qui s'est passé dans l'assemblée commune et pourrait être testé/exécuter sur demande incroyablement facilement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X