0
votes

I am testing WCF for potentially implementing an API for remote controlling a device that runs our Controller-Software (C#/.Net 4.6.1) on Windows.

I am currently trying to figure out how to throw and catch a FaultException from my service and catch it from a .Net client.

The problem I am having is that when running the code (in Debug-mode on VS 2015), the exception is not caught by the client, but VS ends up showing me the exception inside VS at the code-location of the service (Service.cs), where it is being thrown. The exception message is:

An exception of type 'System.ServiceModel.FaultException`1' occurred in WcfService.dll but was not handled in user code

Additional information: The argument value was not 1

where The argument value was not 1 is the custom message provide by me. Here are the relevant parts of my code. I hope somebody can spot, what I am doing wrong:

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)] public class Service : IService { private string 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: public class Server { private ServiceHost svh; private Service service;

    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 (Test Program using the server and the client):

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();
    }
}
3

3 Answers

0
votes

If you generated your SOAP code from wsdl using vs tools then FaultException that is being thrown here is generic FaultException - meaning it is FaultException<fault_contract>. You what generic type exception that is by checking your service reference code and inspecting [System.ServiceModel.FaultContractAttribute()] attribute. This attribute has Type parameter which is you generic type.

So if you it looks something like this

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

then your catch clause should look like this

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

}
0
votes

I had his issue recently (if i understood correctly)

1) VS -> DEBUG -> Options and Settings -> Debugging -> General

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

2) DEBUG -> Exceptions and deselect the exceptions for common language runtime (both Thrown and user-unhandled) and try it again. If that solves the problem, you can seek which exception(s) you want to customize or just do this whenever testing exceptions across the AppDomain.

0
votes

Ok. I found the answer to my question by luck. The error was due to running my code in Debug mode in Visual Studio, where VS catches the exception the moment it is thrown. In order for it to work correctly you need to disable some settings. To do this go to Tools->Option->Debugging->General and remove the checkmarks:

  • Enable the exception assistant
  • Enable just my code

I found this solution here.