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

Posted

技术标签:

【中文标题】WCF 反序列化中的 XmlException:“名称不能以 \'<\' 开头”-在自动属性支持字段中【英文标题】:XmlException in WCF deserialization: "Name cannot begin with '<'" - in automatic property backing fieldsWCF 反序列化中的 XmlException:“名称不能以 '<' 开头”-在自动属性支持字段中 【发布时间】:2012-12-04 02:21:36 【问题描述】:

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

问题是我在运行时 XmlExceptions 说“名称不能以 '<MyProperty>k_BackingField,这就是 XmlException 的来源。

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

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

问题;

    为什么在未更改代码和未更改框架源时会突然出现此问题? 如何在不修改所有 DTO 以使用完全实现的属性的情况下解决此问题?

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

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

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

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报错->&lt;Id&gt;k_BackingField cannot start with '&lt;'

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

现在这个问题越来越深奥了,所以我不期待答案,只是更新问题所在。

【问题讨论】:

你能发布一个示例数据合同吗? 我将尝试将其进一步隔离到问题发生的位置。目前决定再开工了……:-( 已将此问题更新为最新版本,因为该问题再次出现。我进一步隔离了为什么某些类型被报告为错误... 【参考方案1】:

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

收到异常报告的 DTO 是:

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

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

【讨论】:

如果碰巧能帮助到其他人,这是我想出的最好的解决方案,虽然我仍然没有解释,所以我很乐意接受更好的答案。 非常感谢这个技巧;刚刚为我节省了很多时间。我的 DTO 从不标有 [DataContract] 属性,并且它工作了好几个月。有一天,我不得不重新启动它,突然就遇到了这个问题。添加属性立即解决它。 这对我帮助很大。在我的例子中,我的一个基类没有用 [DataContract] 属性修饰。 在添加[DataContract]属性后,请务必在[DataMember]属性中标记需要序列化的内容。否则什么都不会被序列化,并且对象被反序列化为空白。【参考方案2】:

我也看过这个问题:WCF Service Reference - Getting "XmlException: Name cannot begin with the '<' character, hexadecimal value 0x3C" on Client Side

关于这个例外:

System.Xml.XmlException: '名称不能以 '

    检查您是否加载了任何有效的 xml 文件(例如,不包含诸如 之类的错字

    如果您使用的是服务 + WCF,请查看您的服务接口(带有 ServiceContract 的接口)。这将是一个很好的起点。现在检查接口的方法中是否有任何 DTO 参数。转到这些 DTO 并查看这些 DTO 类是否具有 [Serializable] 或 [DataContract] 或类似属性。如果这些类还包含自动属性,请将它们的属性更改为使用您自己的支持字段的表示法,例如:

    私人 Foo _Bar; 公共 Foo Bar 获取 返回 _Bar; 设置 _Bar = 值;

如果幸运的话,您会看到错误消失! 自动属性似乎存在问题,其中自动生成的支持字段的名称类似于例如somethingd_whatever 或类似的东西。这些名称以“

对于服务和 WCF,您的服务接口和回调(使用 datacontract)是开始替换自动属性的好地方。至少它让您知道从哪里开始,而不是替换数千个自动属性。

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

AppDomain.CurrentDomain.FirstChanceException += (对象源,System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)=> Console.WriteLine("0 中引发的 FirstChanceException 事件:1", AppDomain.CurrentDomain.FriendlyName, e.Exception.Message); ;

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

这是我目前发现的。希望对您有所帮助。

【讨论】:

【参考方案3】:

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

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

Id Address UserName

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

【讨论】:

结果可能不是 - 尝试重命名其中一些字段并在“MyId”、“BogusAddress”、“UserNameX”中遇到同样的问题。问题当然与类型有关 - 它不喜欢 some 类型中的 some 名称,无论名称是什么......!【参考方案4】:

我今天遇到了这个问题(第一次机会例外,否则没有明显问题)。在我的例子中,NetDataContractSerializer (NDCS) 正在序列化IFieldData[](来自CSLA.NET library)。 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 抛出“名称无法开始...”异常,这是由于自动属性正在使用生成的私有字段,例如 &lt;Numerator&gt;k__BackingField。如果在类中添加[DataContract] 属性,则必须通过[DataMember] 属性显式标记需要序列化的内容。这使得异常消失。序列化程序不再接触私有字段。

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

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

【讨论】:

【参考方案5】:

找出问题所在字段的最佳方法是在出现错误时检查 StackTrace:

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

public string ScreenName  get; set; 

变成:

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

【讨论】:

【参考方案6】:

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

【讨论】:

以上是关于WCF 反序列化中的 XmlException:“名称不能以 '<' 开头”-在自动属性支持字段中的主要内容,如果未能解决你的问题,请参考以下文章

WCF 服务参考 - 在客户端获取“XmlException:名称不能以 '<' 字符开头,十六进制值 0x3C”

WCF XML反序列化不填充数组

使用 WCF 反序列化 XML 字符串

关于调试WCF时引发的异常XmlException: Name cannot begin with the '<' character, hexadecimal value 0x

WCF 无法反序列化 JSON 请求

如何设置 WCF 自定义反序列化错误消息