我今天开始遇到WCF反序列化中的错误 - 代码已经保持不变并且工作了几个月。
问题是我得到运行时XmlException
说'名字不能以'&lt;'开头字符'。我已经调试到.NET源代码,似乎错误是从WCF服务调用反序列化返回对象。这些对象是使用自动属性定义的,并且支持字段的名称似乎是<MyProperty>k_BackingField
,这是XmlException的来源。
我在网上看到了其他一些人们接受的解决方案是“我将我的代码更改为不使用自动属性”,这对我来说是不可接受的,因为我会有100个对象需要更改, (其中有1000个属性)。此外,当我上周运行它时,同样的代码工作正常,并且似乎不会影响所有序列化的DTO,只有一些。
为了让它更令人沮丧,它似乎有点间歇性。今天早上有时候没有例外......!
问题;
更新经过一天工作正常后,这个问题又重新出现了 - 没有理由我可以找到它为什么会再次工作/不工作/工作,但我们就是这样。
我已经进一步跟踪问题,使用ServiceKnownType
属性与我在ServiceContracts上的一些代码相关,该属性用于定义序列化的已知类型。似乎虽然报告错误的类型甚至不是我当时正在进行的服务调用的一部分,但是这种错误发生在类型上,这些类型是这种已知类型的“发布”行为的一部分。
当我使用某些代理创建代码来应用某些服务行为时会出现问题;
IOperationBehavior innerBehavior = new PreserveReferencesOperationBehavior(
description, this.preserveReferences, this.maxItemsInObjectGraph);
innerBehavior.ApplyClientBehavior(description, proxy);
我无法调试ApplyClientBehavior
代码,因为它是System.ServiceModel
的一部分(或者我可以?),但该方法中的某些内容正在尝试使用我的{{1}来验证我发布的所有类型}属性,并使用此ServiceKnownType
打破其中一些属性。我没有IDEA为什么有些类型失败 - 而且只有某些属性。
这是针对它们报告错误的类型的示例;
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; }
}
- &gt;的错误Id
因此,在该课程中没有任何争议,也没有需要考虑的继承。它甚至不是服务合同的一部分,只是它以前作为序列化的已知类型发布。
现在这已经变得非常深奥了,所以我不期待答案,只是更新问题所在。
答案 0 :(得分:10)
我认为我已经找到了更多信息来帮助解释这个问题,(至少就错误仅出现在某些类型上的原因而言)。
正在获得针对他们报告的异常的DTO是;
[ServiceKnownType]
属性[Serializable]
[DataContract]
将[DataContract]
属性添加到该类型可解决此问题。我不知道为什么,并且仍然不知道为什么发生时这个错误是间歇性的,但是它会影响什么。
答案 1 :(得分:1)
关于此例外情况:
System.Xml.XmlException:'名称不能以'<'字符开头, 十六进制值0x3C。'
如果您使用服务+ WCF,请查看您的Service接口(与ServiceContract的接口)。这将是一个很好的起点。现在,检查接口的方法中是否有任何DTO参数。转到这些DTO,看看这些DTO类是否具有[Serializable]或[DataContract]或类似的属性。如果这些类还包含自动属性,请使用您自己的后备字段将其属性更改为表示法,例如:
私人Foo _Bar; 公共Foo Bar {get {return _Bar; }设置{_Bar =值; }}
如果幸运的话,您会看到错误消失了! 自动属性似乎存在问题,其中自动生成的后备字段的名称类似于例如 <>某物, <> d_whatever 或类似的东西。这些名称以“ <”字符开头,从而导致该错误。
对于服务和WCF,服务接口和回调(带有datacontract)是开始替换自动属性的好地方。至少它为您提供了一个起点,而不是替换成千上万的自动属性。
另外尝试通过在应用程序的开头添加此代码来捕获FirstChanceExceptions并将消息写入控制台。 这将有助于了解“名称不能以'<'字符开头”消息的数量是否减少。
AppDomain.CurrentDomain.FirstChanceException + = (对象源,System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)=> { Console.WriteLine(“在{0}中引发的FirstChanceException事件:{1}”, AppDomain.CurrentDomain.FriendlyName,e.Exception.Message); };
这是我到目前为止发现的。希望对您有所帮助。
答案 2 :(得分: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抛出“名称无法开始...”异常,这是由于自动属性正在使用名为<Numerator>k__BackingField
的生成的私有字段引起的。如果将[DataContract]
属性添加到该类,则必须显式标记[DataMember]
属性需要序列化的内容。这使异常消失了。序列化程序不再接触私有字段。
我认为这是WCF中的错误。推断的合同应仅使用类的公共表面,而没有任何命名问题。它不应在私有字段(无论是否由编译器生成)上监听。
答案 3 :(得分:0)
弄清楚哪个字段给您带来问题的最佳方法是在出现错误时检查StackTrace:
在我的情况下,答案是将auto属性更改为已明确声明了后备字段,以避免这种命名的可能性。所以
public string ScreenName { get; set; }
成为:
private string _screenName;
public string ScreenName { get { return _screenName; } set { _screenName = value; } }
答案 4 :(得分:0)
对于任何其他遇到此问题的人:如果在Visual Studio的异常设置中检查了XmlException,则即使将在System.Runtime.Serialization中处理该异常,它也会引发。我花了大约20个小时的时间来弄清楚为什么在打开所有异常时我的代码突然停止工作-这实际上不是致命的异常,只是〜1200个被捕获的XmlExceptions。