Я работаю как служба

В настоящее время я пишу небольшой код начальной загрузки для службы, которую можно запустить в консоли. Это, по сути, сводится к вызову метода OnStart () вместо использования ServiceBase для запуска и остановки службы (потому что она не запускает приложение, если оно не установлено как служба и делает отладку кошмаром).

Прямо сейчас я использую Debugger.IsAttached, чтобы определить, следует ли мне использовать ServiceBase.Run или [service] .OnStart, но я знаю, что это не лучшая идея, потому что некоторые конечные пользователи хотят запустить службу в консоли (чтобы увидеть выход и т.п. в реальном времени).

Любые идеи о том, как я могу определить, запущен ли сервисный контроллер Windows «я», или пользователь начал «меня» в консоли? Очевидно, Environment.IsUserInteractive - это не ответ. Я думал об использовании командной строки, но это кажется «грязным».

Я всегда мог видеть заявление о попытке захвата вокруг ServiceBase.Run, но это кажется грязным. Изменить: попытка catch не работает.

У меня есть решение: поставить его здесь для всех других заинтересованных штабелеров:

    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: Был еще один вопрос в StackOverflow, где у парня были проблемы с Environment.CurrentDirectory, являющийся «C: Windows System32», выглядит так, что это может быть ответ. Я буду проверять сегодня.

c#,.net,windows-services,

42

Ответов: 12


15 принят

Подобно Ash, я пишу весь фактический код обработки в отдельной сборке библиотеки классов, на которую тогда ссылался исполняемый файл службы Windows, а также консольное приложение.

Однако бывают случаи, когда полезно знать, запущена ли библиотека классов в контексте исполняемого файла службы или консольного приложения. То, как я это делаю, - это задуматься о базовом классе хостинга. (Извините за VB, но я предполагаю, что следующее может быть c # -определено довольно легко):

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

25

Другое обходное решение .. так что может работать как WinForm или как служба 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);
}

20

Обычно я использую службу Windows как консольное приложение, которое использует параметр командной строки «-console» для запуска в качестве консоли, иначе он работает как служба. Для отладки вы просто установите параметры командной строки в параметрах проекта в «-console», и вы выключены!

Это делает отладку приятной и легкой и означает, что приложение функционирует как услуга по умолчанию, и это то, что вам нужно.


уя 14

Что работает для меня:

  • Класс, выполняющий фактическую работу службы, работает в отдельном потоке.
  • Этот поток запускается из метода OnStart () и останавливается с OnStop ().
  • Решение между режимом службы и консоли зависит от Environment.UserInteractive

Образец кода:

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

9

Джонатан, не совсем ответ на ваш вопрос, но я только что закончил писать службу Windows, а также отметил трудности с отладкой и тестированием.

Решила его, просто написав весь фактический код обработки в отдельной сборке библиотеки классов, на которую тогда ссылался исполняемый файл службы Windows, а также консольное приложение и тестовый жгут.

Помимо основной таймерной логики, все более сложная обработка происходила в общей сборке и ее можно было протестировать / запустить по требованию невероятно легко.

C # ,. чистые, окна-услуги,
Похожие вопросы