繁体   English   中英

WCF 反序列化中的 XmlException:“名称不能以 '<' 开头”- 在自动属性支持字段中

[英]XmlException in WCF deserialization: “Name cannot begin with '<'” - in automatic property backing fields

我今天开始在 WCF 反序列化中遇到错误 - 代码一直没有改变并且工作了几个月。

问题是我收到运行时XmlException说“名称不能以 '<' 字符开头”。 我已经调试到 .NET 源代码中,似乎错误在于从我们的 WCF 服务调用中反序列化返回对象。 这些对象是使用自动属性定义的,似乎支持字段的名称类似于<MyProperty>k_BackingField ,这是 XmlException 的来源。

我在网上看到了一些其他参考资料,其中人们接受的解决方案是“我更改了我的代码以不使用自动属性”,这对我来说并不是真正可以接受的,因为我将有 100 个对象要更改,(有 1000 个其中的属性)。 此外,当我上周运行它时,同样的代码运行良好,并且似乎不会影响所有序列化的 DTO,只有一些。

更令人沮丧的是,它似乎有点间歇性。 有时今天早上,没有异常抛出......!

问题;

  1. 为什么在不变的代码和不变的框架源码中突然出现这个问题?
  2. 如何在不修改所有 DTO 以使用完全实现的属性的情况下解决此问题?

更新:在正常工作一天左右后,这个问题再次出现 - 我没有理由找到为什么它会工作/不工作/再次工作,但我们在这里。

我已经使用ServiceKnownType属性进一步追踪了与我在 ServiceContracts 上的一些代码相关的问题,该属性用于定义已知的序列化类型。 似乎虽然报告有错误的类型甚至不是我当时所做的服务调用的一部分,但此错误发生在属于这种已知类型“发布”行为一部分的类型上。

当我使用一些代理创建代码来应用一些服务行为时出现问题;

IOperationBehavior innerBehavior = new PreserveReferencesOperationBehavior(
    description, this.preserveReferences, this.maxItemsInObjectGraph);
innerBehavior.ApplyClientBehavior(description, proxy);

我无法调试ApplyClientBehavior代码,因为它是System.ServiceModel一部分(或者我可以吗?),但该方法中的某些内容正在尝试验证我使用我的ServiceKnownType属性发布的所有类型,并使用此XmlException中断其中一些类型。 我不知道为什么某些类型会失败 - 并且仅针对它们的某些属性。

这是针对它们报告错误的类型的示例;

[Serializable]
public class MyDataObject
{
    public ActivitySession(string id)
    {
        this.Id = id;
        this.IsOpen = true;
    }

    public string Id { get; set; }

    public bool IsValid { get; set; }
}

异常针对Id报告错误 -> <Id>k_BackingField cannot start with '<'

所以在那个类中没有什么有争议的,也不需要考虑继承。 它甚至不是服务合同的一部分,只是它以前作为已知的序列化类型发布。

这现在变得非常深奥,所以我不期待答案,而只是更新问题所在。

我想我找到了更多信息来帮助解释这个问题,(至少就错误仅出现在某些类型上的原因而言)。

收到针对他们报告的例外情况的 DTO 是;

  • 作为我的[ServiceKnownType]属性的一部分发布
  • 标有[Serializable]
  • 标有[DataContract]

[DataContract]属性添加到类型可解决此问题。 我不知道为什么,仍然不知道为什么这个错误是它发生在间歇性的,但的影响是一致的。

我也看了这个问题: WCF 服务参考 - 在客户端获取“XmlException: Name cannot begin with the '<' character, hexadecimal value 0x3C”

关于这个例外:

