WCF – logování neošetřených výjimek na straně serveru


V předchozím článku jsem se zaměřil na ladění vzájemné komunikace mezi klientem a WCF službou. Tentokrát se podívám na ladění samotné WCF služby. Na zachycování neošetřených výjimek a na jejich následné logování.

Zachytávání výjimek na straně WCF služby

Logování popisovaném v předchozím článku neumí (nebo já o tom nevím) zachytávat a logovat výjimky, ke kterým dojde ve webových metodách WCF služby. Problém ovšem je, že i tyto chyby je potřeba nějakým způsobem zaznamenávat a opravovat. Samozřejmě lze využít klasické zachytávání výjimek jako try-catch a jejich následné zpracování, ale ne vždy se tento způsob hodí.

Proto existuje také další, globálnější způsob, jak s nezachycenými výjimkami pracovat v celé WCF službě. Tímto způsobem je použití rozhraní IErrorHandler.

Rozhraní IErrorHandler

Toto rozhraní poskytuje kontrolu nad Fault zprávami (Message), které jsou potom vraceny klientovi, umožňuje zpracovávat chyby požadovaným způsobem (například logování) atd.

Objekty implementující toto rozhraní se přiřazují do kolekce ErrorHandlers třídy ChannelDispatcher. Způsobů jak toho dosáhnout je několik – viz například MSDN. Protože se jedná o kolekci, je možné použít několik handlerů chyb a tak je zpracovávat zároveň různými způsoby a již hotové třídy implementující toto rozhraní používat ve více projektech a libovolně je kombinovat. Handlery v kolekci ErrorHandlers jsou volány v pořadí, v jakém byly do kolekce přidány.

Rozhraní definuje dvě metody – ProvideFault a HandleError, které je potřeba implementovat, ale je možné je nechat prázdné, což například umožňuje zalogovat chybu, ale nezpracovávat zprávu posílanou klientovi atd.

ProvideFault

Metoda, která se používá pro kontrolu nad Fault zprávami, které jsou vraceny klientovi. V případě, že je tato metoda prázdná, nebude error handler fault zprávy zpracovávat (budou se posílat defaultní zprávy).

Tato zpráva je vždy volána první, takže ještě před metodou HandleError.

V případě, že chceme pouze logovat výjimky, ke kterým ve WCF službě došlo, stačí nechat tělo prázdné.

Blíže k této metodě a příkladu, jak tuto metodu implementovat viz MSDN.

HandleError

Implementací této metody zajistíme, že se provede požadované chování – například zalogování, vypnutí aplikace atd.

Implementace metody HandleError je jednoduchá (samozřejmě záleží na požadavcích). V parametru je metodě předána výjimka, ke které došlo a tuto výjimku stačí libovolným způsobem zpracovat. Například je možné jednoduše zapisovat do souboru:

        public bool HandleError(Exception error)
        {
            using (TextWriter textWriter = File.AppendText(@"c:logserrors.txt"))
            {
                if (error != null)
                {
                    textWriter.WriteLine(String.Format("{0} - {1}: {2}", DateTime.Now.ToString(), error.GetType().Name, error.Message));
                }
                textWriter.Close();
            }
            return true;
        }

Naznačeným způsobem je tedy možné logovat výjimky do souboru, ale představivosti se meze nekladou. Do databáze by se dalo logovat stejně přímočarou cestou.

Použití třídy Implementující rozhraní IErrorHandler

V tuto chvíli máme hotovou třídu implementující IErrorHandler, ale její použití jsem naznačil pouze povrchně. Velice elegantním způsobem, jak používat vlastní error handler je vytvoření atributu, který nastavuje chování WCF služby. Tímto atributem poté stačí označit WCF službu a ta automaticky používá zadaný error handler.

    public class CustomErrorBehaviorAttribute : Attribute, IServiceBehavior
    {
        void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
        }

        void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection endpoints, BindingParameterCollection parameters)
        {
        }

        void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                channelDispatcher.ErrorHandlers.Add(new CustomErrorHandler());
            }
        }
    }

Naznačeným způsobem implementujeme vlastní atribut, který WCF službě přiřadí výše vytvořený error handler. Takto vytvořený atribut je pouze nejjednodušším způsobem, jakým se dá atribut napsat, ovšem funguje, a pro pochopení je myslím ideální.

Použití tohoto atributu bude vypadat následovně:

[CustomErrorBehavior]

Tímto atributem potom označíme WCF službu a všechny neošetřené výjimky budeme mít zalogované.

Závěr

Postup předvedený v článku je pouze odrazovým můstkem, ale tímto způsobem se dá k logování výjimek přistupovat a zpracovávat je. Pokud někdo preferuje jiný postup nebo vidí na mém něco špatně, ať se o své názory podělí v komentářích.

Odkazy:

, , , ,

Komentáře jsou uzavřeny.