Projektowanie, Programowanie, Codzienność – BeniaminZaborski.com

18 stycznia 2014

WCF – logowanie błędów

Może część z Was zastanawiała się kiedyś jak wprowadzić własny mechanizm logowania błędów w WCF? Ja miałem potrzebę implementacji takiego mechanizmu logowania i podzielę się jedną z prostszych opcji.

O co właściwie chodzi?

Mianowicie walczymy o to, aby po stronie serwera hostującego nasz serwis WCF była możliwość zapisu do logów błędów występujących w tymże serwisie. Wiemy, że domyślnie wszystkie wyjątki jakie wystąpią w serwisach WCF nie są wysyłane do klienta. Wiemy także, że to domyślne zachowanie możemy łatwo zmienić ustawiając includeExceptionDetailInFaults="true". Może na etapie developingu (tfu co za słowo) jest to wygodne, ale na pewno w systemie produkcyjnym … hmm no cóż powiedzmy, że klienta nie do końca interesują szczegóły wyjątku i cały stack trace:).  W systemie produkcyjnym chcemy mieć szczegóły błędów w naszym logu … czymkolwiek on będzie.

Z pomocą przychodzi nam prosty interfejs IErrorHandler z przestrzeni System.ServiceModel.Dispatcher. Zaimplementujmy go:

public class CustomErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        Logger.LogError(error); // Tutaj użyj swojego loggera!
        return true;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message msg)
    {

    }
}

To wszystko? Tak, a właściwie prawie:). Metoda HandleError to miejsce logowania błędu. Ale to jednak za mało gdyż jak się pewnie domyślacie teraz trzeba jakoś poinformować WCF-a, żeby użył naszej klasy CustomErrorHandler. Z pomocą przychodzi sam WCF, a mianowicie mechanizm rozszerzeń WCF-a, konkretniej mechanizm rozszerzeń zachowania serwisu BehaviorExtensionElement. A zatem:

public class CustomErrorHandlerExtension : BehaviorExtensionElement, IServiceBehavior
{
    public override Type BehaviorType
    {
        get { return GetType(); }
    }

    protected override object CreateBehavior()
    {
        return this;
    }

    private IErrorHandler GetInstance()
    {
        return new CustomErrorHandler();
    }

    void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
    {
    }

    void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        IErrorHandler errorHandlerInstance = GetInstance();
        foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
        {
            dispatcher.ErrorHandlers.Add(errorHandlerInstance);
        }
    }

    void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {

    }
}

Dwa najistotniejsze elementy powyższego kodu został wyróżnione, tj. instancjonowanie naszego CustomErrorHandler oraz zarejestrowanie go.

Czy teraz to już wszystko? Prawie :). Teraz przenosimy się do pliku konfiguracyjnego naszego serwera (w wypadu self-hosting to będzie pewnie usługa Windows, a w wypadku hostowania na IIS to jakaś aplikacja Web).

W ramach <system.serviceModel> dodajemy:

<extensions>
 <behaviorExtensions>
   <add name="customErrorHandler" type="TwojaAplikacja.CustomErrorHandlerExtension, TwojeAssembly" />
 </behaviorExtensions>
</extensions>

Rozszerzyliśmy WCF o nasz error handler, teraz pozostaje tylko go użyć. W ramach sekcji behavior naszego serwisu dodajemy <customErrorHandler/>.

Teraz to już naprawdę wszystko i działa!

Stwórz darmową stronę albo bloga na WordPress.com.