12

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

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

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

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

问题;

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

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

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

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

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

我无法调试ApplyClientBehavior代码,因为它是System.ServiceModel(或者我可以吗?)的一部分,但该方法中的某些内容试图验证我使用我的ServiceKnownType属性发布的所有类型,并使用 this 打破其中一些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 '<'

因此,在该类中没有任何争议,也无需考虑继承。它甚至不是服务合同的一部分,只是它以前作为序列化的已知类型发布。

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

4

6 回答 6

10

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

收到异常报告的 DTO 是:

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

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

于 2012-12-19T02:13:24.557 回答
1

我还查看了这个问题:WCF 服务参考 - 在客户端获取“XmlException:名称不能以 '<' 字符开头,十六进制值 0x3C”

关于这个例外:

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

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

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

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

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

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

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

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

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

于 2018-07-06T14:24:44.020 回答
0

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

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

  • Id
  • Address
  • UserName

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

于 2012-12-19T00:53:18.693 回答
0

我今天遇到了这个问题(第一次机会例外,否则没有明显的问题)。就我而言,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 抛出“名称无法开始...”异常,这是由于自动属性使用生成的名为 like 的私有字段这一事实引起的<Numerator>k__BackingField。如果[DataContract]向类添加属性,则必须显式标记需要按[DataMember]属性序列化的内容。这使得异常消失。序列化程序不再接触私有字段。

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

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

于 2019-01-23T15:03:25.273 回答
0

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

在此处输入图像描述

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

public string ScreenName { get; set; }

变成:

private string _screenName;
public string ScreenName { get { return _screenName; } set { _screenName = value; } }
于 2019-07-25T09:54:03.630 回答
0

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

于 2020-07-02T12:17:11.747 回答