WCF FaultException IErrorHandler - не возвращается клиенту и вызывает исключение тайм-аута
Я пытаюсь реализовать IErrorHandler в службах WCF, которые используют iis и net.tcp.
Я установил сценарий, чтобы бросить DivideByZeroException на сервере. IErrorHandler запускается, как и ожидалось.
FaultException не возвращается клиенту, и я получаю исключение тайм-аута. Я не мог найти информацию / исключение в журнале событий.
Вот демонстрационный код. http://www.fileswap.com/dl/gQFlVsZK7M/ (Пожалуйста, нажмите на медленную загрузку изображения)
РЕДАКТИРОВАТЬ 1 (добавлен код из архива для всех, чтобы увидеть его):
Контракт на обслуживание:
[ServiceContract]
public interface IService1
{
[OperationContract]
[FaultContract(typeof(DivideByZeroException))]
string GetData(int value);
[OperationContract]
[FaultContract(typeof(DivideByZeroException))]
CompositeType GetDataUsingDataContract(CompositeType composite);
// TODO: Add your service operations here
}
Внедрение сервиса:
public class Service1 : IService1
{
public string GetData(int value)
{
int i = 0;
//division by zero!
int y = 10/i;
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
Реализация IErrorHandler:
public class WcfErrorHandler : IErrorHandler
{
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
var v = error as DivideByZeroException;
if (v != null)
fault = Message.CreateMessage(
version,
new FaultException<DivideByZeroException>(v, new FaultReason(v.Message)).CreateMessageFault(),
"http://the.fault.action");
}
public bool HandleError(Exception error)
{
return true;
}
}
1 ответ
Ваша ServiceReference в ConsoleApplication1 не обновляется и не содержит атрибут контракта ошибки. Поскольку вы используете.NET для службы и клиента, лучше делить DataContract и ServiceContract между ними.
Для теста вы можете ссылаться на библиотеку WcfService1 в вашем приложении ConsoleApplication1. Когда вы это сделаете, выполните следующие действия:
app.config в ConsoleApplication1:
<client> <endpoint address="net.tcp://localhost/WcfService1/Service1.svc" binding="netTcpBinding" contract="WcfService1.IService1" name="NetTcpBinding_IService2"> </endpoint> </client>
Код клиента:
try { var fact = new ChannelFactory<WcfService1.IService1>("NetTcpBinding_IService2"); var proxy = fact.CreateChannel(); var ves = proxy.GetData(1); Console.WriteLine(ves); } catch (FaultException<DivideByZeroException> exp) { Console.WriteLine(exp.Detail); }
Сервисный код (я предпочитаю перехватывать исключение как можно ближе к коду, вызывающему его, а затем выдает конкретное исключение ошибки):
public string GetData(int value) { try { int i = 0; int y = 10/i; return string.Format("You entered: {0}", value); } catch (DivideByZeroException d) { throw new FaultException<DivideByZeroException>(d); } }
Ваш IErrorHandler:
public class WcfErrorHandler : IErrorHandler { public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { if (error is FaultException) { //do nothing as it's already FaultException //you should do a transformation only in the case it's required } else { // Generate fault message manually including the exception as the fault detail MessageFault messageFault = MessageFault.CreateFault( new FaultCode("Sender"), new FaultReason(error.Message), error); fault = Message.CreateMessage(version, messageFault, null); } } public bool HandleError(Exception error) { //here you can log an exception return true; } }
PS Кажется, вы неправильно разместили свой сервис. Чтобы проверить это, я сослался на WcfService1 в ConsoleApplication1. И сделал следующее:
Добавлены такие строки в app.config ConsoleApplication1:
<services> <service name="WcfService1.Service1" behaviorConfiguration="CalculatorServiceBehavior"> <endpoint address="" binding="netTcpBinding" contract="WcfService1.IService1" /> <!--<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> --> <host> <baseAddresses> <add baseAddress="net.tcp://localhost/WcfService1/Service1.svc"/> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors> <behavior name="CalculatorServiceBehavior"> <serviceDebug includeExceptionDetailInFaults="True" /> <errorHandler /> </behavior> </serviceBehaviors> </behaviors> <extensions> <behaviorExtensions> <add name="errorHandler" type="WcfService1.ErrorHandlerExtension, WcfService1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> </behaviorExtensions> </extensions>
И прежде чем звонить в сервис клиенту, я запустил сервис:
private static void Main(string[] args) { var host = new ServiceHost(typeof(WcfService1.Service1)); host.Open(); ...