Programování Windows Services

Tomáš Jecha       24. 1. 2012       C#, VB.NET, Architektura, .NET       5735 zobrazení

Services (služby) jsou jedním ze základních stavebních kamenů programování pro systémy Windows. V článku se budu věnovat jak obecným principům a doporučením, tak konkrétním implementačním postupům.

Co je to Windows Service?

Windows ServicesWindows service (dále jen service, či česky služba) je druh aplikace, která na rozdíl od klasických programů běží na pozadí systému. Důležitý je fakt, že služba nevyžaduje pro svůj běh, aby byl přihlášený uživatel. Z toho důvodu nemají žádné grafické rozhraní a běží bez přímé interakce s uživatelem. Příkladem může být webový server, který očekává příchozí HTTP spojení a obsluhuje požadavky.

Některé služby se spouští se startem systému a zastavují s jeho ukončením. Jiné se spouštějí až na vyžádání nebo jejich start není povolen vůbec, protože jejich běh není aktuálně v systému nutný.

Nezanedbatelné množství služeb využívá sám systém k obsluze zcela základních funkcí. Příkladem může být služba pro zpracování audio výstupu, cache DNS záznamů, firewall, kryptografické služby, plánovač úloh a celá řada dalších. Při doinstalování různých komponent samozřejmě počet služeb může narůstat – například databázový nebo webový server.

Seznam instalovaných služeb

Rychlý přehled služeb nainstalovaných v počítači lze zobrazit pomocí aplikace Windows Task Manager (po stisknutí Ctrl+Alt+Delete nebo spuštěním taskmgr.exe):

Windows Task Manager - Services

Zde podle sloupce “Status” vidíme, zda konkrétní služby běží (Running) nebo jsou zastaveny (Stopped).

Pokud však chcete provádět i konfiguraci, využijete konzoli pro správu služeb přístupnou přes:

Ovládací panely > Nástroje pro správu > Služby

Nebo spuštěním:

services.msc

Konzole obsahuje seznam služeb s možností jejich zastavování, spouštění, restartování, či konfigurací:

Services

Poznámka: Za určitých okolností lze zvýšit výkon (či snížit paměťovou náročnost) systému vypínáním nepotřebných služeb. Toto doporučuji pouze v případech, kdy přesně víte, k čemu služba slouží a máte jistotu, že tím neovlivníte jinou část systému.

Co to je služba?

Windows služba je fyzicky exe soubor, který však není možné přímo spustit. Obvykle po manuálním spuštění vypíše hlášku, že se jedná o službu a nelze jej spustit přímo, či se ihned ukončí.

Vnitřně je služba postavená tak, aby s ní dokázal komunikovat systém. Konkrétně, aby dokázal službě předávat příkazy. Těmi nejdůležitějšími jsou “Start” a “Stop” pro spuštění a zastavení. Případně “Pause” a “Continue”, pokud služba podporuje dočasné pozastavení.

Velkým rozdílem oproti běžným aplikacím je způsob vývoje. Ve službě neběží hlavní vlákno, pouze dostáváme signály "spustit službu”, “zastavit službu” a podobné další. Je jen na nás jak při těchto událostech budeme reagovat a jaké části našeho systému spustíme.

Aby bylo službu možné vidět v seznamu služeb, měnit jí konfiguraci a samozřejmě spouštět, je potřeba provést její registraci do systému. O tom budu psát dále.

Co jsou to procesy “svchost.exe”?

Při zobrazení běžících procesů si můžete všimnout, že v systému žije řada instancí služby “svchost.exe” – zkratka pro Service host. Tato aplikace se stará o hostování služeb, které nejsou ve formátu exe, ale dll a nelze je tak zaregistrovat jako službu přímo. Jinými slovy je “svchost.exe” pouze běhové prostředí pro určitý typ služeb ve formátu dll.

Pokud tedy máme s tímto procesem problémy (padá, je na 100% vytížený atp.), většinou se nejedná o problém se “svchost.exe” ale se službou, kterou hostuje.

svchost.exe processes

Těchto pár vět o “svchost.exe” je pouze informativních. V tomto článku se totiž budu věnovat psaní běžné služby (ve formátu exe) a nebudeme proto nijak tento proces potřebovat.

Windows Service v C#