System.Xml.XmlException: '名称不能以 '<' 字符开头,十六进制值 0x3C。

  1. 检查您是否加载了任何有效的 xml 文件(例如,不要包含诸如 < 或 > 之类的拼写错误)
  2. 如果您使用的是服务 + WCF,请查看您的服务接口(与 ServiceContract 的接口)。 这将是一个很好的起点。 现在检查接口的方法中是否有任何 DTO 参数。 转到这些 DTO 并查看这些 DTO 类是否具有 [Serializable] 或 [DataContract] 或类似的属性。 如果这些类还包含自动属性,请将它们的属性更改为具有您自己的支持字段的符号,例如:

    私人 Foo _Bar; 公共 Foo Bar { get { return _Bar; } 设置 { _Bar = 值; } }

如果幸运的话,您会看到错误消失了! 自动属性似乎存在问题,其中自动生成的支持字段的名称类似于例如<>something<>d_whatever或类似的名称。 这些名称以 '<' 字符开头,从而导致该错误。

在服务和 WCF 的情况下,您的服务接口和回调(带有数据契约)是开始替换自动属性的好地方。 至少它让您知道从哪里开始而不是替换数千个自动属性。

此外,尝试通过在应用程序的开头添加此代码并将消息写入控制台来捕获 FirstChanceExceptions。 这将有助于查看“名称不能以 '<' 字符开头”消息的数量是否减少。

AppDomain.CurrentDomain.FirstChanceException += (object source, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e) => { Console.WriteLine("FirstChanceException 事件在 {0} 中引发:{1}", AppDomain.CurrentDomain.FriendlyName, e.Exception 。信息); };

https://docs.microsoft.com/en-us/dotnet/framework/app-domains/how-to-receive-first-chance-exception-notifications

这是我目前发现的。 希望能帮助到你。

我现在有一个解决方法,但它不是我可以依赖的东西 -> 导致问题的 DTO 已从[ServiceKnownType]发布者中删除,这使得错误消失。

我想知道问题是否与我遇到异常的成员名称有关。 到目前为止,我已经看到它抱怨;

  • Id
  • Address
  • UserName

我猜,期望这些特定的属性名称在序列化或服务模型的其他地方使用是合理的,导致它们以不同的方式编译。

我今天遇到了这个问题(第一次机会例外,否则没有明显问题)。 就我而言,NetDataContractSerializer (NDCS) 正在序列化IFieldData[] (来自CSLA.NET 库)。 NDCS 可以序列化数组,也可以序列化没有应用[DataContract]属性的对象。 在这种情况下,序列化程序会推断合同——所有公共读/写属性和类型的字段都被序列化。 它记录在这里: https : //docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-data-contracts

所以在我的例子中,数组中的一个对象有一个对Fraction (我自己的类)的引用,定义如下:

public sealed class Fraction
{
    public int Numerator { get; private set; }
    public int Denominator { get; private set; }
    public double Value { get; private set; }
}

它导致 WCF 抛出“名称无法开始...”异常,这是由于自动属性使用生成的名为<Numerator>k__BackingField私有字段<Numerator>k__BackingField 如果向类添加[DataContract]属性,则必须通过[DataMember]属性显式标记需要序列化的内容。 这使得异常消失。 序列化程序不再涉及私有字段。

在我看来,这是 WCF 中的一个错误。 推断的契约应该只使用类的公共表面,它没有任何命名问题。 它不应该窥探私有字段(编译器生成与否)。

我的回答支持/补充了RJ LohanjuFo之前所说的内容,我赞成他们的回答。

找出哪个字段给您带来问题的最佳方法是在出现错误时检查 StackTrace:

在此处输入图片说明

就我而言,答案是将 auto 属性更改为显式声明支持字段,以避免这种命名的可能性。 所以

public string ScreenName { get; set; }

变成:

private string _screenName;
public string ScreenName { get { return _screenName; } set { _screenName = value; } }

对于遇到此问题的其他任何人:如果您在 Visual Studio 的异常设置中检查了 XmlException,即使在 System.Runtime.Serialization 中处理异常,它也会抛出。 我花了大约 20 个小时试图弄清楚为什么当我打开所有异常时我的代码突然停止工作 - 这实际上不是一个致命的异常,它只是捕获了大约 1200 个 XmlExceptions。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM