【问题标题】:Passing complex types via WCF using known types使用已知类型通过 WCF 传递复杂类型
【发布时间】:2012-06-22 16:06:05
【问题描述】:

我正在开发 WCF 服务。

其中一个 OperationContracts 需要一个复杂类型作为参数之一(具体为 System.Exception)。

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

 System.Exception toNewException = new Exception();

然后发送它......它工作得很好。

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

尝试序列化参数时出错 http://tempuri.org/:Exception。 InnerException 消息是“类型 带有数据合同名称的“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 消息是“类型 带有数据合同名称的“System.Collections.ListDictionaryInternal” 'ArrayOfKeyValueOfanyTypeanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' 预计不会。将任何静态未知的类型添加到列表中 已知类型 - 例如,通过使用 KnownTypeAttribute 属性 或者通过将它们添加到传递给的已知类型列表中 DataContractSerializer.'。有关详细信息,请参阅 InnerException。

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


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

【问题讨论】:

  • 您尝试将什么添加到您的 web.config 中?
  • 为什么要发送异常?您是否看过 FaultContracts,这通常是如何使用 WCF 处理异常的方式。
  • @JasonDeOliveira 听起来 OP 正在尝试将异常作为参数传递给此 WCF 服务,并且在发送从 parm 列表中指定的类型继承的类型时遇到问题...跨度>
  • @Nate 正确。我将异常作为参数传递。

标签: c# wcf


【解决方案1】:

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

我在 MSDN 上的 KnowTypes 上看到的最好的文档是 here

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

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

你可以把属性放在方法上,也可以放在整个接口上。

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

【讨论】:

  • 我正在为此努力,我想也许就是这样......但我在客户端上遇到了另一个错误......我用结果更新了我的 OP。
  • 这指出了为什么人们在合同中使用故障而不传递异常。异常具有包含“对象”的数据集合。同样的问题。 “对象”是最终的基类。您需要知道其中的实际内容并将其添加到已知类型列表中。我以前没有使用过 HttpUnhandledException。可能还有其他我不知道的收藏。您可以尝试调试会话以查看其中可能的类型或发布另一个问题。无论你做什么,它都不会是我认为“强大”的东西。
  • 我不希望它是任何“健壮的”异常的主要问题之一是它们具有内部异常的事实......这使得它们很难序列化。不幸的是,我来到一家没有错误记录功能的商店,我需要想出一个解决方案。我可以从没有 oa 问题的单个应用程序中记录它们……我希望将登录集中到我们所有应用程序都可以调用的一项服务中……不幸的是,我认为这不会像我想的那样成功就像由于物体的性质一样。
  • 如果这是您的用例,Jordan 有正确的想法。将有意义的信息放入 WCF 调用的数据传输对象中并不难。即使存储 Exception.ToString() 和一些基本的元数据(如时间和应用程序名称)也可能是一个很好的第一步。
【解决方案2】:

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

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

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

【讨论】:

  • 1) 是的...这将是最简单的部分,我过去也这样做过。 2)我通过这种方法完成了第一。我遇到的问题是实施。我有 5 个左右的中型到大型应用程序并不能很好地处理错误......(抛出 catch 抛出 catch 抛出 .. 最终导致用户收到系统错误)全局 asax 处理很棒......但我结束了多达 3 个级别的内部异常,所有这些异常都需要独立记录...
  • 将错误记录到数据库的类对象已经处理了这个问题......我宁愿传递一个对象并一次记录内部异常......而不是多次调用服务。 ..(我现在接受它可能不会那么简单)
【解决方案3】:

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

客户端,你会使用:

    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[] 实际上不是异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-06
    • 1970-01-01
    • 2011-01-19
    • 2011-02-20
    • 2013-07-08
    • 1970-01-01
    • 2013-10-18
    相关资源
    最近更新 更多