programing

ASP에서 *all* 예외 처리를 사용하지 않도록 설정합니다.NET Web API 2 (나만의 공간을 만들기 위해)?

lastcode 2023. 9. 19. 21:11
반응형

ASP에서 *all* 예외 처리를 사용하지 않도록 설정합니다.NET Web API 2 (나만의 공간을 만들기 위해)?

미들웨어 구성 요소에서 예외 처리를 배선하고 싶습니다. 다음과 같은 것입니다.

public override async Task Invoke(IOwinContext context)
{
    try
    {
        await Next.Invoke(context);
    }
    catch (Exception ex)
    {
        // Log error and return 500 response
    }
}

제가 몇 가지 사항은 되어 입니다 입니다.HttpErrorResponse내가 그들에게 가기 전에 웹 API 파이프라인으로 s.그 과정에서 오류에 대한 세부 정보가 많이 손실되기 때문에 디버깅 등을 할 때 유용한 스택 트레이스를 얻을 수 없습니다(디버거는 예외를 던졌을 때도 멈추지 않습니다 - 수동으로 코드를 뒤져서 어디에서 실패하는지 확인해야 합니다...).

다음과 같은 구현을 통해 사용자 지정 예외 처리기를 추가하려고 했습니다.

public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
    var owinContext = context.Request.GetOwinContext();
    owinContext.Set(Constants.ContextKeys.Exception, context.Exception);
    return Task.FromResult(0);
}

를 통하여 config.Services.Replace(typeof(IExceptionHandler), new MyExceptionHandler());Next.Invoke(context)를 통하여

context.Get<Exception>(Constants.ContextKeys.Exception);

여전히 원하는 세부 정보를 제공하지 못할 뿐만 아니라 디버거의 장애 지점에서 멈추지 못합니다.

내장된 모든 오류 처리완전히 꺼서 미들웨어가 처리할 수 있는 방법이 있습니까?

해명, 많은 사람들이 내가 무엇을 추구하는지 오해하는 것 같기 때문입니다.

  • 웹 API의 기본 제공 오류 처리는 일부(모두는 아니지만) 예외를 잡아 500개의 응답으로 다시 씁니다.
  • 모든 예외를 잡고 로깅을 수행한 다음 선택한 정보로 500개의 응답을 내보내고 싶습니다(대부분은 다음 글머리표 참조)
  • 비즈니스 로직 오류를 나타내는 몇 가지 예외 사항도 있습니다. 대신 오류 40배를 반환하고자 합니다.
  • 이것이 (앱) 파이프라인의 맨 위에 있기를 바랍니다. 즉, 요청 라이프사이클의 다른 모든 것을 포장하는 것입니다.
  • 이 문제를 OWIN을 사용하여 처리하여 향후 가능한 자체 호스팅 시나리오로 이동할 수 있도록 하고 싶습니다(즉, 이 앱이 IIS에서 항상 호스팅된다는 것이 전혀 명시되어 있지 않습니다. Global.asax.cs 등은 여기와 관련이 없습니다).

업데이트: 블로그에 올린 내용입니다.블로그 게시물을 조사해보니 개선 가능성이 발견되었고, 이 답변의 관련 부분을 업데이트했습니다.여기 있는 다른 모든 제안이나 기본 동작보다 이것이 더 낫다고 생각하는 이유에 대한 자세한 내용은 게시물 전체를 읽어보세요 :)


