2015-03-10 2 views
0

Я пишу HttpHandler, и, как часть моего внутреннего дизайна, я бросаю разные исключения и улавливаю их на верхнем уровне, чтобы определить, какой код состояния задает запрос.Захват базы, но не вспомогательные исключения

I.e. ArgumentException запускает Bad Request
AuthenticationException запускает Несанкционированное
OracleException запускает InternalServerError
и т.д.

Проблема я обнаружил, что я использовал InvalidOperationException, чтобы вызвать NotFound, но ошибка в моем коде заставило меня осознать, что, конечно, некоторые системные исключения наследуют от этих исключений базовой системы, что вызывает неожиданные ответы.

I.e. Я обнаружил, что ObjectDisposedException наследует от InvalidOperationException, что означает, что ответ возвращает 404 вместо 500.

Есть ли способ поймать только базовое исключение?

Я нашел this thread, который предполагает, что я могу сделать фильтр и ретрол, но это кажется взломанным.

Буду ли я лучше создавать собственные типы исключений, чтобы сохранить все эти проблемы?

+3

Да, вы обязательно должны свернуть свое собственное исключение для этого конкретного варианта использования, а не использовать 'InvalidOperationException'. – dursk

+1

Определенно не поднимайте 'InvalidOperationException' за что-то, что это не значит. То же самое относится к любому другому исключению. Соблюдайте собственные исключения и основывайте их на «Исключении». Просто убедитесь, что вы передаете исходное исключение как внутреннее исключение, когда вы бросаете свои собственные исключения, чтобы поддерживать стек вызовов. Я не знаю, почему у вас есть нисходящая линия, это законная и очень распространенная ошибка. – bokibeg

+0

@mattm @bokibeg спасибо, я, вероятно, должен был прочитать doco о том, что .NET определяет '' InvalidOperationException''. Я буду определять свои собственные исключения и обернуть любые обнаруженные исключения. –

ответ

0

Это не представляется возможным только поймать базовых исключений.

В этом случае лучше создать собственное исключение, а не использовать типы исключений системы.

public class HttpErrorException : Exception 
{ 
    public HttpStatusCode StatusCode { get; private set; } 
    public HttpErrorException(HttpStatusCode code, string message) 
     : base(message) 
    { 
     this.StatusCode = code; 
    } 
} 

throw new HttpErrorException(400, "You sent a bad request!"); 

Если первоначальное намерение было запутать коды состояния HTTP, и вместо того, чтобы использовать их текстовые имена, фабричные методы могут быть созданы.

public class HttpErrorException : Exception 
{ 
    public HttpStatusCode StatusCode { get; private set; } 

    private HttpErrorException(HttpStatusCode code, string message) 
     : base(message) 
    { 
     this.StatusCode = code; 
    } 

    public static HttpErrorException BadRequest(string message) 
    { 
     return new HttpErrorException(400, message); 
    } 

    public static HttpErrorException InternalServerError(string message) 
    { 
     return new HttpErrorException(500, message); 
    } 
    // etc 
} 

throw HttpErrorException.BadRequest("You made a bad request!"); 
2

Если вы хотите, чтобы передать результирующий код HTTP (и, возможно, строка с сообщением об ошибке) к клиенту, то я рекомендую вам создать одного пользовательских исключений:

public class MyCustomException : Exception { // Or maybe InvalidOperationException 
    public int StatusCode {get;set;} 
    public string Status {get;set;} 
} 

т.д.

+0

Это прекрасная идея, я всегда забываю, что вы можете добавить дополнительные свойства к исключениям! Однако я думаю, что предпочитаю иметь набор пользовательских исключений. Несмотря на то, что он добавляет немного служебных данных кода, IMO выглядит более чистым в коде ('' throw BadRequestExeption («msg») '' в отличие от '' throw HttpErrorException (400, msg)) '') –

+1

Вы должны свести к минимуму число настраиваемых классов исключений, которые вы создаете. Особенно в этом случае, где они все одинаковые. Вы можете создать набор заводских методов для создания определенных видов, и, кроме того, вы говорите о двух параметрах, а не о одном. –

+0

В моей голове я всегда думаю об исключениях как о отдельном зверю и забываю, что они просто классы. Я предпочитал отдельные именованные классы, так как легче получить смысл (а не коды состояния), но идея фабричных функций велика, так как позволяет использовать один класс исключений с обфускацией названных вызовов. Вместо этого я реализовал это. Если вы можете добавить эту часть к своему ответу, я помечаю ее как принятую. –

0

Насколько мне известно, нет способа поймать исключение, но не поймать унаследованные исключения. Проблема заключается в том, что вы рассматриваете базовое исключение как более конкретное, чем унаследованное исключение, которое противоположно тому, как они предназначены для работы (унаследованные исключения должны быть более конкретными подмножествами их родительского элемента, поэтому концептуально, если вы можете справиться родительский, вы должны иметь возможность обрабатывать унаследованное исключение).

Ваши варианты в основном являются:

  1. Создайте свой собственный тип исключения & только поймать это. Если ваше исключение подпадает под определение InvalidOperationException, вы можете наследовать его. Тогда вы можете поймать вас специально.
  2. Поймать, осмотреть и повторно бросить, если это не то, что вам нужно. Этот метод, который я обычно стараюсь избегать, но иногда требуется, если типы исключений являются слишком общими. например

    catch (InvalidOperationException ex) { 
        if (ex.GetType() != typeof(InvalidOperationException)) throw; 
        /* Do stuff */ 
    } 
    
Смежные вопросы