【问题标题】:How to catch a custom FaultException in WCF如何在 WCF 中捕获自定义 FaultException
【发布时间】:2017-01-15 02:11:02
【问题描述】:

我正在测试 WCF 是否可能实现一个 API,以远程控制在 Windows 上运行我们的控制器软件 (C#/.Net 4.6.1) 的设备。

我目前正试图弄清楚如何从我的服务中抛出和捕获 FaultException,并从 .Net 客户端中捕获它。

我遇到的问题是,在运行代码时(在 VS 2015 的调试模式下),客户端没有捕获到异常,但 VS 最终在 VS 的代码位置向我显示了异常服务(Service.cs),它被抛出的地方。异常消息是:

“System.ServiceModel.FaultException`1”类型的异常发生在 WcfService.dll 中,但未在用户代码中处理

附加信息:参数值不是 1

The argument value was not 1 是我提供的自定义消息。这是我的代码的相关部分。我希望有人能发现我做错了什么:

IService.cs:

[ServiceContract(CallbackContract = typeof(IMyEvents))]
public interface IService
{
    [OperationContract]
    [FaultContract(typeof(InvalidValueFault))]
    string ThrowsFaultIfArgumentValueIsNotOne(int value);

    ...
}

[DataContract]
public class InvalidValueFault
{
    private string _message;

    public InvalidValueFault(string message)
    {
        _message = message;
    }

    [DataMember]
    public string Message { get { return _message; } set { _message = value; } }
}   

Service.cs: [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, InstanceContextMode = InstanceContextMode.Single)] 公共类服务:IService { 私有字符串 defaultString;

    public Service(string ctorTestValue)
    {
        this.defaultString = ctorTestValue;
    }

    public string ThrowsFaultIfArgumentValueIsNotOne(int value)
    {
        if (value == 1)
            return string.Format("Passed value was correct: {0}", value);

        // this is where the box with the exception is shown inside Visual Studio
        throw new FaultException<InvalidValueFault>(new InvalidValueFault("The argument value was not 1"), new FaultReason("The argument value was not 1"));
    }

    ...
}

Server.cs: 公共类服务器 { 私人服务主机 svh; 私人服务服务;

    public Server()
    {
        service = new Service("A fixed ctor test value that the service should return.");
        svh = new ServiceHost(service);
    }

    public void Open(string ipAdress, string port)
    {
        svh.AddServiceEndpoint(
        typeof(IService),
        new NetTcpBinding(),
        "net.tcp://"+ ipAdress + ":" + port);
        svh.Open();
    }

    public void Close()
    {
        svh.Close();
    }
}

Client.cs:

public class Client : IMyEvents
{
    ChannelFactory<IService> scf;
    IService s;

    public void OpenConnection(string ipAddress, string port)
    {
        var binding = new NetTcpBinding();

        scf = new DuplexChannelFactory<IService>(
        new InstanceContext(this),
        binding,
        "net.tcp://" + ipAddress + ":" + port);
        s = scf.CreateChannel();
    }

    public void CloseConnection()
    {
        scf.Close();
    }

    public string ThrowsFaultIfArgumentValueIsNotOne(int value)
    {
        try
        {
            return s.ThrowsFaultIfArgumentValueIsNotOne(value);
        }

        catch (System.ServiceModel.FaultException<InvalidValueFault> fault)
        {
            Console.WriteLine("Exception thrown by ThrowsFaultIfArgumentValueIsNotOne(2):");
            Console.WriteLine("Exception message: " + fault.Message);
            //throw;
            return "Exception happend.";
        }
    }

    ...
}

Program.cs(使用服务器和客户端的测试程序):

class Program
{
    static void Main(string[] args)
    {
        // start server
        var server = new Server();
        server.Open("localhost", "6700");
        Console.WriteLine("Server started.");

        var client = new Client();
        client.OpenConnection("localhost", "6700");

        Console.ReadLine();
        Console.WriteLine("Result for client.ThrowsFaultIfArgumentValueIsNotOne(1): {0}", client.ThrowsFaultIfArgumentValueIsNotOne(1));

        Console.ReadLine();
        Console.WriteLine("Result for client.ThrowsFaultIfArgumentValueIsNotOne(2): {0}", client.ThrowsFaultIfArgumentValueIsNotOne(2));

        Console.ReadLine();
        client.CloseConnection();
        Thread.Sleep(1000);
        server.Close();
    }
}

【问题讨论】:

    标签: c# .net wcf


    【解决方案1】:

    好的。我很幸运地找到了我的问题的答案。该错误是由于在 Visual Studio 中以调试模式运行我的代码,VS 在抛出异常时捕获了异常。为了使其正常工作,您需要禁用一些设置。为此,请转到 Tools-&gt;Option-&gt;Debugging-&gt;General 并删除复选标记:

    • Enable the exception assistant
    • Enable just my code

    我找到了这个解决方案here

    【讨论】:

      【解决方案2】:

      我最近遇到了他的问题(如果我理解正确的话)

      1) VS -> 调试 -> 选项和设置 -> 调试 -> 常规

      有 UNTICK 'Break when exceptions cross AppDomain...'

      2) DEBUG -> Exceptions 并取消选择公共语言运行时的异常(抛出的和用户未处理的),然后重试。如果这样可以解决问题,您可以查找要自定义的异常,或者在跨 AppDomain 测试异常时执行此操作。

      【讨论】:

      • 感谢您的回答。我刚刚找到了一个类似的解决方案并发布了我的答案。我也会试试你的,这似乎更有针对性。我发布的答案似乎就像用锤子拧螺丝一样。
      【解决方案3】:

      如果您使用 vs 工具从 wsdl 生成 SOAP 代码,那么这里抛出的 FaultException 是通用的 FaultException - 意味着它是 FaultException&lt;fault_contract&gt;。通过检查您的服务参考代码并检查[System.ServiceModel.FaultContractAttribute()] 属性,您可以了解什么是通用类型异常。此属性具有 Type 参数,它是您的泛型类型。

      所以如果你看起来像这样

      [System.ServiceModel.FaultContractAttribute(typeof(MyFaultContract)]
      [System.ServiceModel.OperationContractAttribute(Action = "SoapAction", ReplyAction = "*")]
      SoapResponse SoapAction(SoapRequest request);
      

      那么你的 catch 子句应该是这样的

      try {
          soapClient.SoapAction(new SoapRequest());
      }
      catch (FaultException<MyFaultContract> e) {
      
      }
      

      【讨论】:

      • 感谢您的回复。不幸的是,这不起作用,TBH 我不完全理解答案。在我最初的问题中,在尝试了各种方法后,我忘记(重新)添加客户端应该捕获的特定故障类型(我现在已经更正了)。我已经尝试过您添加[System.ServiceModel.OperationContractAttribute(Action = "ThrowsFaultIfArgumentValueIsNotOne", ReplyAction = "*")] 的建议,但这并没有帮助(老实说,我不明白它的作用——到目前为止我遇到的任何示例中都没有使用它)。还有其他建议吗?
      • @packoman 检查你的肥皂动作是否有[System.ServiceModel.FaultContractAttribute(typeof(MyFaultContract)] 属性?
      • 是的。我有这个属性。原来错误在别处。请参阅我的回答和@Kafros 的回答。再次感谢。
      猜你喜欢
      • 1970-01-01
      • 2013-04-09
      • 1970-01-01
      • 2011-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-13
      相关资源
      最近更新 更多