저는 이제 다음과 같은 접근 방식을 취했는데, 이 접근 방식은 제가 찾던 것과 100% 일치하지 않더라도 잘 작동하는 것 같습니다.

  • 클래스생성PassthroughExceptionHandler:

    public class PassthroughExceptionHandler : IExceptionHandler
    {
        public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
        {
            // don't just throw the exception; that will ruin the stack trace
            var info = ExceptionDispatchInfo.Capture(context.Exception);
            info.Throw();
            return Task.CompletedTask;
        }
    }
    
  • 그 수업이 그 수업을 대체하게 해주세요.IExceptionHandler웹 API 서비스:

    config.Services.Replace(typeof(IExceptionHandler), new PassthroughExceptionHandler());
    
  • 내가 원하는 작업을 수행하는 미들웨어 클래스를 만듭니다.

    public class ExceptionHandlerMiddleware
    {
        public override async Task Invoke(IOwinContext context)
        {
            try
            {
                await Next?.Invoke(context);
            }
            catch (Exception ex)
            {
                // handle and/or log
            }
        }
    }
    
  • 미들웨어를 스택에 먼저 등록합니다.

    app.Use<ExceptionHandlerMiddleware>()
       .UseStageMarker(PipelineStage.Authenticate)
       // other middlewares omitted for brevity
       .UseStageMarker(PipelineStage.PreHandlerExecute)
       .UseWebApi(config);
    

나는 여전히 누구에게나 현상금을 수여할 것입니다. (혜택이 만료됨...) 더 나은 해결책을 찾고 있습니다. 예를 들어, 처리되지 않은 예외를 처리할 때 깨지는 것입니다. (이 방법은 처리기에서 예외를 다시 처리할 때 VS가 깨집니다.그러나 원래 콜 스택이 손실됩니다. 오류가 발생한 회선에 중단점을 설정하고 예외가 발생했을 때 상태를 가로챌 수 있도록 다시 디버그해야 합니다.)

이것이 당신에게 도움이 될지는 모르겠지만, 나는 오류가 발견되지 않았더라도 모든 오류를 JSON으로 다시 보내야 하는 비슷한 요구사항이 있습니다.기본 컨트롤러를 만들고 ExecuteAsync를 덮어쓰면 응답을 만들 수 있습니다.

public class ControllerBase : ApiController
{
    protected string ClassName = "ControllerBase::";

    public override System.Threading.Tasks.Task<HttpResponseMessage> ExecuteAsync(System.Web.Http.Controllers.HttpControllerContext controllerContext, System.Threading.CancellationToken cancellationToken)
    {
        try
        {
            System.Threading.Tasks.Task<HttpResponseMessage> TaskList = base.ExecuteAsync(controllerContext, cancellationToken);

            if (TaskList.Exception != null && TaskList.Exception.GetBaseException() != null)
            {
                JSONErrorResponse AsyncError = new JSONErrorResponse();
                AsyncError.ExceptionMessage = TaskList.Exception.GetBaseException().Message;
                AsyncError.ErrorMessage = string.Format("Unknown error {0} ExecuteAsync {1}", ClassName ,controllerContext.Request.RequestUri.AbsolutePath);
                AsyncError.HttpErrorCode = HttpStatusCode.BadRequest;

                HttpResponseMessage ErrorResponse = controllerContext.Request.CreateResponse(AsyncError.HttpErrorCode, AsyncError);

                return System.Threading.Tasks.Task.Run<HttpResponseMessage>(() => ErrorResponse);
            }
            return TaskList;
        }
        catch (Exception Error)
        {
            JSONErrorResponse BadParameters = new JSONErrorResponse();
            BadParameters.ExceptionMessage = Error.Message;
            BadParameters.ErrorMessage = string.Format("Method [{0}], or URL [{1}] not found, verify your request", controllerContext.Request.Method.Method, controllerContext.Request.RequestUri.AbsolutePath);
            BadParameters.HttpErrorCode = HttpStatusCode.NotFound;
            HttpResponseMessage ErrorResponse = controllerContext.Request.CreateResponse(BadParameters.HttpErrorCode, BadParameters);

            return System.Threading.Tasks.Task.Run<HttpResponseMessage>(() => ErrorResponse);
        }
    }
}

public class JSONErrorResponse
{
    //Possible message from exception
    public string ExceptionMessage { get; set; }
    //Possible custom error message
    public string ErrorMessage { get; set; }
    //Http error code
    public HttpStatusCode HttpErrorCode { get; set; }
}

