Поэтому я пытаюсь использовать Enterprise Library в своем сервисе WCF, чтобы выполнить для меня часть работы, связанной с исключениями.
Моя идея состоит в том, чтобы установить « Пользовательский обработчик исключений », скажем, «NullReferenceException», и в «Пользовательском обработчике исключений» создать исключение FaultException.
Насколько я понимаю, это "новое" исключение будет затем передаваться по проводам, и я поймаю его на клиенте.
Некоторый код для лучшего понимания:
Служба WCF:
[ServiceContract(Name="MyService", ConfigurationName="MyNamespace.MyService")]
[ExceptionShielding("PolicyName")]
public interface IMyService
{
[OperationContract]
[FaultContract(typeof(MyFaultContract))]
string Method(String Param);
}
public class MyService : IMyService
{
public string Method(String Param)
{
throw new NullReferenceException("code-created null message here");
}
}
Пользовательский обработчик исключений: (Корпоративная библиотека)
public class MyExceptionHandler : IExceptionHandler
{
public MyExceptionHandler(NameValueCollection collection) { }
public MyExceptionHandler() { }
public System.Exception HandleException(System.Exception exception,
Guid handlingInstanceId)
{
MyFaultContract details = new MyFaultContract();
if (exception is NullReferenceException)
{
details.ErrorCode = MyFaultCode.NullReferenceException;
details.OriginalMessage = exception.Message;
details.MyMessage = "Null Reference exception here!";
}
return new FaultException<MyFaultContract>(details);
}
}
Файл конфигурации приложения, который отображает исключение NullReferenceException на «Обработчик пользовательских исключений»:
<exceptionPolicies>
<add name="PolicyName">
<exceptionTypes>
<add name="NullReferenceException" type="System.NullReferenceException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction="ThrowNewException">
<exceptionHandlers>
<add type="MyExceptionHandler, MyApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
name="MyExceptionHandler" />
</exceptionHandlers>
</add>
</exceptionTypes>
</add>
</exceptionPolicies>
И, наконец, код клиента, который ожидает перехват этого FaultException:
MyService.MyServiceClient client = new MyService.MyServiceClient();
client.Open();
try
{
string result = client.Method(string parameter);
}
catch (System.ServiceModel.FaultException<MyService.MyFaultContract> ex)
{
// where I think exception should end up
}
catch (System.ServiceModel.FaultException ex)
{
// general FaultException
}
Но вместо этого я получаю ProtocolException, заявляя, что требуется ответное действие:
Получено ответное сообщение для операции «Метод» с действием ».
Тем не менее, ваш клиентский код требует действий
«http://tempuri.org/MyService/MethodResponse'.
Что я делаю не так? Можно ли вернуть (не явно выдать) исключение FaultException с настраиваемым FaultContract в «Обработчик настраиваемых исключений»?
Любой совет приветствуется.
Обновление:
Как видите, действие постобработки в «Обработчике нестандартных исключений» установлено в «ThrowNewException».
Если я изменяю его на «NotifyRethrow», я больше не получаю «ProtocolException»!
Вместо этого клиент перехватывает обычное «FaultException» (не пользовательский тип).
Теперь вопрос в том, почему оригинальное FaultException с пользовательским типом не проходит через провод.
Обновление 2
Одна вещь, которую я забыл упомянуть, это то, что моя служба WCF работает в ServiceHost, а не в IIS. Поэтому в основном у меня есть служба Windows, которая создает ServiceHost и предоставляет интерфейс Service1 через этот ServiceHost.
Причина, по которой я думаю, что это может быть как-то связано с этой проблемой, заключается в том, что Enterprise Library утверждает, что имеет дело с исключениями во всем приложении, а не только в границах служб. Может быть, это приведет к тому, что исключение будет выдано слишком поздно? Или не на правильном уровне?
Обновление 3
Спасибо за пост!
Вы правы, единственная причина, по которой я связываюсь с пользовательским обработчиком, заключается в том, что я хочу установить значение MyFaultCode.
Я попробовал ваш совет - настроил 2 обработчика.
First - это пользовательский обработчик, который перехватывает исключение NullReference. Затем создается новое исключение - MyApplicationException с полем MyFaultContract.
Затем я настроил второй обработчик - встроенный «обработчик исключений Fault Contract», который перехватывает MyApplicationException, создает новое FaultException и автоматически сопоставляет MyFaultcontract из MyApplicationException с вновь созданным FaultException.
Клиент WCF по-прежнему перехватывает общее исключение FaultException, а не пользовательское соглашение.