Windows služby lze velmi pohodlně psát v prostředí .NET Framework. Následující řádky popisují, jak službu naprogramovat a zaregistrovat do systému.

Založení projektu

Založte si nový projekt typu Windows Service. Využít můžete jak C#, tak Visual Basic .NET. Používám Visual Studio 2010. Téměř identicky však vše probíhá i pod Visual Studio 2008. Projekt jsem si pojmenovat “Jecha.Samples.MyWindowsService”. Výstupem tedy bude ”Jecha.Samples.MyWindowsService.exe”.

Windows Service - New Project

V projektu se založí 2 důležité soubory:

  • Program – řeší spouštění služby
  • Service1 – implementace chování služby

Pokud aplikaci spustíme, zobrazí se hláška o tom, že nelze službu spustit přímo – je potřeba ji nejprve zaregistrovat:

Cannot start service from the command line or a debugger. A Windows Service must first be installed (using installutil.exe) and then started with the ServerExplorer, Windows Services Administrative tool or the NET START command.

Toto zajistí kód v třídě Program. Díky tomu dokáže systém Windows zajistit komunikaci s třídou Service1 obsahující konkrétní chování služby při instalaci a jejím spuštění. Pokud však tento kód odstraníme a nahradíme ho například za kód pro zobrazení formuláře, stane se ze služby běžná Windows aplikace.

Nyní se podívejme na kód služby do souboru Service1. Po rozkliknutí se zobrazí návrhář s touto hláškou:

To add componets to your class, drag them from the Toolbox and use the Properties window to set their properties. To create methods and events for your class, click here to switch to code view.

My však návrhář nebudeme nijak potřebovat a proto zvolíme “Click here to switch to code view”. Existuje malý trik, kterým zamezíte zobrazování návrháře, který je v případě služeb zcela zbytečný. Vložte nad třídu služby tento atribut:

[System.ComponentModel.DesignerCategory("")]

Návrhář s neužitečnou hláškou se pak při otevřením služby již nebude zobrazovat. Někdy však chvilku trvá, než Visual Studio atribut vezme v potaz. Občas je potřeba celé Visual Studio zavřít a zase otevřít.

Celý kód třídy pak bude:

[System.ComponentModel.DesignerCategory("")]
public partial class Service1 : ServiceBase
{
    public Service1()
    {
        InitializeComponent();
    }

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

    protected override void OnStop()
    {
    }
}

V této třídě nás zajímají především metody “OnStart”, která se vyvolá při spuštění služby a “OnStop”, která se vyvolá při zastavování.

Akce při spouštění a zastavování služby

Délka spouštění a zastavování služby odpovídá době, kterou se stráví prováděním OnStart a OnStop metod. Jinak řečeno, pokud bude metoda OnStart trvat nekonečnou dobu, služba se nikdy nespustí. Účel těchto metod je tedy službu inicializovat a nastartovat a měl by trvat co nejkratší dobu. Zároveň úspěšné provedení těchto metod značí úspěšnost startu služby. Například pokud vyvoláte při spouštění v metodě OnStart výjimku, systém oznámí chybu při spouštění a proces služby se ihned ukončuje.

Pro demonstraci implementujeme jednoduchý časovač, který se spustí se startem služby a ukončí jejím uzavřením. Každou vteřinu přečteme vytížení procesoru a zapíšeme jej do souboru. V kódu jsem použil následující pevnou cestu:

c:\temp\cpu.txt

Poznámka: Vytvořte si složku “c:\temp” nebo změňte cestu k souboru. Pokud tato složka nebude existovat, výsledek se nebude nikam zapisovat.

