6

I have been looking everywhere to find out how to catch a base fault contract type in c#. I would like to have all my fault contracts inherit from one class and have one catch(FaultException fex) in the MVC controller.

DataContracts

[DataContract]
public class BaseClass1 
{ }

[DataContract]
public class Class2 : BaseClass1 
{ }

Service

[ServiceContract]
public interface IService1
{
    [OperationContract]
    [FaultContract(typeof(BaseClass1))]
    [FaultContract(typeof(Class2))]  //Do I need this one?
    void ThrowClass2();
}

public class Service1 : IService1
{
    public void ThrowClass2()
    {
        throw new FaultException<Class2>(new Class2(), "Class2 Reason");
    }
}

Service Consumer

FaultTestService.Service1Client client = null;
try
{
    client = new FaultTestService.Service1Client();
    client.ThrowAmpFaults("InvalidParameter", 0);
}
catch (FaultException<Namespace.BaseClass1> fex)
{
    //DOES NOT GO IN HERE AS I WOULD EXPECT   
}
catch (FaultException fex)
{
    //Other Possible Option
    MessageFault fault = fex.CreateMessageFault();  
    var fe1 = fault.GetDetail<BaseClass1>();
    //This throws a serialization exception it needs <Class2>
}

Please let me know if either of these catch statements can be fixed to do what I am looking for.

ca_allicat
  • 81
  • 1
  • 5

3 Answers3

5

That syntax will not work in C#. Consider the folowing "workaround" instead.

try
{
    throw new FaultException<DerivedClass2>(new DerivedClass2());
}
catch (FaultException fex)
{
    bool handled = false;
    Type fexType = fex.GetType();
    if (fexType.IsGenericType && fexType.GetGenericTypeDefinition() == typeof(FaultException<>))
    {
        if (typeof(BaseClass1).IsAssignableFrom(fexType.GetGenericArguments()[0]))
        {
            object detail = fexType.GetProperty("Detail").GetValue(fex, null);

            // Use detail here.

            handled = true;
        }
    }

    if (!handled)
        throw; // Don't know how to handle. Re-throw.
}

This can be simplified if we disregard the unusual case where Detail == null but the constructed generic type matches. I'll also use the C# dynamic keyword to simplify it a little further.

try
{
    throw new FaultException<DerivedClass2>(new DerivedClass2());
}
catch (FaultException fex)
{
    bool handled = false;
    Type fexType = fex.GetType();
    if (fexType.IsGenericType && fexType.GetGenericTypeDefinition() == typeof(FaultException<>))
    {
        object detail = ((dynamic)fex).Detail;
        if (detail is BaseClass1) // true for subclasses too!
        {
            // Use detail here.
        }

    }

    if (!handled)
        throw; // Don't know how to handle. Re-throw. 
}

The other thing to consider is whether you should just use throw new FaultException<BaseClass1>(new DerivedClass2()). This way of throwing will let you catch using the code you originally provided.

Jason Kresowaty
  • 16,105
  • 9
  • 57
  • 84
2

Sorry, there is no way to do this. There is no relationship between FaultException<T1> and FaultException<T2> simply because T1 may be a subclass of T2.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
0

Your client needs a message inspector. We had a similar situation where the server was throwing various exceptions and they all ended up as a FaultException.

Community
  • 1
  • 1
Tangurena
  • 2,121
  • 1
  • 22
  • 41