또한 컨트롤러 활성화기를 직접 만들고 사용자 지정 예외 처리기를 가지고 ExceptionFilterAttribute를 사용해 볼 수도 있습니다.

  1. 컨트롤러 액티베이터 만들기

    public class ExceptionHandlingControllerActivator : IHttpControllerActivator
    {
        private readonly IHttpControllerActivator _concreteActivator;
    
        public ExceptionHandlingControllerActivator(IHttpControllerActivator concreteActivator)
        {
            _concreteActivator = concreteActivator;
        }
    
        public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
        {
            try
            {
                return _concreteActivator.Create(request, controllerDescriptor, controllerType);
            }
            catch (Exception ex)
            {
                // do stuff with the exception
                throw new HttpResponseException(request.CreateResponse(HttpStatusCode.InternalServerError, new ResponseModel(ex)));
            }
        }
    }
    
  2. ExceptionFilter 특성 만들기

    public class ExceptionHandlingFilter : ExceptionFilterAttribute
    {
        public override void OnException(HttpActionExecutedContext context)
        {
            // do stuff with the exception
    
            var request = context.Request;
            ResponseModel respMod = null;
    
            // Example: if debug constant is not defined, mask exception, otherwise create normal object with message, inner exception and stacktrace
    
            #if !DEBUG
            respMod = new ResponseModel(context.Exception, context.Exception.Message, true);
            #else
            respMod = new ResponseModel(context.Exception);
            #endif
    
            context.Response = request.CreateResponse(HttpStatusCode.InternalServerError, respMod);
        }
    }
    
  3. ResponseModel은 Formaters를 사용하여 JSON에 직렬화하고 모든 컨트롤러 응답에 의해 반환되는 클래스이므로 클라이언트는 HTTP 상태 코드 외에도 성공적인 응답뿐만 아니라 오류 데이터를 식별할 수 있습니다.

    config.Formatters.Clear(); // do not need any other
    config.Formatters.Add(new JsonMediaTypeFormatter());
    
  4. 와이어업

    // ... [cut] ...            
    config.Filters.Add(new ExceptionHandlingFilter());
    // ... [cut] ...
    config.Services.Replace(typeof(IHttpControllerActivator),
        new ExceptionHandlingControllerActivator(config.Services.GetHttpControllerActivator())
    );
    // ... [cut] ...
    app.UseWebApi(config);
    

OWIN은 웹 api 자체 오류 처리 기능이 내장되어 있기 때문에 그런 예외를 처리하지 않는 것으로 되어 있습니다.OWIN은 애플리케이션과 분리되도록 설계되었습니다.예외 처리기의 HandleAsync 메서드에 중단점을 설정한 경우 컨텍스트 변수를 검사하고 예외의 세부 정보를 볼 수 있어야 합니다.

디버깅 목적으로만 이 작업을 수행하려는 경우 중단점을 설정하면 예외를 볼 수 있습니다.예외 사항을 기록해야 한다면 예외 처리자가 가장 적합하다고 생각합니다.

도움이 되길 바랍니다.

다음과 같은 도움이 될 수 있습니다.

https://stackoverflow.com/a/21382651/1419853

http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-21#global-error

기본적으로 오류를 파악, 처리 및 변경하기 위한 지원 기능이 내장되어 있습니다.

다음과 같습니다.

public class ExceptionLogger : System.Web.Http.ExceptionHandling.ExceptionLogger
{
    Logger _logger;

    public ExceptionLogger(Logger logger)
    {
        _logger = logger;
    }

    public override void Log(ExceptionLoggerContext context)
    {
        _logger.Error(context.ExceptionContext.Exception.ToString());
    }
}

언급URL : https://stackoverflow.com/questions/34201527/disable-all-exception-handling-in-asp-net-web-api-2-to-make-room-for-my-own

반응형