简体   繁体   English

WCF FaultException IErrorHandler-不返回客户端并导致超时异常

[英]WCF FaultException IErrorHandler - Not returning to client and causing timeout exception

I am trying to implement IErrorHandler in the WCF services that uses iis and net.tcp. 我正在尝试在使用iis和net.tcp的WCF服务中实现IErrorHandler。

I set a scenario to throw DivideByZeroException in the server. 我设置了一个方案以在服务器中引发DivideByZeroException。 IErrorHandler is firing as expected. IErrorHandler正在按预期触发。

The FaultException is not returning to client and I am getting timeout exception. FaultException没有返回到客户端,并且我收到超时异常。 I could not find any info/exception in event log also. 我也没有在事件日志中找到任何信息/异常。

Here is the demo code. 这是演示代码。 http://www.fileswap.com/dl/gQFlVsZK7M/ (Please click on slow download image) http://www.fileswap.com/dl/gQFlVsZK7M/ (请单击慢速下载图像)

EDIT 1 (added code from archive for all to see it): 编辑1(从存档中添加代码,以供所有人查看):

Service contract: 服务合同:

[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
}

Service Implementation: 服务实施:

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 implementation: 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;
    }
}

You ServiceReference in ConsoleApplication1 is not updated and does not contain fault contract attribute. ConsoleApplication1中的ServiceReference未更新,并且不包含故障契约属性。 As you use .NET for the service and client it's better to share DataContract and ServiceContract between them. 在将.NET用于服务和客户端时,最好在它们之间共享DataContract和ServiceContract。

For the test you can reference WcfService1 library in your ConsoleApplication1 application. 对于测试,您可以在ConsoleApplication1应用程序中引用WcfService1库。 When you do that, follow steps: 当您这样做时,请按照下列步骤操作:

  1. app.config in ConsoleApplication1: ConsoleApplication1中的app.config:

     <client> <endpoint address="net.tcp://localhost/WcfService1/Service1.svc" binding="netTcpBinding" contract="WcfService1.IService1" name="NetTcpBinding_IService2"> </endpoint> </client> 
  2. Client code: 客户代码:

     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); } 
  3. Service code (I prefer to catch exception as much closer to code causing it as possible and then throws a concrete fault exception): 服务代码(我更喜欢捕获异常,使其尽可能接近导致它的代码,然后引发具体的故障异常):

     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); } } 
  4. Your IErrorHandler: 您的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 It seems you have hosted your service incorrectly. PS看来您托管的服务不正确。 To test it, I've referenced WcfService1 in ConsoleApplication1. 为了测试它,我在ConsoleApplication1中引用了WcfService1。 And did following: 并执行以下操作:

  1. Added such lines into app.config of ConsoleApplication1: 在ConsoleApplication1的app.config中添加以下行:

     <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> 
  2. And before making a call to the service by client, I've started service: 在客户致电服务之前,我已经开始服务:

     private static void Main(string[] args) { var host = new ServiceHost(typeof(WcfService1.Service1)); host.Open(); ... 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM