3
votes

I'm working on a WCF service.

One of the OperationContracts requres a complex type as one of the parameters (System.Exception to be specific).

When the client calls the proxy if I create a new exception, eg.

 System.Exception toNewException = new Exception();

And send it... it works rather nicely.

But if i try to send an exception of type 'System.Web.HttpUnhandledException'. The service faults with an unknown type. (see error below)

There was an error while trying to serialize parameter http://tempuri.org/:Exception. The InnerException message was 'Type 'System.Web.HttpUnhandledException' with data contract name 'HttpUnhandledException:http://schemas.datacontract.org/2004/07/System.Web' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.

I've researched the known types attribute... but I have not found any examples or documentation so far that has helped.

Anyone know a good source for information on how I may be able to alter my client/server to accept/work with any kind of exception?

To make my question a little bit more detailed... The error states; 'Add any types not known statically to th elist of known types'. That is what I want to know how to do specifically for a complex .net object like system.exception.

Update

I tried making the following changes:

[OperationContract]
[ServiceKnownType(typeof(HttpUnhandledException))]
void LogError(Exception Exception, Boolean LogInternalFlag, int UserId, int ApplicationId, int SeverityId);

and I ended up getting another error!

There was an error while trying to serialize parameter http://tempuri.org/:Exception. The InnerException message was 'Type 'System.Collections.ListDictionaryInternal' with data contract name 'ArrayOfKeyValueOfanyTypeanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.

Atleast the error with the exception made sense... I'm not sure what this means at all.


I'm also going to throw in that I did try to serialize the exception as xml and passing it as a string... unfortunately thats not as simple as it may sound, and there are to many considerations to take into account for the serialization of the exception and any inner exceptions.

3
What you have tried adding to your web.config?ChrisBint
Why do you want to send exceptions? Did you look at FaultContracts that is normally the way of how to handle exceptions with WCF.Jason De Oliveira
@JasonDeOliveira It sounds like the OP is trying to pass an Exception as a parameter to this WCF service, and is having issues sending types that inherit from the type specified in the parm list...Nate
@Nate correct. I am passing exceptions as a parameter.Patrick

3 Answers

2
votes

Your problem isn’t that the type is complex. Your problem is that your contract was declared with a base class (Exception) and you passed in a child class (HttpUnhandledException). You didn't give the contract serializer any type information for what the child added to the base definition. You provide that extra information through KnownTypes.

The best documentation I’ve seen on KnowTypes on MSDN is here.

What you are missing in your search is that since you only have a OperationContract (with no DataContract) the attribute you really want to use is ServiceKnownType.

[ServiceContract]
public interface IContract
{
   [OperationContract]
   [ServiceKnownType(typeof(HttpUnhandledException))]
   void PassException(Exception c);
}

You can put the attribute to just the method or the whole interface.

Note there is a version of ServiceKnownType (and KnowTypes) that takes a runtime method if you don’t know all the possible child (Exception) types at compile time.

1
votes

ErnieL has the correct technical answer. Pragmatically, however, I would be prone to either 1) break out the parts of the exception and pass only those along or 2) create your own custom ErrorLog type and send that.

This removes the need to handle subclassing of exception objects and gives you a consistent interface to work with. Likely, you only need a few members from the exception (error message, inner exception error message, and stack trace).

For inner exceptions, just write a method that loops through the message and concatenates them together. Do they really need to be stored separately?

1
votes

You could work around this by serializing your exception as a byte array, then deserializing it server-side.

Client side, you would use:

    try { /* Do something that generates an exception here. */ }
    catch(System.Exception exception)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            BinaryFormatter bf = new BinaryFormatter();
            bf.Serialize(ms, exception);
            YourWCFMethodHere(ms.ToArray());
        }
     }

and then on the server side:

    public void YourWCFMethodHere(byte[] exception)
    {
        using (MemoryStream ms = new MemoryStream(exception, false))
        {
            BinaryFormatter bf = new BinaryFormatter();
            Exception ex = (Exception)bf.Deserialize(ms);
            // Do something with the exception here
        }
    }

Of course, you'd want to put some error checking in place, just in case the byte[] passed in isn't actually an Exception.