Управление / изменение ошибок десериализации / перехват ответов
Допустим, у меня есть следующий объект запроса:
[DataContract]
public class MyContract {
[DataMember]
public Guid Token { get; set; }
}
И определение службы WCF следующим образом:
[ServiceContract]
public interface IMyService {
[OperationContract]
bool Validate(MyContract request);
}
Если я отправлю следующую операцию, я получу желаемый ответ:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:esi="http://mynamespace.com/" xmlns:con="http://mynamespace.com">
<soapenv:Header>
</soapenv:Header>
<soapenv:Body>
<esi:Validate>
<esi:Token>9192ef6a-819f-4a8a-8fde-4125999e33dc</esi:Token>
</esi:Validate>
</soapenv:Body>
</soapenv:Envelope>
Если я отправляю неверный Guid (это происходит с любым типом), я получаю следующий ответ:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</faultcode>
<faultstring xml:lang="en-GB">The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.</faultstring>
</s:Fault>
</s:Body>
</s:Envelope>
Это все хорошо, но не достаточно информации для моих потребителей, учитывая, что мой сервис точно знает, что не так с данными.
Я могу выставить полное исключение с <serviceDebug includeExceptionDetailInFaults="true"/>
Настройка веб-конфигурации, но это СЛИШКОМ МНОГО информации для моих потребителей! Я бы предпочел настроить ошибку на уровне кода, но я не уверен, как я могу подключиться к десериализатору? Я знаю, как бороться с пользовательскими ошибками SOAP и FaultContracts, но это, кажется, на более низком уровне - мне нужно как-то перехватить входящее сообщение, прежде чем оно попадет в методы CLR? Есть ли способ сделать это, о котором я не знаю?
2 ответа
Десериализатор находится в IDispatchMessageFormatter
public class MyFormatter : IDispatchMessageFormatter
{
readonly IDispatchMessageFormatter _originalFormatter;
public MyFormatter(IDispatchMessageFormatter originalFormatter)
{
_originalFormatter = originalFormatter;
}
public void DeserializeRequest(Message message, object[] parameters)
{
try
{
_originalFormatter.DeserializeRequest(message, parameters);
}
catch(Exception ex)
{
//throw custom fault here
}
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
return _originalFormatter.SerializeReply(messageVersion, parameters, result);
}
Вы можете подключить это через OperationBehavior:
public class MyOperationBehavior : IOperationBehavior
{
public void Validate(OperationDescription operationDescription) { }
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.Formatter = new MyFormatter(dispatchOperation.Formatter);
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { }
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { }
}
Подключите OperationBehavior к вашим сервисным операциям через атрибут.
Если вам нужно использовать конфигурацию, присоедините их через ServiceBehavior или EndpointBehavior
Вы можете отлавливать ошибки и обрабатывать их, реализуя IErrorHandler.
Попробуйте прикрепить это к служебному поведению:
public class ServiceExceptionBehaviour : BehaviorExtensionElement, IServiceBehavior, IErrorHandler
{
//...
//implement all required methods
//...
}
Я предполагаю, что вы хотите преобразовать исключение, которое выдает десериализатор (при десериализации недействительного Guid), в надлежащую ошибку SOAP с правильным уровнем детализации. Здесь мне могут помочь две точки расширения - IErrorHandler ( http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.aspx) и FaultConverter ( http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.faultconverter.aspx). Не могу сказать вам по макушке, смогут ли они на самом деле делать то, что вы хотите, но я надеюсь, что это будет хорошей отправной точкой. Идея заключается в том, что вы получите возможность изучить все возникающие исключения и самостоятельно преобразовать их в ошибки, а не полагаться на ошибку по умолчанию.