programing

ELMAH를 사용한 WCF 서비스에 대한 예외 로깅

telebox 2023. 7. 6. 22:08
반응형

ELMAH를 사용한 WCF 서비스에 대한 예외 로깅

우리는 ASP.NET 3.5 웹 애플리케이션에서 처리되지 않은 예외를 처리하기 위해 우수한 ELMAH를 사용하고 있습니다.이것은 REST 기능을 사용하여 소비되는 WCF 서비스를 제외한 모든 사이트에서 매우 잘 작동합니다.응용 프로그램 코드로 처리되지 않는 작업 방법 내에서 예외가 발생하면 WCF는 서비스 계약 및 구성 설정에 따라 다양한 방법으로 이를 처리합니다.이는 예외가 ASP.NET HttpApplication을 실행하는 것으로 끝나지 않습니다.ELMAH가 사용하는 오류 이벤트입니다.이 문제를 해결하기 위해 알고 있는 두 가지 솔루션은 다음과 같습니다.

  • 모든 메서드 호출을 try { } catch(Exception ex) {Elmah}(으)로 래핑합니다.오류 신호입니다.FromCurrentContext().캐치 블록 내에서 엘마를 명시적으로 호출하려면 (ex); 던지기; }을(를) 올립니다.
  • Will Hughes의 블로그 게시물 Making WCF와 ELMAH의 설명따라 IErrorHandler를 사용하여 ELMAH에 대한 호출을 별도의 ErrorHandler로 분해합니다.

첫 번째 옵션은 매우 간단하지만 완전히 건조하지는 않습니다.두 번째 옵션은 속성 및 ErrorHandler를 구현한 후 각 서비스를 사용자 지정 속성으로 장식하기만 하면 됩니다.저는 윌의 작업을 바탕으로 이 작업을 수행했지만 코드를 게시하기 전에 이 방법이 올바른지 확인하고 싶습니다.

제가 놓친 더 좋은 방법이 있을까요?

IErrorHandler에 대한 MSDN 문서에는 HandleError 메서드가 로깅을 수행하는 위치이지만 ELMAH는 HttpContext에 액세스한다고 나와 있습니다.현재의.응용 프로그램인스턴스. HttpContext에도 불구하고 이 메서드 내에서 null입니다.전류를 사용할 수 있습니다.ProvideFault 메서드 내에서 Elmah에 전화를 거는 것은 Application과 같은 해결 방법입니다.인스턴스가 설정되었지만 API 설명서에 설명된 의도와 일치하지 않습니다.제가 여기서 뭘 빠뜨린 건가요?설명서에는 작업 스레드에서 호출되는 HandleError 메서드에 의존해서는 안 된다고 명시되어 있습니다. 이는 응용 프로그램의 이유일 수 있습니다.인스턴스가 이 범위에서 null입니다.

제 블로그 게시물(OP에서 참조)의 솔루션은 오류 상태에서 HTTP 응답 코드를 변경하기 위해 사용 중이거나 사용 중인 기존 솔루션을 기반으로 했습니다.

그래서, 우리에게는 ELMAH에 대한 예외를 통과시키는 것이 한 줄 변경이었습니다.더 좋은 해결책이 있다면 저도 알고 싶습니다.

사후/참조 및 잠재적 개선을 위해 현재 솔루션의 코드가 여기 있습니다.

HttpErrorHandler 및 ServiceErrorBehavior 특성 클래스

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);
            }
        }
    }
}

사용 예

ServiceErrorBehavior 특성을 사용하여 WCF 서비스를 장식합니다.

[ServiceContract(Namespace = "http://example.com/api/v1.0/")]
[ServiceErrorBehaviour(typeof(HttpErrorHandler))]
public class MyServiceService
{
  // ...
}

동작을 생성할 때ExtensionElement 구성을 사용하여 동작을 활성화할 수도 있습니다.

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

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

구성:

<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>

그렇게 하면 ELMAH를 RIA 서비스와 함께 사용할 수도 있습니다!

이것은 일부 사람들에게는 명백할 수 있지만, 저는 단지 제 HttpContext의 이유를 알아내기 위해 꽤 오랜 시간을 보냈습니다.윌 휴즈의 훌륭한 답변을 모두 따랐음에도 불구하고 전류는 무효였습니다.당황스럽게도, 저는 이것이 제 WCF 서비스가 MSMQ 메시지에 의해 활성화되었기 때문이라는 것을 깨달았습니다.

나는 결국 그것을 다시 썼습니다.ProvideFault()방법:

if (HttpContext.Current == null)
{
    ErrorLog.GetDefault(null).Log(new Error(error));
}
else
{
    ErrorSignal.FromCurrentContext().Raise(error);
}

저는 윌의 작업을 바탕으로 이 작업을 수행했지만 코드를 게시하기 전에 이 방법이 올바른지 확인하고 싶습니다.

저는 이것이 훌륭한 접근법이라고 생각합니다(이 게시물에 대한 윌의 칭찬!).윌이나 당신은 여기서 놓친 것이 없다고 생각합니다.IErrorHandler를 구현하는 것은 통신 채널에 장애가 발생할 수 있는 모든 가능한 서버 측 예외를 캡처하는 선호되는 방법이므로 ELMAH와 같은 일부 로깅에서 후크를 거는 것이 당연합니다.

마르크

WCF 데이터 서비스를 사용하여 제안된 답변을 얻을 수 없습니다.동작 속성 등을 연결했지만 오류가 기록되지 않았습니다.대신 서비스 구현에 다음 사항을 추가했습니다.

protected override void HandleException(HandleExceptionArgs args)
{
    Elmah.ErrorSignal.FromCurrentContext().Raise(args.Exception);
    base.HandleException(args);
}

나는 REST 물건으로 이것을 명시적으로 시도하지 않았고, ELMAH를 직접 사용하지도 않았지만, 조사할 가치가 있는 다른 옵션은 ID 디스패치 메시지를 사용하여 WCF에 연결하는 것일 수 있습니다.IErrorHandler 대신 Inspector.

언급URL : https://stackoverflow.com/questions/895901/exception-logging-for-wcf-services-using-elmah

반응형