Подтвердить что ты не робот

Обключение службы С# в консольном приложении для ее отладки

Я хочу отладить службу, написанную на С#, и старомодный способ слишком длинный. Я должен остановить службу, запустить приложение, которое использует службу в режиме отладки (Visual studio 2008), запустить службу, подключиться к процессу службы, а затем перейти в приложение Asp.Net для запуска службы.

В основном я работаю в фоновом режиме, ожидая задачи. Веб-приложение вызовет задачу, которую будет обслуживать служба.

Что бы я хотел сделать, это иметь консольное приложение, которое запускает службу, чтобы отладить ее. Есть ли какая-то простая демонстрация, о которой кто-либо знает?

Спасибо. Джек

4b9b3361

Ответ 1

Вы можете сделать что-то подобное в главной точке входа:

static void Main()
{
#if DEBUG
    Service1 s = new Service1();
    s.Init(); // Init() is pretty much any code you would have in OnStart().
#else
    ServiceBase[] ServicesToRun;
    ServicesToRun=new ServiceBase[] 
    { 
        new Service1() 
    };
    ServiceBase.Run(ServicesToRun);
#endif
}

и в обработчике событий OnStart:

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

Ответ 2

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

Таким образом, вы можете легко unit test и отлаживать свой код, не имея дело с головной болью отладки службы, присоединяясь к процессу. Конечно, я бы рекомендовал модульное тестирование, но если вы этого не сделаете, добавьте консольное приложение, которое вызывает ту же точку входа, что и ваш сервис.

Ответ 3

Чтобы избежать использования глобальных определений, я обычно тестирую во время выполнения независимо от того, являюсь ли я сервисом или обычным приложением через свойство Environment.UserInteractive.

    [MTAThread()]
    private static void Main()
    {
        if (!Environment.UserInteractive)
        {
            ServiceBase[] aServicesToRun;

            // More than one NT Service may run within the same process. To add
            // another service to this process, change the following line to
            // create a second service object. For example,
            //
            //   ServicesToRun = New System.ServiceProcess.ServiceBase () {New ServiceMain, New MySecondUserService}
            //
            aServicesToRun = new ServiceBase[] {new ServiceMain()};

            Run(aServicesToRun);
        }
        else
        {
            var oService = new ServiceMain();
            oService.OnStart(null);
        }
   }

Ответ 5

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

Ответ 6

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

 #if DEBUG
    Debugger.Break();
 #endif

или

if(Settings.DebugBreak)
            Debugger.Break();

Я поместил это в метод OnStart компонента службы. Затем вам будет предложено автоматически и подключено к процессу.

Ответ 7

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

Использование Environment.UserInteractive позволяет нам узнать, запущено ли мы как консольное приложение или как служба.

ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
    new MyService()
};

if (!Environment.UserInteractive)
{
    // This is what normally happens when the service is run.
    ServiceBase.Run(ServicesToRun);
}
else
{
    // Here we call the services OnStart via reflection.
    Type type = typeof(ServiceBase);
    BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
    MethodInfo method = type.GetMethod("OnStart", flags);

    foreach (ServiceBase service in ServicesToRun)
    {
        Console.WriteLine("Running " + service.ServiceName + ".OnStart()");
        // Your Main method might not have (string[] args) but you could add that to be able to send arguments in.
        method.Invoke(service, new object[] { args });
    }

    Console.WriteLine("Finished running all OnStart Methods.");

    foreach (ServiceBase service in ServicesToRun)
    {
        Console.WriteLine("Running " + service.ServiceName + ".OnStop()");
        service.Stop();
    }
}

Ответ 8

Вот сообщение о запуске службы Windows в качестве консольного приложения.

Вы также можете просто создать новое консольное приложение, которое ссылается на ту же логику, что и ваша служба, на методы тестирования или настроить тесты единиц в логике ваших услуг

Ответ 9

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

Использование testdriven.net или jetbrains testrunner облегчает процесс.

Ответ 10

Я использую это, чтобы проверить, работает ли мой процесс как служба или нет.

public class ServiceDiagnostics
{
    readonly bool _isUserService;
    readonly bool _isLocalSystem;
    readonly bool _isInteractive;

    public ServiceDiagnostics()
    {
        var wi = WindowsIdentity.GetCurrent();
        var wp = new WindowsPrincipal(wi);

        var serviceSid = new SecurityIdentifier(WellKnownSidType.ServiceSid, null);
        var localSystemSid = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
        var interactiveSid = new SecurityIdentifier(WellKnownSidType.InteractiveSid, null);

        this._isUserService = wp.IsInRole(serviceSid);

        // Neither Interactive or Service was present in the current user token, This implies 
        // that the process is running as a service, most likely running as LocalSystem.
        this._isLocalSystem = wp.IsInRole(localSystemSid);

        // This process has the Interactive SID in its token.  This means that the process is 
        // running as a console process.
        this._isInteractive = wp.IsInRole(interactiveSid);
    }

    public bool IsService
    {
        get { return this.IsUserService || this.IsLocalSystem || !this.IsInteractive; }    
    }

    public bool IsConsole
    {
        get { return !this.IsService; }
    }

    /// <summary>
    /// This process has the Service SID in its token. This means that the process is running 
    /// as a service running in a user account (not local system).
    /// </summary>
    public bool IsUserService
    {
        get { return this._isUserService; }
    }

    /// <summary>
    /// Neither Interactive or Service was present in the current user token, This implies 
    /// that the process is running as a service, most likely running as LocalSystem.
    /// </summary>
    public bool IsLocalSystem
    {
        get { return this._isLocalSystem; }
    }

    /// <summary>
    /// This process has the Interactive SID in its token.  This means that the process is 
    /// running as a console process.
    /// </summary>
    public bool IsInteractive
    {
        get { return this._isInteractive; }
    }
}