Zde je kód celé služby:

    [System.ComponentModel.DesignerCategory("")]
    public partial class Service1 : ServiceBase
    {
        public Service1()
        {
            InitializeComponent();
        }

        PerformanceCounter counter;
        System.Timers.Timer timer = new System.Timers.Timer();
        string fileName;
        bool isStopping;
        
        protected override void OnStart(string[] args)
        {
            // vytvořit performance counter pro zjištění zatížení procesoru
            counter = new PerformanceCounter();
            counter.CategoryName = "Processor";
            counter.CounterName = "% Processor Time";
            counter.InstanceName = "_Total";
            
            // cesta, kam se budou data ukládat
            fileName = @"c:\temp\cpu.txt";

            // vytvořit timer, který bude každou vteřinu data zapisovat
            timer.Interval = 1000;
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
            timer.AutoReset = false;
            timer.Start();
        }

        protected override void OnStop()
        {
            // oznámit zastavení služby
            isStopping = true;
        }

        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            // zastavuje se služba? pak neprovádět další krok
            if (isStopping)
                return;

            try
            {
                // naformátovat hlášku, která bude do logu zapsána
                string message = 
                    string.Format("{0:HH:mm:ss} - CPU usage {1}%", 
                    DateTime.Now, 
                    counter.NextValue());

                // zapsat hlášku
                System.IO.File.AppendAllText(fileName, message + Environment.NewLine);
            }
            finally
            {
                // po provedení kroku znovu spustit časovač
                timer.Start();
            }
        }
    }

Poznámka: Můžete si všimnout nastavené vlastnosti AutoReset = false u časovače. To zajištuje, že se po vykonání události Elapsed časovač zastaví. Já jej znovu spouštím až po dokončení této události v bloku finally. Tím docílíme, že se časovač bude spouštět až po ukončení předchozího zápisu a nikdy se nemůže vykonávat více zápisů paralelně. Časovač by bez této úpravy totiž po uplynutí intervalu vytvářel nové vlákno i pokud to předchozí ještě nedoběhlo.

Nyní máme připravenou službu a čeká nás její registrace do systému.

Registrace služby do systému

Při registraci potřebujeme definovat primárně následující nastavení:

  • Jméno služby – ideálně bez diakritiky (diakritika může být problematické na starších systémech) – unikátní název služby
  • Zobrazované jméno služby – jméno služby, které se zobrazí v seznamu služeb (může být s diakritikou), nepoužívá se k identifikaci služby, je pouze informativní
  • Popis služby – informativní popis služby (může být delší text) – zobrazuje se v konzoli služeb při označení konkrétní služby v  levém panelu nebo při zobrazení vlastností služby
  • Účet, pod kterým se služba spouští – ačkoliv služby nevyžadují pro svůj běh přihlášeného uživatele (plochu), je nutné je spustit s určitou identitou – pod určitým uživatelem.
  • Způsob spouštění – volíme, zda se služba spustí ihned po spuštění systému (Automatic), na vyžádání (Manual) a nebo je spouštění dočasně zakázáno (Disabled).

Dále lze nadefinovat:

  • Závislosti – volitelně lze předat pole obsahující seznam jmen služeb, které jsou vyžadované pro spuštění
  • Odložený start – služba se bude spouštět až po spuštění všech služeb, které odložený start nemají nastavený. Tato volba je defaultně vypnuta.

Registraci můžete provést několika způsoby. Já osobně preferuji vytvoření tzv. instalační třídy. Do ukázkového projektu přidejte třídu Service1Installer:

    [RunInstaller(true)]
    [System.ComponentModel.DesignerCategory("")]
    public class Service1Installer: Installer
    {
        public Service1Installer()
        {
            ServiceProcessInstaller serviceProcessInstaller =
                               new ServiceProcessInstaller();
            ServiceInstaller serviceInstaller = new ServiceInstaller();

            // spouštění pod účtem LocalSystem
            serviceProcessInstaller.Account = ServiceAccount.LocalSystem;
            serviceProcessInstaller.Username = null;
            serviceProcessInstaller.Password = null;

            // unikátní název, název pro zobrazení a popis
            serviceInstaller.ServiceName = "MyWindowsService";
            serviceInstaller.DisplayName = "My service";
            serviceInstaller.Description = "Popis služby";

            // způsob spouštění
            serviceInstaller.StartType = ServiceStartMode.Automatic;
            
            this.Installers.Add(serviceProcessInstaller);
            this.Installers.Add(serviceInstaller);
        }
    }

Pravděpodobně bude potřeba přidat referenci na assembly: System.Configuration.Install

K registraci služby z naší assembly využijeme utilitu “installutil.exe” (dodaná s .NET Frameworkem). Ta po spuštění vyhledá třídy dědící z bázové třídy Installer a dekorované atributem [RunInstaller(true)] a provede jejich vykonání. V našem případě to bude právě Service1Installer třída. V té najde popis pro registraci služby do systému.

