I'm wondering is there any way to handle deserialisation after changing a classes, namespace?
At the moment I'm having to do an edit replace on the text value of the XML replacing old namespace with new namespace.
Is there a better way to do this?
Always a tricky one. Unless you can guarantee that the class won't change, then it's probably best to find another approach to serializing.
However, to answer the question, you could have a Version property of the class (or put it in a base class if you have many). You'll need to remember to increment this whenever you change the class.
Then you could have a series of "migrations", which would know how to transform the XML from one version to the next. When you want to deserialize, first load the file as XML, apply the migrations in turn (as there may have been several changes since the file was created), and then deserialize the now transformed XML.
Related
I am using xml serialization and de-serialization to read and write to an XML file. Everything is working and I love it because I can access any data from the file via the single object that I generated.
However, I have to update certain element or remove it from my xml file. From reading around the site I think I can do this with Xpath or LINQ but I still like to do it via serialization due to the above reason. Is it possible? Does serialization mean to do this kind of logic? oh and I don't want to delete/recreate my file because it defeats the purpose of updating.
Changing it in the xml can be iffy, removing a node unless it's one of a collection, will almost certainly break it, and possibly even then. You might be able to get this to work but it will make your code extremely fragile, and could leave you with some horrendously difficult bugs.
Deserialise it. Change the property and serialise it again.
Or don't use serialisation to get your xml.
I'm using DataContractSerializer to serialize a class with DataContract and DataMember attributes to an XML file. My class could potentially change later, and thus the format of the serialized files could also change. I'd like to tag the files I'm saving with a version number so I at least know what version each file is from. I'm still deciding how and if I want to add functionality that will migrate files in older formats to later formats. But right now I'd be happy with just identifying a version mismatch.
Is the namespace of the XML file the correct place to store the version of the file? I was thinking of attributing my class with a DataContract attributes as follows.
[DataContract(Name="MyClass",Namespace="http://www.mycompany.com/MyProject/1.0
public class MyClass
...
Then later if MyClass changes I would change the namespace...
[DataContract(Name="MyClass",Namespace="http://www.mycompany.com/MyProject/2.0)]
public class MyClass
...
Is this the correct usage of XML namespaces, or is there another more prefered way to save the version of an XML file?
You can do it this way, but then the XML representation of your data becomes completely different from version to version from XML Infoset point of view (in which namespace is the part of the qualified name of the element), so you have neither backwards nor forwards compatibility.
Now, one advantage XML has is that it can be easily processed in a forward-compatible way with technologies such as XPath and XSLT - you just pick the elements you can interpret, and leave anything you don't recognize as is. But this requires elements with the same meaning to retain the same name (including namespace) between versions.
In general, it is best to make your schemas forward-compatible. If you can't achieve that, you might still want to provide as much compatibility as possible with existing tools (it is often easier to achieve compatibility against tools which only read data, rather than with those which also write it). Consequently, you avoid storing version number in such cases, and just try to parse whatever you're given, signalling an error if the input is definitely malformed.
If you come to the point where you absolutely must break compatibility in both directions and start from a clean slate, the suggested way of handling this for WCF data contracts is indeed by changing the namespace, as described in best practices on data contract versioning. There are a few minor variations there as well, such as using publication date instead of version number in the URL (W3C is quite fond of this for their schemas), but these are mostly stylistic.
Our system stores XML strings in a database. I've recently had to change the Properties on a Class, and now when an XML string gets deserialized it will throw an exception. What is the best way to handle this change? Look for the Node in the application code using XPATH or LINQ, or change the xml string in sql database (ie do a mass update)?.
You might want to look at writing a custom XML deserializer (i.e. implementing IXmlSerializable, see here) to handle changes in your XML. If you've invested a lot of time into crafting your XML serialization attributes, you may want to look at another approach.
Consider batch-upgrading your XML, or deprecating (instead of removing) properties inside of your classes and mapping older behavior to newer behavior.
Longer term, you will want to come up with a strategy for dealing with this in the future, since you will most likely be continue to make changes to your schema/object definitions as you add/change the functionality of your system.
if you serialize the objects to the database you could try the approach I outlined here to load the old versions into a new version then when you save the new version will be saved. Not sure if having different versions of your class will be appropriate though...
Basically you create a factory to produce your objects from the xml. everytime you change your object you create a new factory and a new object class, which is given a version of the old class in its constructor and it creates itself from the old class. The new factory tries to create a new object from the xml, if it can, happy days, if it can't then it creates a new object and tells the next oldest factory to create a next oldest object from the xml. These factories can then be chained together so that you can always load a newest version of the objects from whatever data is in the db.
This assumes that its possible to always create a valid v2 object from a v1 object.
It's a good practice to store a version along your XML strings. Either at the database level or at the class level so that your code knows which version of the class it has to deserialize.
You might also look at XSLT. It allows you to transform one version of XML into another.
In that case the logic to go from one version to another is not handle by code but by the XSLT. You can even store the XSLT into the database which makes it reusable by other programs.
It's ok if the answer to this is "it's impossible." I won't be upset. But I'm wondering, in making a game using C#, if there's any way to mimic the functionality of the "save state" feature of console emulators. From what I understand, emulators have it somewhat easy, they just dump the entire contents of the virtualized memory, instruction pointers and all. So they can resume exactly the same way, in the exact same spot in the game code as before. I know I won't be able to resume from the same line of code, but is there any way I can maintain the entire state of the game without manually saving every single variable? I'd like a way that doesn't need to be extended or modified every single time I add something to my game.
I'm guessing that if there is any possible way to do this, it would use a p/invoke...
Well, in C# you can do the same, in principle. It's called serialization. Agreed, it's not the exact same thing as a memory dump but comes close enough.
To mark a class as serializable just add the Serializable attribute to it:
[Serializable]
class GameState
Additional information regarding classes that might change:
If new members are added to a serializable class, they can be tagged with the OptionalField attribute to allow previous versions of the object to be deserialized without error. This attribute affects only deserialization, and prevents the runtime from throwing an exception if a member is missing from the serialized stream. A member can also be marked with the NonSerialized attribute to indicate that it should not be serialized. This will allow the details of those members to be kept secret.
To modify the default deserialization (for example, to automatically initialize a member marked NonSerialized), the class must implement the IDeserializationCallback interface and define the IDeserializationCallback.OnDeserialization method.
Objects may be serialized in binary format for deserialization by other .NET applications. The framework also provides the SoapFormatter and XmlSerializer objects to support serialization in human-readable, cross-platform XML.
—Wikipedia: Serialization, .NET Framework
If you make every single one of your "state" classes Serializable then you can literally serialize the objects to a file. You can then load them all up again from this file when you need to resume.
See ISerializable
I agree with the other posters that making your game state classes Serializable is probably the way you want to go. Others have covered basic serialization; for a high end alternative you could look into NHibernate which will persist objects to a database. You can find some good info on NHibernate at these links:
http://www.codeproject.com/KB/database/Nhibernate_Made_Simple.aspx
http://nhibernate.info/doc/burrow/faq
Is it possible to have any control over the class names that get generated with the .Net XSD.exe tool?
As far as I'm aware I don't think this is possible, the class names match almost exactly to whats in the schema.
Personally I would change the class names after XSD has generated the code, but to be honest I usually just stick with what XSD generates. Its then easier for someone else reading the code to understand what classes map to what parts of the XML.
Alternatively, if you have control over the schema you could update that?
Basically, no. If you were writing the classes manually, you could have:
[XmlType("bar")]
class Foo {}
however, you can't do this with the xsd-generated classes. Unfortunately, one of the things you can't do with a partial class is rename it. Of course, you could use xsd to generate it, change the .cs file and don't generate it again, but that is not ideal for maintenance.
Any schema with somewhat deep nesting then ends up with utterly useless names.
I don't know of a way to work around the problem, but my tip to at least reduce the negative impact is this: Define a list of aliases for the awfully-named types. This way you can write code that isn't completely unreadable without losing the ability to regenerate.
using AgentAddress = Example.Namespace.DataContract.RootElementNestedElementAgentAddress;
...
It's a pity this list itself has to be copy-pasted to all code files needing it, but I think this at least constitutes an improvement.