RJ Lohan
RJ Lohan

Reputation: 6527

XmlException in WCF deserialization: "Name cannot begin with '<'" - in automatic property backing fields

I have started experiencing errors in WCF deserialization today - in code which has been unchanged and working for months.

The issue is that I am getting runtime XmlExceptions saying 'Name cannot begin with the '<' character'. I have debugged into the .NET source, and it seems the error is in deserializing return objects from our WCF service calls. These objects are defined using automatic properties, and it seems the backing fields are given names like <MyProperty>k_BackingField, which is where the XmlException is coming from.

I've seen a couple of other references online where the solution people accept is "I changed my code to not use automatic properties", which isn't really acceptable to me, as I would have 100s of objects to change, (with 1000s of properties amongst them). Also, this same code was working fine when I ran it last week, and doesn't seem to affect all serialized DTOs, only some.

To make it even more frustrating, it seems mildly intermittent. On occasion this morning, there has been no exception thrown...!

Questions;

  1. Why has this problem suddenly appeared in unchanged code and unchanged framework source?
  2. How do I fix this without modifying all the DTOs to use fully implemented properties?

UPDATE: After a day or so of working fine, this issue has reappeared - no reason I can find why it would work/not work/work again, but here we are.

I have tracked the problem down further to be related to some code I have on my ServiceContracts using the ServiceKnownType attribute, which is used to define known types for serialization. It seems that although the types being reported with errors are not even part of the service call I am making at the time, that this error is occurring on types which are part of this known types 'publishing' behaviour.

The problem occurs when I use some proxy creation code to apply some service behaviours;

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

I cannot debug the ApplyClientBehavior code as it is part of System.ServiceModel (or can I?), but something in that method is trying to validate all types I have published using my ServiceKnownType attribute, and breaking on some of them with this XmlException. I have NO IDEA why some of the types are failing - and only for some of their properties.

This is an example of the types which are getting errors reported against them;

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

    public string Id { get; set; }

    public bool IsValid { get; set; }
}

The exception reported an error against Id -> <Id>k_BackingField cannot start with '<'

So nothing controversial in that class, and no inheritance to consider. It's not even part of a service contract, only it was previously published as a known type for serialization.

This is getting quite esoteric now, so I'm not expecting an answer, but just updating where the problem is at.

Upvotes: 12

Views: 4027

Answers (6)

fortyCakes
fortyCakes

Reputation: 233

For anyone else having this issue: If you have XmlException checked in Visual Studio's exception settings, it'll throw even if the exception will get handled in System.Runtime.Serialization. I spent a good 20 or so hours trying to work out why my code had suddenly stopped working when I turned on all exceptions - it wasn't actually a fatal exception, it was just ~1200 caught XmlExceptions.

Upvotes: 0

James Harcourt
James Harcourt

Reputation: 6399

The best way to figure out which field is giving you the problem is to inspect the StackTrace as the error comes up:

enter image description here

The answer, in my case, was to change the auto property to have explicitly declared backing fields to avoid the possibility of this naming. So

public string ScreenName { get; set; }

becomes:

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

Upvotes: 0

Tomas Karban
Tomas Karban

Reputation: 1174

I was hitting this issue today (first-chance exception, no apparent problem otherwise). In my case NetDataContractSerializer (NDCS) was serializing IFieldData[] (from CSLA.NET library). NDCS can serialize arrays, it is also able to serialize objects that don’t have [DataContract] attribute applied to it. In that case the serializer infers the contract – all public read/write properties and fields of the type are serialized. It is documented here: https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/using-data-contracts

So in my case, one of the objects in the array had a reference to Fraction (my own class) defined as follows:

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

It is causing WCF to throw the "Name cannot begin..." exception, which is caused by the fact that the automatic properties are using generated private fields named like <Numerator>k__BackingField. If you add [DataContract] attribute to the class, then you must explicitly mark what needs to be serialized by [DataMember] attribute. That makes the exception go away. The serializer is not touching the private fields anymore.

In my opinion, it is a bug in WCF. The inferred contract should be only using the public surface of the class, which does not have any naming problems. It should not be snooping on private fields (compiler-generated or not).

My answer supports/supplements what RJ Lohan and juFo said earlier and I upvoted their answers.

Upvotes: 0

juFo
juFo

Reputation: 18587

I looked at this question also: WCF Service Reference - Getting "XmlException: Name cannot begin with the '<' character, hexadecimal value 0x3C" on Client Side

regarding this exception:

System.Xml.XmlException: 'Name cannot begin with the '<' character, hexadecimal value 0x3C.'

  1. Check if you load any xml files that they are valid (e.g. do not contain typo's like < or >
  2. If you are using services + WCF, have a look at your Service interfaces (the interfaces with ServiceContract). This will be a good starting point. Now check to see if you have any DTO parameters in methods from the interface. Go to these DTO's and see if these DTO classes have [Serializable] or [DataContract] or similar attributes. If these classes also contain automatic properties, change them the properties to the notation with your own backing field like:

    private Foo _Bar; public Foo Bar { get { return _Bar; } set { _Bar = value; } }

If you are lucky you will see the errors go away! There seems to be a problem with automatic properties where the automatically generated backing field has a name similar to e.g. <>something, <>d_whatever or things like that. These names start with '<' character, resulting in that error.

In case of services and WCF, your service interfaces and callbacks (with datacontract) are a good place to start replacing the automatic properties. At least it gives you an idea where to start instead of replacing thousands of automatic properties.

Additionally try to catch FirstChanceExceptions by adding this code at the start of your application and write the messages to the console. This will help a lot to see if the number of "Name cannot begin with the '<' character" messages is reduced or not.

AppDomain.CurrentDomain.FirstChanceException += (object source, System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e) => { Console.WriteLine("FirstChanceException event raised in {0}: {1}", AppDomain.CurrentDomain.FriendlyName, e.Exception.Message); };

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

This is what I found so far. Hope it helps.

Upvotes: 1

RJ Lohan
RJ Lohan

Reputation: 6527

I think I have found more information to help explain this issue, (at least in so far as why the error is appearing on certain types only).

The DTOs which are getting exceptions reported against them are;

  • published as part of my [ServiceKnownType] attribute
  • marked with [Serializable]
  • NOT marked with [DataContract]

Adding the [DataContract] attribute to the type resolves this issue. I have no idea why, and still no idea why this error is intermittent in when it happens, but consistent in what it affects.

Upvotes: 12

RJ Lohan
RJ Lohan

Reputation: 6527

I have a workaround in place now, however it's not something I can rely on -> the DTOs which are causing the problem have been removed from the [ServiceKnownType] publisher, which makes the error go away.

I'm wondering if the problem is to do with the member names I am getting exceptions on. So far I have seen it complain about;

  • Id
  • Address
  • UserName

It would be reasonable to expect those particular property names are in use somewhere else in the serialization or service model, causing them to be compiled differently, I guess.

Upvotes: 0

Related Questions