Všimněte si, že nikde v instalační třídě neuvádíme odkaž na konkrétní třídu služby (Service1) – registruje se totiž celá assembly. O spuštění konkrétní služby se pak postará spouštěcí kód uvnitř třídy Program.

Ještě než provedeme samotnou registraci, rád bych se věnoval nastavení účtu, pod kterým se služba bude spouštět.

Účet služby

Při volbě účtu (vlastnost Account), pod kterým služba poběží si volíte buď jeden ze 3 pevně definovaných systémových účtů nebo libovolný účet pomocí jména a hesla:

  • LocalSystem – účet s plným oprávněním – de facto administrátor. Není potřeba vyplňovat jméno a heslo. Toto je defaultní nastavení.
  • NetworkService – účet s omezeným oprávněním. Není potřeba vyplňovat jméno a heslo.
  • LocalService – účet s omezeným oprávněním podobný jako NetworkService. Rozdíl je v komunikaci s ostatními servery, kde využívá anonymní přihlašovací údaje. Není potřeba vyplňovat jméno a heslo.
  • User – libovolný účet podle vyplněného jména a hesla. Je potřeba vyplnit vlastnosti Username a Password.

Registrace do systému pomocí InstallUtil.exe

K registraci do systému budeme potřebovat administrátorská oprávnění. Spusťte si proto v administrátorském režimu příkazový řádek Visual Studia – “Visual Studio Command Prompt (2010)”.

Poznámka: Můžete využít i klasickou příkazovou řádku, pouze se budete muset odkazovat na utilitu “installutil.exe” plnou cestou. Například v mém případě: “C:\Windows\Microsoft.NET\Framework\v4.0.30319\installutil.exe”.

Nyní spusťte příkaz pro registraci služby (patřičně upravte cestu k projektu):

installutil.exe c:\Dev\MyWindowsService\bin\Debug\Jecha.Samples.MyWindowsService.exe

Pro případné odebrání služby pak přidáme navíc parametr “/u”. Zatím ji ale neodebírejte.

installutil.exe /u c:\Dev\MyWindowsService\bin\Debug\Jecha.Samples.MyWindowsService.exe

Pokud se vše povedlo správně, služba by se měla zobrazit v seznamu konzole služeb systému Windows:

Services - My service

Nejčastější problémy

  • Chybová hláška při instalaci služby: “System.Security.SecurityException: The source was not found, but some or all event logs could not be searched.  Inaccessible logs: Security.” – příkazová řádka nebyla spuštěna s administrátorským oprávněním.
  • Chybová hláška při instalaci služby: “System.BadImageFormatException: Could not load file or assembly XYZ – používáte pravděpodobně verzi “installutil.exe” pro starší verzi .NET Frameworku.
  • Služba běží, ale nezapisuje výsledek do souboru. Pravděpodobně služba nemá oprávnění zapisovat do složky, případně složka vůbec neexistuje. Zkontrolujte cestu, která v kódu služby určuje, kam se bude soubor zapisovat.

Spuštění služby

Službu se pokuste pomocí konzole spustit. Nechte ji 15 vteřin běžen a následně ji ukončete.

Zastavování služby:

Ukončování služby

Pokud jste vše provedli správně, soubor s výsledky bude obsahovat výpis zatížení procesoru za dobu, kdy služba byla v provozu. Například:

13:29:08 - CPU usage 6,447178%
13:29:09 - CPU usage 12,12361%
13:29:10 - CPU usage 11,93132%
13:29:11 - CPU usage 0%
13:29:12 - CPU usage 0%
13:29:13 - CPU usage 21,66084%
13:29:14 - CPU usage 0%
13:29:15 - CPU usage 1,547676%
13:29:16 - CPU usage 6,639277%
13:29:17 - CPU usage 10,30455%
13:29:18 - CPU usage 11,24968%
13:29:19 - CPU usage 5,585763%
13:29:20 - CPU usage 0%
13:29:21 - CPU usage 5,877517%
13:29:22 - CPU usage 4,334079%
13:29:23 - CPU usage 3,47057%

Nezapomeňte na konci testování službu zase odinstalovat. Pokud to neuděláte, služba se automaticky po restartu počítače spustí a bude každou vteřinu zapisovat na disk do příslušného souboru.

Tipy při vývoji

Pozastavení služby

