Programování služeb ve Windows - 3.díl

C# .NET Pro pokročilé Programování služeb ve Windows - 3.díl

Jak ladit služby?

Odstraňování problémů je u služeb jiné než u ostatních aplikací. Jako nejlepší postup se ukazuje nejprve vytvořit sestavení s požadovanou funkčností a testovací klientskou aplikaci ještě před zavedením služby.

V této fázi lze bezpečně ladit a odstraňovat chyby. Po odladění můžeme naši aplikaci vložit do služby. Veškeré chyby ve službě se nezobrazují v okně se zprávou, ale zapisují se do protokolu událostí. Službu nemůžeme spustit v ladícím programu, můžeme se připojit ke spuštěnému procesu služby. Postupujeme tak, že otevřeme ve VS zdrojový kód služby, nastavíme zarážky a připojíme se k běžícímu procesu služby.

Z nabídky Ladění vybereme Připojit se k procesu (Attach to Process) viz obrázek.

Pripojení k procesu

Musíme ve vlastnostech projektu označit tato políčka:

Service Vlastnosti

Jiný další způsob ladění je uveden na odkazu: Programovani-Windows-Services

Zde cituji z uvedeného článku.

Druhou možností je přímo zavolat kód 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:

Services_attach 2

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í. (konec citátu)

Další možnosti jsou popsány v MSDN, kdo má zájem, může si je nastudovat.

Zavedený způsob ladění a testování služba

Podle mého je nejlepší způsob vytvoření klienta a serveru a tyto odladit klasickým způsobem a pak implementovat do služby. Je to patrně nejrychlejší způsob.

Tento způsob jsem nevymyslel, jeho strategii nastínilo mnoho autorů přede mnou a já jsem tento způsob také převzal. Není nutné mít práva administrátora pro pohodlné ladění a testování.

  • Vytvoříme projekt serveru (co nám bude naše služba vykonávat)
  • Okenní jednoduchou aplikaci pro spuštění serveru
  • Okenní aplikaci pro sledování činnosti serveru nemusíme přepínat do "Prohlížeče událostí"
  • Jednoduchého klienta pro komunikaci

Zde bych chtěl upozornit, že vnitřní funkce se budou mírně lišit podle zaměření serveru a výměny dat.

Server naší služby

Funkčnost serveru bude otevřít soubor, načíst náhodně data ze souboru a tato náhodná data poslat na klienta pomocí IP. Události budeme zapisovat v systémovém logu, můžeme trastovat a používat čítače výkonu.

Přidáme do našeho projektu další projekt, který pojmenujeme na příklad Server, na jménu nezáleží.
VS - soubor - přidat - nový projekt - Windows - knihovna tříd (název projektu Server).
Visual studio nám neumožňuje vytvořit (.dll) projekt přímo z komponenty, proto je jednodušší toto obejít. Nyní přidáme do našeho nového projektu komponentu, nazveme ji MujServer1 a pokud nebudeme potřebovat pro velkou složitost třídu, tak tuto předchozí třídu odstraníme.

Náš kód serveru bude vypadat:

public partial class Server1 : Component
{
        public Server1(IContainer container)
        {
            container.Add(this);
            InitializeComponent();
        }
}

Postupně doplním a vysvětlím kód. Provedeme kompilaci pouze tohoto projektu pro získání dll knihovny.

Projekt test serveru

Další projekt přidaný do naší aplikace bude jednoduchá konzolová aplikace, která bude simulovat start a ukončení služby. Název může být libovolný. VS - soubor - přidat - nový projekt - konzolová aplikace , pojmenujeme TestServeru.

using System;
namespace WindowsService1
{
        class Program
        {
                static void Main(string[] args)
                {
                        Server1 qs = new Server1(@"C:\Temp\quotes.txt", 4567); //1 , 2 , 3
                        qs.Start();
                        Console.WriteLine("Pro ukončení stiskněte klávesu Enter.");
                        Console.ReadLine();
                        qs.Stop();
                }
        }
}
  1. @"C:\Temp\quo­tes.txt" je umístění našeho testovacího souboru, musí existovat.
  2. Název souboru musí být plná cesta, nesmí se používat dvojitá lomítka!
  3. Port bude stejný pro veškeré instalace.
  4. Přidáme odkaz na náš server. (knihovna MujServer.dll)

