Обертывание службы C # в консольном приложении для его отладки - PullRequest
28 голосов
/ 25 марта 2010

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

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

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

Ответы [ 10 ]

23 голосов
/ 25 марта 2010

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

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();
}
16 голосов
/ 25 марта 2010

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

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

13 голосов
/ 14 февраля 2014

Чтобы избежать использования глобальных определений, я обычно проверяю во время выполнения, являюсь ли я службой или обычным приложением через свойство 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 голосов
/ 25 марта 2010

Возможно, вы захотите проверить TopShelf и в своих приключениях.

http://codebetter.com/blogs/dru.sellers/archive/2009/01/11/topshelf.aspx

http://code.google.com/p/topshelf/

3 голосов
/ 14 января 2016

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

Использование 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();
    }
}
3 голосов
/ 08 марта 2013

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

2 голосов
/ 25 марта 2010

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

 #if DEBUG
    Debugger.Break();
 #endif

или

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

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

1 голос
/ 25 марта 2010

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

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

1 голос
/ 25 марта 2010

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

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

0 голосов
/ 14 сентября 2015

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

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's 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's 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; }
    }
}
...