So I ran into an annoying problem today with an entity that has a timestamp. When imported LINQ to SQL will create a Binary type for this the timestamp and as it turns out this type does not serialize via XML. This means ASMX Web services fail as well as plain old XmlSerializer style serialization. You’ll get:
System.Data.Linq.Binary cannot be serialized because it does not have a parameterless constructor.
Uh, how can you build a new type for a data component that doesn’t serialize natively?
The only reason I use a timestamp field in the first place is to facilitate updates with LINQ to SQL especially in some disconnected scenarios. Without time stamps many update scenarios send all the data back in the Where clause every time and some disconnected updates don’t work altogether (with invalid results) unless a timestamp is present. That’s scary enough as it is without the serialization problems.
I ran into this while working on my side project – CodePaste.net - and providing a general mechanism to retrieve content using various output mechanisms. Basically most Urls on the site can be accessed with a ?format=json/format=xml/format=rss/format=atom and retrieve that data. Json worked fine I figured xml would be a no-brainer but due to this little SNAFU the xml serialization is not working.
Workarounds
The easiest and most cases most practical solution is to make the timestamp internal:
And this indeed does the trick. This hides the property from the XmlSerializer so serialization works properly for Web Services and plain ole’ XML Serialization.
However, this may cause some other problems as it hides the timestamp from other code that might access it. If you were using a timestamp to do possible disconnected entity updates then hiding the timestamp in this way may not allow you to pass the change status around with the entity.
Another example, and one I ran into in my business object framework: I check for the tstamp field to detect a new value vs. an update:
if (this.TableInfo.VersionField != null)
{
object tstamp = entity.GetType()
.GetProperty(this.TableInfo.VersionField)
.GetValue(entity, null);
IsNew = tstamp == null;
}
else // try to do it off the PK field
{
object pkVal = entity.GetType().GetProperty(this.TableInfo.PkField).GetValue(entity, null);
IsNew = this.IsPkEmpty(pkVal);
}
which now fails, because the timestamp is internal and the business framework lives in a different assembly which now no longer can see the timestamp property.
This can be fixed with with this code:
object tstamp = entity.GetType()
.GetProperty(this.TableInfo.VersionField,BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(entity, null);
but this is problematic if you happen to run this code in a low trust environment that doesn’t support private Reflection (although it does appear to work in Medium trust for Web apps).
I tweeted this on Twitter and a number of folks suggested using [XmlIgnore] to get around the serialization issue, but since the entity is generated by LINQ to SQL designer I don’t think there’s a way to inject the [XmlIgnore] attribute. If anybody sees a better solution than the Internal switch I’d love to hear it.
Other Posts you might also like