1

我正在尝试在使用 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;
    }
}
4

1 回答 1

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

PS 看来您的服务托管不正确。为了测试它,我在 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();
       ... 
    
于 2014-04-24T18:52:27.753 回答