Službu je možné zastavovat a spouštět. Po ukončení služby se instance procesu zcela ukončuje. Pokud chcete dovolit možnost dočasného pozastavování služby, stačí v konstruktoru služby (Service1) pozastavování povolit:

this.CanPauseAndContinue = true;

Dále naimplementujete metody “OnPause” a “OnContinue” a je čistě na vás, jak se v případě vyvolání těchto událostí zachováte:

protected override void OnPause()
{
    // příkaz při pozastavení
}

protected override void OnContinue()
{
    // příkaz při opětovném spuštění
}

Služba, která je takto nastavená bude mít v konzoli služeb navíc možnost “Pause” pro pozastavení. Většinou ale tuto možnost implementovat nemusíte a je, až na speciální případy, poměrně zbytečná.

Dodatečné nastavování

V konzoli služeb můžete z kontextového menu na příslušnou službou zvolit “Properties”. Zobrazí se dialog s konfigurací služby:

Service properties

Na tomto dialogu můžete službu spouštět, zastavovat, měnit způsob spouštění, doplnit parametry spuštění, prohlédnout si její závislosti na jiných službách, změnit účet spouštění a případně nastavit možnosti zotavení (pokud se nepovede službu spustit, vyzkoušej to za chvilku znovu atp.). Přes tento dialog nelze službu odregistrovat ze systému, lze ji maximálně zakázat.

Logování

Logování je u služeb nesmírně důležité. Pokud vznikne jakákoliv výjimka, logování ji pomůže odhalit. Bez logování se o chybě při spouštění služby dozvíte tak maximálně, že vznikla. A o chybě v průběhu se nedozvíte dokonce vůbec. Zkuste si například v ukázkovém projektu vyvolat výjimku uvnitř události časovače. Chyba vznikne, ale služba se kvůli ní neukončí a “spolkne ji”. Logování je však nad rámec tohoto článku.

Vyžádání delšího času na spuštění

Vzhledem k tomu, že systém čeká na spuštění a ukončení služby, snažíme se o co nejrychlejší nastartování a zastavení. Pokud nejsme schopni start/stop zaručit bezpečně do 20ti vteřin (orientační hodnota), můžeme si na spouštění vyžádat více času příkazem:

// vyžádání dalších 60 vteřin na spouštění / zastavování
RequestAdditionalTime(60 * 1000);

Debugování služby

Na rozdíl od běžné aplikace je ladění služeb trochu komplikovanější. Službu totiž nespouštíte přímo vy, ale systém. Jaké máme tedy možnosti?

První možností je připojit debugger do procesu běžící služby. Toto je postup:

  1. Ujistěte se, že služba běží.
  2. Spusťte Visual Studio s projektem služby v režimu adminsitrátora (pokud to neuděláte, k službě se nepřipojíte).
  3. Proveďte volbu Debug > Attach to process…
  4. V zobrazeném seznamu zaškrtněte možnosti Show processes from all users i Show processes in all sessions a zvolte Refresh. Vyhledejte instanci služby:
    Attach to process... - Visual Studio
  5. Pokud máte označenou instanci běžící služby, zvolte Attach.
  6. Nyní můžete plně debugovat. Vložte do příslušné části kódu breakpointy a vyčkejte na jejich zasažení.

Tento způsob má jasnou výhodu – ladíte přímo službu hostovanou systémem a pracujete tak přímo v prostředí, kde služba následně poběží. Existují ale i nevýhody – hlavní problém je v tom, že se špatně ladí kód při spouštění služby. Než stihnete debugger připojit, pravděpodobně služba již bude spuštěna. To lze však vyřešit malým trikem – vložte do metody OnStart příkaz pro čekání Thread.Sleep(čas) (například minutu) a to vám dá dostatek času na připojení debuggeru a nastavení breakpointu. Další nevýhodou je nutnost spouštění pod administrátorským oprávněním a potřeba při každém spouštění znovu provést připojení debuggeru.

Druhou možností je přímo zavolat kódu startu služby, pokud spustíte službu přímo z příkazové řádky. Například já používám jako odlišení testovacího spuštění parametr “debug”. Kód v třídě Program pak může vypadat takto:

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main(params string[] args)
    {
        if (string.Equals(args.FirstOrDefault(), "debug", StringComparison.OrdinalIgnoreCase))
        {
            var service = new Service1();
            service.StartDebug();
            System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
        }

        ServiceBase[] ServicesToRun;
        ServicesToRun = new ServiceBase[] 
		{ 
			new Service1() 
		};
        ServiceBase.Run(ServicesToRun);
    }
}