Zde nebudeme již nic měnit, vše je jasné.

Projekt MujServerEven­tListener

Tento projekt bude sledovat veškeré naše události, jak při ladění serveru mimo instalaci tak i při celkovém ladění, když bude začleněn do našeho instalačního projektu. Toto je pohodlné, přepínání do logování je nepraktické a zdlouhavé. Události se zapisují tak jak jsou vyvolány.
Vs - přidat - nový projekt - Formulářová aplikace Windows (název MujServerEven­tListener)
Kód této aplikace je také velmi jednoduchý:

using System;
using System.Windows.Forms;

namespace WindowsService1
{
    partial class MujServerEventListener : Form
    {
        public MujServerEventListener()
        {
            InitializeComponent();
            eventLog1.EnableRaisingEvents = true;
            eventLog1.Log = "Application";
            eventLog1.MachineName = ".";
            eventLog1.Source = "MojeService1";
        }
        protected void OnEntryWritten(object sender, System.Diagnostics.EntryWrittenEventArgs e)
        {
            DateTime time = e.Entry.TimeGenerated;
            string message = e.Entry.Message;
            this.listBox1.Items.Add(time + " " + message);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }
}

Otevřeme návrhář zobrazení a přetáhneme na plochu komponentu EventLog. Upravíme zdroj událostí.
Nezapomeneme přidat reference na server.

Projekt ClientServer

Tento poslední projekt bude odesílat a přijímat data ze serveru.
Vs - přidat - nový projekt - Formulářová aplikace Windows (název ClientServer).

Kód této aplikace je také velmi jednoduchý:

using System;
using System.Windows.Forms;
using System.Text;
using System.Net.Sockets;

namespace WindowsService1
{
    partial class ClientServer1 : Form
    {
        public ClientServer1()
        {
            InitializeComponent();
        }

        private void OnGetQuote1_Click(object sender, EventArgs e)
        {
            TcpClient client = new TcpClient();
            NetworkStream stream = null;
            try
            {
                client.Connect("127.0.0.1", 5678);                      //1
                stream = client.GetStream();                            //2
                byte[] buffer = new Byte[1024];
                int received = stream.Read(buffer, 0, 1024);            //3
                if (received <= 0)
                {
                    this.textQuote1.Text = "Čtení selhalo";
                    return;
                }
                textQuote.Text = Encoding.Unicode.GetString(buffer);    //4
            }
            catch (SocketException ex)
            {
                this.textQuote1.Text = ex.Message;
            }
            finally
            {
                if (stream != null)
                    stream.Close();                                     //5
                if (client.Connected)
                    client.Close();                                     //5
            }
        }
    }
}
  1. Připojení klienta ke vzdálenému hostiteli TCP pomocí zadaného hostitele, jména a čísla portu.
  2. Vrátí NetworkStream, slouží k odesílání a přijímání dat.
  3. Čtení dat z NetworkStream.
  4. Kódování UTF-16 formátu little-endian bajt pořadí načtení.
  5. Zavře aktuální proud a uvolní všechny prostředky (například sokety a popisovačů souboru) spojené s aktuálním datovým proudem.
Windows Service

Doplníme assemblyInfo:

ClientServer, MujServerEven­tListener, Server a WindowsService1.

using System.Security;

[assembly: AssemblyKeyNameAttribute("")]
[assembly: SecurityRules(SecurityRuleSet.Level2)]

Pokud používáte VS2008 .NET Framework nižší než verze 4.0 použijete:

[assembly: SecurityRules(SecurityRuleSet.Level1)]

U všech projektů ve vlastnostech - sestavení - zpracovávat upozornění jako chyby - zatrhneme vše

Budeme pokračovat v dalším dílu doplněním kódu serveru.


 

Stáhnout

Staženo 50x (306.77 kB)
Aplikace je včetně zdrojových kódů v jazyce C#

 

  Aktivity (1)

Článek pro vás napsal zpavlu
Avatar
C# a C++

Jak se ti líbí článek?
Ještě nikdo nehodnotil, buď první!


 


Miniatura
Všechny články v sekci
C# - Pro pokročilé

 

 

Komentáře

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zatím nikdo nevložil komentář - buď první!