Logowanie wyjątków dla usług WCF przy użyciu ELMAH

Używamy doskonałego ELMAH do radzenia sobie z nieobsługiwanymi wyjątkami w ASP.NET 3.5 aplikacja internetowa. Działa to bardzo dobrze dla wszystkich stron, z wyjątkiem usług WCF, które są wykorzystywane przy użyciu pozostałych funkcji. Gdy w metodach operacyjnych występuje wyjątek, który nie jest obsługiwany przez kod aplikacji, WCF obsługuje go na różne sposoby w zależności od umów serwisowych i ustawień konfiguracji. Oznacza to, że wyjątek nie kończy się odpaleniem ASP.NET HttpApplication.Zdarzenie błędu, którego używa ELMAH . Dwa rozwiązania, które znam, aby sobie z tym poradzić, to:

Pierwsza opcja jest niezwykle prosta, ale nie jest dokładnie sucha . Druga opcja wymaga tylko udekorowania każdej usługi atrybutem niestandardowym po zaimplementowaniu atrybutu i narzędzia ErrorHandler. Zrobiłem to na podstawie pracy Willa, ale chcę sprawdzić, czy jest to poprawne podejście przed opublikowaniem kodu.

Czy jest lepszy sposób, który przegapiłem?

Dokument MSDN dla Ierorhandler mówi, że metoda HandleError jest miejscem do logowania, ale ELMAH uzyskuje dostęp do HttpContext.Aktualne.ApplicationInstance , która jest null w tej metodzie, mimo że HttpContext.Prąd jest dostępny. Wywołanie Elmah w metodzie ProvideFault jest obejściem, ponieważ ustawiona jest ApplicationInstance, ale nie odpowiada intencji opisanej w dokumentacji API. czy coś mi umknęło? dokumentacja stwierdza, że nie należy polegać na wywołaniu metody HandleError w wątku operacji, co może być powodem, dla którego ApplicationInstance jest null w tym zakresie.

Author: Martin Hollingsworth, 2009-05-22

6 answers

Rozwiązanie z mojego postu na blogu (o którym mowa w OP) było oparte na istniejącym rozwiązaniu, którego używamy do zmiany kodów odpowiedzi HTTP podczas stanu błędu.

Więc dla nas była to zmiana w jednej linii, aby przekazać wyjątek ELMAH. Jeśli jest lepsze rozwiązanie, też chciałbym się o tym dowiedzieć.

Dla potomności/odniesienia i potencjalnej poprawy-oto kod z obecnego rozwiązania.

HttpErrorHandler i Serviceerrorbehaviouratribute Klasy

using System;
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Collections.ObjectModel;
using System.Net;
using System.Web;
using Elmah;
namespace YourApplication
{
    /// <summary>
    /// Your handler to actually tell ELMAH about the problem.
    /// </summary>
    public class HttpErrorHandler : IErrorHandler
    {
        public bool HandleError(Exception error)
        {
            return false;
        }

        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            if (error != null ) // Notify ELMAH of the exception.
            {
                if (System.Web.HttpContext.Current == null)
                    return;
                Elmah.ErrorSignal.FromCurrentContext().Raise(error);
            }
        }
    }
    /// <summary>
    /// So we can decorate Services with the [ServiceErrorBehaviour(typeof(HttpErrorHandler))]
    /// ...and errors reported to ELMAH
    /// </summary>
    public class ServiceErrorBehaviourAttribute : Attribute, IServiceBehavior
    {
        Type errorHandlerType;

        public ServiceErrorBehaviourAttribute(Type errorHandlerType)
        {
            this.errorHandlerType = errorHandlerType;
        }

        public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
        }

        public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
        {
        }

        public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            IErrorHandler errorHandler;
            errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);
            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                channelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }
    }
}

Przykład Użycia

Udekoruj swoje usługi WCF atrybutem ServiceErrorBehaviour:

[ServiceContract(Namespace = "http://example.com/api/v1.0/")]
[ServiceErrorBehaviour(typeof(HttpErrorHandler))]
public class MyServiceService
{
  // ...
}
 86
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-19 01:23:28

Podczas tworzenia BehaviorExtensionElement możliwe jest nawet aktywowanie zachowania za pomocą config:

public class ErrorBehaviorExtensionElement : BehaviorExtensionElement
{
    public override Type BehaviorType
    {
        get { return typeof(ServiceErrorBehaviourAttribute); }
    }

    protected override object CreateBehavior()
    {
        return new ServiceErrorBehaviourAttribute(typeof(HttpErrorHandler));
    }
}

Config:

<system.serviceModel>
    <extensions>
      <behaviorExtensions>
        <add name="elmah" type="Namespace.ErrorBehaviorExtensionElement, YourAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
      </behaviorExtensions>
    </extensions>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <elmah />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

W ten sposób możliwe jest również korzystanie z ELMAH w połączeniu z usługami RIA!

 9
Author: riezebosch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-17 13:42:38

Zrobiłem to na podstawie pracy Willa ale chcę sprawdzić, czy jest to poprawne podejście przed wysłaniem kod.

Myślę, że jest to świetne podejście (chwała Willowi za ten post!). Nie sądzę, żeby Will lub ty coś tu przegapiłeś. Implementacja Ierorhandlera jest preferowanym sposobem przechwytywania wszystkich możliwych WYJĄTKÓW po stronie serwera, które w przeciwnym razie mogłyby spowodować uszkodzenie kanału komunikacyjnego (zburzenie), a zatem jest to naturalne miejsce, aby podłączyć się do niektórych wycinka drzew jak ELMAH.

Marc

 2
Author: marc_s,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 05:25:14

Może to być oczywiste dla niektórych osób, ale spędziłem trochę czasu próbując dowiedzieć się, dlaczego mój HttpContext.Prąd był zerowy, mimo że podążał za doskonałą odpowiedzią Willa Hughesa. Embassy, zdałem sobie sprawę, że to dlatego, że moja usługa WCF jest aktywowana przez wiadomość MSMQ.

Skończyłem przepisując metodę ProvideFault():

if (HttpContext.Current == null)
{
    ErrorLog.GetDefault(null).Log(new Error(error));
}
else
{
    ErrorSignal.FromCurrentContext().Raise(error);
}
 2
Author: Steve Rukuts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-05 16:47:14

Nie byłem w stanie uzyskać proponowanej odpowiedzi pracując z usługą danych WCF. Podłączyłem atrybut zachowania itp., ale nadal nie zarejestrowałem żadnych błędów. Zamiast tego dodałem do implementacji usługi:

protected override void HandleException(HandleExceptionArgs args)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(args.Exception);
    base.HandleException(args);
}
 1
Author: Daniel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-05 19:40:19

Nie próbowałem robić tego wprost z resztą rzeczy, i nie używałem ELMAH osobiście, ale inną opcją warto przyjrzeć się może być hook do WCF za pomocą IDispatchMessageInspector zamiast Ierorhandler.

 0
Author: tomasr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-22 02:11:03