3

我正在开发 WCF 服务。

OperationContracts 之一要求将复杂类型作为参数之一(具体为 System.Exception)。

当我创建一个新的异常时客户端调用代理,例如。

 System.Exception toNewException = new Exception();

并发送它......它工作得很好。

但是,如果我尝试发送“System.Web.HttpUnhandledException”类型的异常。服务故障类型未知。(见下面的错误)

尝试序列化参数 http://tempuri.org/:Exception时出错。InnerException 消息是 'Type 'System.Web.HttpUnhandledException' 与数据协定名称 'HttpUnhandledException:http://schemas.datacontract.org/2004/07/System.Web' 不是预期的。将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。有关更多详细信息,请参阅 InnerException。

我已经研究了已知的类型属性......但到目前为止我还没有找到任何有帮助的示例或文档。

任何人都知道有关我如何能够更改我的客户端/服务器以接受/处理任何类型的异常的信息的良好来源?

为了让我的问题更详细一点......错误状态;'将任何静态未知的类型添加到已知类型的列表中'。这就是我想知道如何专门为像 system.exception 这样的复杂.net 对象做的事情。

更新

我尝试进行以下更改:

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

我最终得到了另一个错误!

尝试序列化参数 http://tempuri.org/:Exception时出错。InnerException 消息是 'Type 'System.Collections.ListDictionaryInternal' 与数据协定名称 'ArrayOfKeyValueOfanyTypeanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' 不是预期的。将任何静态未知的类型添加到已知类型列表中 - 例如,通过使用 KnownTypeAttribute 属性或将它们添加到传递给 DataContractSerializer 的已知类型列表中。有关更多详细信息,请参阅 InnerException。

至少有异常的错误是有道理的......我完全不确定这意味着什么。


我还要说明一下,我确实尝试将异常序列化为 xml 并将其作为字符串传递......不幸的是,这并不像听起来那么简单,并且有很多考虑因素需要考虑到序列化异常和任何内部异常。

4

3 回答 3

2

您的问题不在于类型复杂。您的问题是您的合同是使用基类(异常)声明的,并且您传入了一个子类(HttpUnhandledException)。您没有为合同序列化程序提供任何关于孩子添加到基本定义的类型信息。您通过 KnownTypes 提供额外的信息。

我在 MSDN 上的 KnowTypes 上看到的最好的文档在这里

您在搜索中缺少的是,由于您只有一个 OperationContract(没有 DataContract),因此您真正想要使用的属性是ServiceKnownType

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

您可以将属性仅用于方法或整个接口。

请注意,如果您在编译时不知道所有可能的子(异常)类型,则有一个 ServiceKnownType(和 KnowTypes)版本采用运行时方法。

于 2012-06-22T18:37:35.903 回答
1

您可以通过将异常序列化为字节数组,然后在服务器端反序列化来解决此问题。

客户端,您将使用:

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

然后在服务器端:

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

当然,您需要进行一些错误检查,以防传入的 byte[] 实际上不是异常。

于 2013-04-05T19:54:01.263 回答
1

ErnieL 有正确的技术答案。然而,实际上,我倾向于 1) 分解异常的部分并仅传递那些部分,或者 2) 创建您自己的自定义 ErrorLog 类型并发送它。

这消除了处理异常对象的子类化的需要,并为您提供了一个一致的接口来使用。很可能,您只需要异常中的几个成员(错误消息、内部异常错误消息和堆栈跟踪)。

对于内部异常,只需编写一个循环消息并将它们连接在一起的方法。它们真的需要分开存放吗?

于 2012-06-22T20:02:02.260 回答