WCF: ошибка SOAP или обычные исключения в классе DataContract

Основным параметром OperationContract моей службы является класс Preapproval. В классе Preapproval есть несколько общедоступных методов получения/установки для атрибутов DataMember. У меня есть код, который проверяет входные данные для сеттеров, так что я бы выдал исключение ArgumentException, если, скажем, параметр пуст или выходит за пределы допустимых границ для домена.

Если входные данные недействительны, я обычно выбрасываю здесь исключение ArgumentException. Поскольку это ситуация с WCF, должен ли я создавать здесь предопределенное исключение FaultException, а не ArgumentException? Я понимаю, что в другом месте я могу перехватывать общие исключения и повторно выдавать их как FaultExceptions, но это действие будет происходить выше по стеку, в некоторых работах, автоматически выполняемых WCF.

Например, когда вызывающая сторона вызывает мою службу, сериализатор десериализует свой SOAP, попытается вызвать сеттеры для моего объекта и сгенерирует исключение ArgumentException задолго до фактического вызова моей операции. Таким образом, является ли хорошей практикой проектирования в классах DataContract просто сразу генерировать исключения FaultException? Я действительно не хочу связывать пользовательский обработчик с диспетчером каналов.

Я понимаю, что могу просто генерировать FaultExceptions напрямую, но мне бы очень хотелось ограничить подобные вещи службой. Если этого нельзя избежать, я могу сделать это и в поддерживающих классах, но я бы предпочел писать как можно больше типового кода, который не так тесно связан с System.ServiceModel и т.д.

Спасибо!


person Pittsburgh DBA    schedule 29.03.2011    source источник
comment
Как насчет использования FaultContractAttribute?   -  person Brad Christie    schedule 29.03.2011
comment
Естественно, это вариант, который мы изучаем. Мой вопрос больше связан с передовой практикой. Например, в классе, который мы используем в качестве служебного параметра, в его сеттерах, если мы должны генерировать исключения, должны ли мы генерировать FaultException и там, а не ArgumentException? Как правило, мы бы предпочли связывать с инфраструктурой WCF как можно меньше вещей, но, учитывая то, как они отмечены атрибутами DataContract и DataMember, возможно, это спорный момент.   -  person Pittsburgh DBA    schedule 29.03.2011
comment
Если кто-то читает это, я решил использовать более простой подход и просто передать службе примитивные типизированные параметры, а не объект Preapproval. Таким образом, сама служба может проверить ввод и выдать соответствующее исключение FaultException. EAB оказался излишним для этой службы с одним методом.   -  person Pittsburgh DBA    schedule 10.05.2011


Ответы (2)


Я бы исключил FaultExceptions из вашего класса DataContract — возможно, вы захотите использовать эти классы вне контекста WCF.

Один из подходов, который предотвратит проникновение специального кода WCF в ваши DataContracts (помимо атрибутов), состоит в том, чтобы класс DataContract выдавал исключения, а на уровне службы использовалось Защита от исключений WCF Enterprise Library чтобы сопоставить эти исключения с контрактами ошибок.

В основном Enterprise Library реализует IErrorHandler и преобразует Exceptions в FaultExceptions. Я думаю, что обработчик - единственный способ добиться того, чего вы хотите (поскольку исключения не генерируются в вашей службе). Хорошая новость заключается в том, что вам действительно не нужно много делать, чтобы заставить его работать.

Просто добавьте атрибут к вашему сервису:

[ServiceContract]
[ExceptionShielding]
public interface IApproval
{
    [OperationContract]
    [FaultContract(typeof(ApplicationServiceFault))]
    [FaultContract(typeof(SystemServiceFault))]
    void PreApprove(Preapproval preapproval);
}

а затем добавьте некоторую конфигурацию (конфигурация опущена для экономии места), чтобы сопоставить исключения с FaultContract. Обратите внимание, что ваши операции по-прежнему должны будут объявлять FaultContracts.

person Randy supports Monica    schedule 29.03.2011
comment
Спасибо; это больше соответствует моему вопросу, поскольку мы хотим, чтобы классы были скорее независимыми от фреймворка. Итак, поскольку мы выбрасываем исключение ArgumentException в сеттерах, нам нужен способ убедиться, что оно отображается должным образом. Я посмотрю на это Exception Shielding. Спасибо. Я буду обновлять, как только я получу шанс. - person Pittsburgh DBA; 30.03.2011
comment
Это похоже на путь. Мне особенно интересно посмотреть, как это работает, когда сервису передаются недопустимые параметры. Между прочим, это направление исследований привело меня к блоку проверки, который также является приятной функцией. Возможно, вместе они станут окончательным решением для чистой проверки параметров WCF. - person Pittsburgh DBA; 31.03.2011
comment
@Pittsburgh DBA: будет немного сложно заставить VAB работать в модели, о которой вы говорите. Вероятно, вам придется создать набор правил для каждого свойства и заставить каждый установщик вызывать метод Validate. Кроме того, в вашем текущем подходе, если вы проверяете установщики, то, как только один установщик получает недопустимое значение, вы выдаете исключение, поэтому пользователь будет получать только одно сообщение об ошибке за раз. Это может быть не то, что пользователи хотели бы видеть. - person Randy supports Monica; 01.04.2011

Ваш класс PreApproval не должен знать, что он используется в веб-службе. Пусть он сгенерирует любое исключение, которое оно бы сгенерировало, если бы его вызывали из приложения любого другого типа.

«Верхний уровень» вашего сервиса должен перехватывать исключения и преобразовывать их в соответствующие FaultException.

person John Saunders    schedule 30.03.2011
comment
Как я уже сказал, это невозможно, так как это не наш код, а внутренние компоненты WCF, которые десериализуют SOAP вызывающего объекта и тем самым вызывают установщики в нашем классе DataContract. Возможно, я не очень хорошо это объясняю. Мы можем, конечно, перехватывать исключения слева и справа и генерировать соответствующее исключение FaultException. Мы не можем сделать это ВНУТРИ системы WCF, которая выполняется ДО нашего кода службы. - person Pittsburgh DBA; 30.03.2011
comment
@Pitt: установщики выдадут исключение. - person John Saunders; 01.04.2011
comment
@John Saunders: установщики выдают исключение, и тип исключения, который они выдают, - ArgumentException. Это связано с тем, что они являются классами общего назначения и не привязаны к зависимостям WCF. Таким образом, когда служба вызывается и установщики выбрасывают свои исключения, это вызывает проблемы, потому что, если мы не используем ExceptionShielding, это происходит слишком далеко вверх по стеку, чтобы мы могли перехватить и впоследствии сгенерировать FaultException, как мы хотели бы сделать. - person Pittsburgh DBA; 03.05.2011
comment
Посмотрите на реализацию интерфейса IErrorHandler. Это то, для чего это нужно. - person John Saunders; 03.05.2011
comment
Спасибо. Будет ли это лучше, чем использование блока приложений Enterprise Exception Handling? - person Pittsburgh DBA; 03.05.2011
comment
@Pitt: для этой цели, я так думаю. Это позволяет вам использовать [FaultContract] в своих операциях. IErrorHandler преобразует исходное исключение в правильную ошибку. - person John Saunders; 04.05.2011
comment
@Джон Сондерс: Большое спасибо! - person Pittsburgh DBA; 04.05.2011