Tento kód kontroluje, zda spouštíme aplikaci s parametrem “debug” a pokud ano, vytvoří instanci služby a vyvolá metodu na spuštění. Následně čeká nekonečnou dobu, díky které se aplikace ihned neukončí a my můžeme ladit. Bez uvedení parametru se služba chová jako doposud.

Aby mohlo toto řešení fungovat, je ještě potřeba vystavit metodu StartDebug pro třídu služby Service1. Metoda OnStart, kterou chceme volat, totiž není veřejná a nemůžeme ji zavolat přímo ze spouštěcí třídy Program.

internal void StartDebug()
{
    this.OnStart(null);
}

Nyní stačí pouze nastavit při ladění spouštění s parametrem “debug” ve vlastnostech projektu:

Project settings

Toto řešení je výhodné ve snadnosti použití. Program prostě spustíte přímo z Visual Studia s parametrem a můžete ladit. Nevýhodou je, že spouštění služby jen simulujeme. Přitom reálné spouštění služby systémem je trochu jiné a běží v jiném prostředí. Například systém ji přiděluje jiná oprávnění a nedává k dispozici použití uživatelského prostředí.

Závěr

Psaní Windows služeb patří mezi základní techniky programování pro systém Windows, ačkoliv k této možnosti saháme většinou až při náročnějších úkolech. Hodí se například jako způsob hostování WCF služeb, vlastního plánovače úloh, či modulu komunikujícím s hardwarem. Doufám, že tento článek dokázal osvětlit alespoň základy programování a práce s Windows Services.

 

hodnocení článku

1 bodů / 1 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Mohlo by vás také zajímat

Windows Presentation Foundation (WPF) - díl 4.: Architektura a objektový model WPF

Na jaké kompromisy museli architekti WPF frameworku přistoupit, aby nabídli vývojářům pohodlný vývoj ve vyšších programovacích jazycích a zároveň odpovídající výkon výsledného uživatelského prostředí? Tento článek se věnuje architektuře WPF frameworku.

Windows Presentation Foundation (WPF) - díl 8.: Canvas, StackPanel, WrapPanel

Článek se věnuje dalším široce používaným pozicovacím komponentám WPF. Canvas pro absolutní pozicování, StackPanel pro skládání elementů vedle sebe nebo nad sebe a WrapPanel zalamující jejich tok do řádků nebo sloupců.

Co je to .NET Framework 4.5?

V tomto článku se snažím nastínit rozdíl mezi .NET 4 a .NET 4.5 z pohledu zpětné kompatibility.

 

 

Nový příspěvek

 

Detail

Diky za super tutorial, jenom jsem si vsimla takoveho preklepu v nasledujicim odstavci:

"Všimněte si, že nikde v instalační třídě neuvádíme odkaž na konkrétní třídu služby (Service1) – registruje se totiž celá assembly. O spuštění konkrétní služby se pak postará spouštěcí kód uvnitř třídy Program."

Pravdepodobne to mel byt odkaz ^_^. (Komentare pisu bez diakritiky, takze mne by se to asi nestalo :D)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Detail

Diky za super tutorial, jenom jsem si vsimla takoveho preklepu v nasledujicim odstavci:

"Všimněte si, že nikde v instalační třídě neuvádíme odkaž na konkrétní třídu služby (Service1) – registruje se totiž celá assembly. O spuštění konkrétní služby se pak postará spouštěcí kód uvnitř třídy Program."

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Programování Windows service aplikací

Dobrý den.

Předem děkuji za článek, jsem mírně pokročilý .NET programátor (stále ještě student). V současné době mám za úkol vytvořit pro jednu firmu Windows service, která se jednou denně připojí a vykonná činost uložení dat do databáze. Součastí zadání je možnost nastavení v kterou hodinu bude služba data stahovat, resp ukládat do databáze.

Bylo by jednoduché to nastavit pomocí timeru, např. Vy jste ukládal co 1s vytížení CPU, obdobně jde nastavit pomocí DateTime.No.Hour hodinu a změnit interval...

Má otázka zní: Jde nějak udělat aby si to mohl uživatel nastavit aniž by zasahoval do kodu (tzn. když už je služba nainstalována) ?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dobrý den,

nejjednodušší je uložit nastavení například do App.config souboru a z něj pak při startu tuto hodnotu číst.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Diskuse: Programování Windows service aplikací

Zdravím, super článek, moc děkuji.

Rád bych se zeptal, zda by šlo nastínit jak registraci služby zautomatizovat v nějakém instalátoru. Myslím tím v rámci instalace nějakého většího programu zavádějící i službu, abych nemusel registrovat zvlášť službu přes cmd.

Děkuji.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Možné to je a velmi snadno. Uvažuji, že bych o tom napsal krátké pokračování. Program "installutil.exe" je totiž klasická .NET konzolová aplikace, která pro instalaci volá běžný .NET kód.

Například jsem nalezl kód, který projde assembly a provede jednotlivé kroky instalátoru stejně jako installutil (kód jsem nezkoušel):

        static void Install(bool undo, string[] args) 
        { 
            try 
            { 
                Console.WriteLine(undo ? "uninstalling" : 
"installing"); 
                using (AssemblyInstaller inst = new 
AssemblyInstaller(typeof(Program).Assembly, args)) 
                { 
                    IDictionary state = new Hashtable(); 
                    inst.UseNewContext = true; 
                    try 
                    { 
                        if (undo) 
                        { 
                            inst.Uninstall(state); 
                        } 
                        else 
                        { 
                            inst.Install(state); 
                            inst.Commit(state); 
                        } 
                    } 
                    catch 
                    { 
                        try 
                        { 
                            inst.Rollback(state); 
                        } 
                        catch { } 
                        throw; 
                    } 
                } 
            } 
            catch (Exception ex) 
            { 
                Console.Error.WriteLine(ex.Message); 
            } 
        } 

Doporučuji ale pomocí například .NET Reflectoru projít kód installutil.exe a prohlédnout si, jak na to. Ten dělá prakticky to samé, jen to obalí logováním.

Více o třídě, která samotnou instalaci provede: http://msdn.microsoft.com/en-us/library/...

Ideálně lze doplnit do vstupní procedury služby detekci textových přepínačů, které provedou instalaci/odinstalaci služby. A z instalátoru pak stačí zavolat například "MyService.exe install".

nahlásit spamnahlásit spam 3 / 3 odpovědětodpovědět

Děkuji za článek... Moc mi pomohl...

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Programování Windows service aplikací

článek je dobrý, ale protože mi něco nešlo, tak jsem hledal hledat a našel odpověď takže doplňuji pro úplné začátečníky :

You're missing a reference to System.Configuration.Install.dll. In your project, you can right click the references folder, choose Add References, and then select this library to add a reference to your solution. You should then be able to build successfully.

neboli když Vám nelze přidat using System.Configuration.Install tak pouzijte výse uvedený návod. funguje.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

To jste musel přehlédnout. Viz můj článek:

Pravděpodobně bude potřeba přidat referenci na assembly: System.Configuration.Install

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Programování Windows service aplikací

Díky za přehledně napsaný článek. Na internetu lze nalézt jeho "kamarády" na stejné téma, ale 1. nejsou česky a 2. nejsou tak přehledné a doplněné skvělými vysvětlivkami jako ten Váš.

Váš článek plní účel beze zbytku a ze šťouralů si nic nedělejte.

M. Bartoš

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Diskuse: Programování Windows service aplikací

Taktéž se připojuji s díky za pěkný a srozumitelný článek.

Velice cenné jsou především doplňující vysvětlivky k programu. Skoro bych řekl, že jsou cennější než vlastní prográmek, protože právě díky nim se problematika stává pochopitelnější :-)

Jenom pro informaci - postup se službou jsem úspěšně vyzkoušel ve Visual C# 2008

nahlásit spamnahlásit spam 0 odpovědětodpovědět

ale spolehnout se na to, že file "temp" existuje a notabene ho natvrdo předpokládat v oddíle systému - kam samozřejmě, podobně jako tuny dalších informací samozřejmě nepatří - je naprosto neprofesiální.

nahlásit spamnahlásit spam -3 / 3 odpovědětodpovědět

To je naprosto zcestná připomínka. Řešení cest pro ukládání není absolutně v rámci tohoto článku. A to stejně jako celá řada dalších věcí, které se kvůli jednoduchosti příkladu neřeší. Podle vašeho tvrzení by byla polovina referenčních kódů "neprofesionální", protože se logicky zaměřuje na řešení konkrétního problému a ne ošetřování věcí okolo.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Pak ale, doufám že mluvím s odborníkem, je ten příklad špatný a zavádějící. Umístění souborů a složek, které na oddílu OS naprosto nemají co dělat, je neprofesionální. Nepostarání se o to, zda vůbec to lze a pouze a jen to předpokládat, je vysloveně špatné.

nahlásit spamnahlásit spam -2 / 2 odpovědětodpovědět

Budu se opakovat - toto není příklad věnující se problematice ukládání souborů na disk. Z pohledu ošetření zápisu, adresáře pro uložení i způsobu uložení to není rozhodně vhodné řešení. Funkce pro zápis do souboru jsou zde pouze a jen ilustrativní.

Vezměte si to takto - kdybych chtěl, aby byl kód, jak jste sám napsal "profesionální", já to raději označím jako "vhodný do produkčního prostředí", pak by byl minimálně 5x delší. Informativnost z pohledu tématu článku by se snížila, protože by kód okolo matl a čas na napsání článku by se zvýšil.

To, že není vhodné mít pevný odkaz do souboru na nevhodné místo z pohledu běžných aplikací snad není potřeba vůbec diskutovat. A nečekal jsem, že někdo vypíchne ze článku takovou věc - protože mnohem důležitějších problémů se zápisem je tam více, ale to prostě není v rámci tohoto článku.

nahlásit spamnahlásit spam 3 / 3 odpovědětodpovědět

Diskuse: Programování Windows service aplikací

Taktéž se připojuji s díky za pěkný a srozumitelný článek.

Velice cenné jsou především doplňující vysvětlivky k programu. Skoro bych řekl, že jsou cennější než vlastní prográmek, protože právě díky nim se problematika stává pochopitelnější :-)

Jenom pro informaci - postup se službou jsem úspěšně vyzkoušel ve Visual C# 2008

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Programování Windows service aplikací

Dobrý den,

chtěl bych poděkovat za zajímavý článek, honě mi pomohl.

Chtěl bych se ale zeptat jak docílit jednoho výsledného .exe souboru. Jak v debug tak i v release adresáři mám vždy dva výsledné .exe soubory. Jeden jako nazevProjektu.exe a druhý jako nazevProjektu.vshost.exe.

Používám Express verzi studia 2010.

Za případné nakopnutí správným směrem předem děkuji.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Dobrý den,

výsledkem je pouze jeden spustitelný soubor - nazevProjektu.exe.

Ten druhý nazevProjektu.vshost.exe je zde pouze jako pomocný program pro hostování při debugování ve Visual Studiu a pro běžný běh není nijak potřeba. Pokud tedy chcete aplikaci někam nasadit, je zcela zbytečné tento vshost soubor kopírovat také.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Aha, děkuji za vysvětlení.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Programování Windows service aplikací

Jen bych poznamenal, že návrhář služby není nutné nuceně schovávat, protože pomocí něj se dají jednoduše vizuálně naklikat všechny důležité vlastnosti, které by se mohly při nastavování pomocí kódu opomenout. To samé platí i pro instalační třídu, kterou lze v návrháři přidat pomocí Add Installer a následně jen naklikat vlastnosti.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pomocí návrháře naklikáte ani ne 10 vlastností, které můžete úplně stejně nastavit v kódu pomocí this.JménoVlastnosti. Navíc většina z nich se přímo pojí na kód uvnitř služby a proto jsem názoru, že zde je návrhář zbytečný. Ale nutné to není. Jen mě osobně vadí se přes něj pokaždé proklikávat.

U komponenty pro instalaci služeb to chápu, ale jde asi o zvyk. Raději ten kód vidím před sebou.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Já zase raději vidím seznam všeho důležitého, co jde nastavovat. Pokud se to nastaví v režimu návrhu, již není potřeba to znovu nastavovat v kódu a veškerou špinavou práci udělá Visual Studio.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Diskuse: Programování Windows service aplikací

Díky za skvělý článek, toto jsou přesně věci, na co by se měli psát články, v češtině je jich málo, ale jsou zajímavé, ještě jednou díky za článek :-)

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback