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

时间:2014-04-24 17:03:12

标签: c# wcf faultexception ierrorhandler

我正在尝试在使用iis和net.tcp的WCF服务中实现IErrorHandler。

我设置了一个场景,在服务器中抛出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 个答案:

答案 0 :(得分:0)

ConsoleApplication1中的ServiceReference未更新且不包含错误契约属性。当您将.NET用于服务和客户端时,最好在它们之间共享DataContract和ServiceContract。

对于测试,您可以在ConsoleApplication1应用程序中引用WcfService1库。执行此操作时,请按照以下步骤操作:

  1. ConsoleApplication1中的app.config:

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

    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. 服务代码(我更喜欢捕获异常,尽可能接近代码,然后引发具体的错误异常):

    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. 您的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;
        }
    }
    
  5. P.S。您似乎错误地托管了您的服务。为了测试它,我在ConsoleApplication1中引用了WcfService1。并做了以下:

    1. 在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. 在客户打电话给服务之前,我已经开始服务了:

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