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

Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException вообще.

См. также: A хороший список лучших практик

Я бы добавил, очень важно, хорошо использовать модификатор final. Использование "окончательной" модификатор, когда это применимо в Java

Сводка:

  1. Используйте модификатор final для обеспечения хорошей инициализации.
  2. Избегайте возврата null в методы, например, при возврате пустых коллекций.
  3. Использовать аннотации @NotNull и @Nullable
  4. Быстрое завершение работы и использование утверждений, чтобы избежать распространения нулевых объектов через все приложение, когда они не должен быть пустым.
  5. Сначала используйте значения с известным объектом: if("knownObject".equals(unknownObject)
  6. Предпочитают valueOf() поверх toString ().
  7. Используйте null safe StringUtils StringUtils.isEmpty(null).

44
задан Jon Seigel 6 March 2010 в 04:06
поделиться

9 ответов

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

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

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
15
ответ дан Manfred Radlwimmer 26 November 2019 в 21:54
поделиться

Я обычно отмечаю службой Windows как консольное приложение, которое берет параметр командной строки "-консоль" для выполнения как консоль, иначе это работает как услуга. Для отладки Вы просто устанавливаете параметры командной строки в опциях проекта к "-консоль", и Вы прочь!

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

20
ответ дан James 26 November 2019 в 21:54
поделиться

Какие работы для меня:

  • класс, делающий работу практической эксплуатации, работает в отдельном потоке.
  • Этот поток запускается из 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() ;
    }
}
14
ответ дан gyrolf 26 November 2019 в 21:54
поделиться

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

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

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

9
ответ дан Ash 26 November 2019 в 21:54
поделиться

Возможно, проверяя, является ли родитель процесса C:\Windows\system32\services.exe.

3
ответ дан 26 November 2019 в 21:54
поделиться

Единственным путем я нашел для достижения этого, должен проверить, присоединена ли консоль к процессу во-первых путем доступа к какому-либо Консольному свойству объекта (например, Заголовок) в блоке попытки/выгоды.

, Если сервис запускается SCM, нет никакой консоли, и доступ к свойству бросит Систему. IO.IOError.

Однако, так как это чувствует немного совсем как доверие определенной для реализации детали (что, если SCM на некоторых платформах или когда-нибудь решает предоставить консоль процессам, это запускает?), я всегда использую переключатель командной строки (-консоль) в производственных приложениях...

2
ответ дан mdb 26 November 2019 в 21:54
поделиться

Это - что-то вроде саморазъема, но у меня есть немного приложения, которое загрузит Ваши сервисные типы в Вашем приложении через отражение и выполнит их тот путь. Я включаю исходный код, таким образом, Вы могли изменить его немного для отображения стандартного вывода.

Никакие изменения кода не должны были использовать это решение. У меня есть Отладчик. Тип IsAttached решения также, которое достаточно универсально, чтобы использоваться с любым сервисом. Ссылка находится в этой статье: Бегун службы Windows.NET

0
ответ дан Anderson Imes 26 November 2019 в 21:54
поделиться

Я модифицировал ProjectInstaller, чтобы добавить параметр / сервис аргумента командной строки, когда он устанавливается в качестве сервиса:

static class Program
{
    static void Main(string[] args)
    {
        if (Array.Exists(args, delegate(string arg) { return arg == "/install"; }))
        {
            System.Configuration.Install.TransactedInstaller ti = null;
            ti = new System.Configuration.Install.TransactedInstaller();
            ti.Installers.Add(new ProjectInstaller());
            ti.Context = new System.Configuration.Install.InstallContext("", null);
            string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
            ti.Context.Parameters["assemblypath"] = path;
            ti.Install(new System.Collections.Hashtable());
            return;
        }

        if (Array.Exists(args, delegate(string arg) { return arg == "/uninstall"; }))
        {
            System.Configuration.Install.TransactedInstaller ti = null;
            ti = new System.Configuration.Install.TransactedInstaller();
            ti.Installers.Add(new ProjectInstaller());
            ti.Context = new System.Configuration.Install.InstallContext("", null);
            string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
            ti.Context.Parameters["assemblypath"] = path;
            ti.Uninstall(null);
            return;
        }

        if (Array.Exists(args, delegate(string arg) { return arg == "/service"; }))
        {
            ServiceBase[] ServicesToRun;

            ServicesToRun = new ServiceBase[] { new MyService() };
            ServiceBase.Run(ServicesToRun);
        }
        else
        {
            Console.ReadKey();
        }
    }
}

ProjectInstaller.cs затем изменен для переопределения Onbeforeinstall () и onbeforeuninstall ()

[RunInstaller(true)]
public partial class ProjectInstaller : Installer
{
    public ProjectInstaller()
    {
        InitializeComponent();
    }

    protected virtual string AppendPathParameter(string path, string parameter)
    {
        if (path.Length > 0 && path[0] != '"')
        {
            path = "\"" + path + "\"";
        }
        path += " " + parameter;
        return path;
    }

    protected override void OnBeforeInstall(System.Collections.IDictionary savedState)
    {
        Context.Parameters["assemblypath"] = AppendPathParameter(Context.Parameters["assemblypath"], "/service");
        base.OnBeforeInstall(savedState);
    }

    protected override void OnBeforeUninstall(System.Collections.IDictionary savedState)
    {
        Context.Parameters["assemblypath"] = AppendPathParameter(Context.Parameters["assemblypath"], "/service");
        base.OnBeforeUninstall(savedState);
    }
}
9
ответ дан 26 November 2019 в 21:54
поделиться

Другой способ обхода проблемы .. поэтому его можно запускать как 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);
}
27
ответ дан 26 November 2019 в 21:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: