Default entries on a first time creation for a serialized class - c#

I have a class I am using for serializing various configuration options for an application I am working on. I'm adding a new property to the class that is a List, and I'd like it to fill this list if it does not exist already in a XML file. My first thought was to check if the list contained zero items, however this is not acceptable because there are times I want to have zero items in the list. In essence I want a file that has been serialized with an older version of the same class to be "upgraded" and have defaults automatically inserted for new properties. How can I do this? For a more visual example of what I'm trying to do, see below:
When I deserialize an XML file that contains:
<Item1>wtfe</Item1>
<Item2>wtfe</Item2>
and after I've added a list property it will serialze as:
<Item1>wtfe</Item1>
<Item2>wtfe</Item2>
<Item3/>
I want it to serialize as:
<Item1>wtfe</Item1>
<Item2>wtfe</Item2>
<Item3>
<DefaultSubItem/ Field="wtfe">
<DefaultSubItem/ Field="wtfe">
</Item3>
But allow me to change it to:
<Item1>wtfe</Item1>
<Item2>wtfe</Item2>
<Item3></Item3>

Another option may be to use these attributes:
[OnSerializing()]
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.onserializingattribute.aspx
[OnDeserializing()]
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.ondeserializingattribute.aspx

I think your looking for the SerializationBinder class:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationbinder%28VS.71%29.aspx

Related

Sitecore - Programatically modify the source field of a template

Currently, all the templates that we have created have source fields whose path is a string.
e.g. :
"sitecore/content/Test"
Now if I want to move the Test folder to
sitecore/content/Shared/Tags/Test
the links are broken.
If i manually change this to use the GUID (Using the build option), I get :
datasource={62CF8494-B148-4B2E-9D36-52EC4CD75E13}&database=master
If i now move the test folder around, my links remain as is.
I wanted to write a routine that runs through the tree and updates all the source fields for my templates (in a particular folder only), to contain the GUID and db name.
Is this possible?
I tried doing this in the Process method of a class that inherits from PublishItemProcessor and added the appropriate entry in the web.config. This method is called, but the Source property of the field is read only and cannpt be modified.
Any ideas?
Thanks in advance.
The best/most efficient option here would be to use Sitecore Powershell Extensions to modify the items.
This is a good reference point: https://sitecorepowershell.gitbooks.io/sitecore-powershell-extensions/content/working-with-items.html
You could also do this in code.
You need to write a routine (code or SPE) that starts with the /sitecore/templates/user defined or whatever your root folder is.
Recurse thru the tree and get all items that have the template: Template Field. Then you can check value of the the Source field. If it is the one you want to change, update the value and save the item.
Remember to publish the templates tree after updating all the values.

Does the class of an xml configuration file need to match an actual class used in the application?

For a configuration file in XML that you are using to store application settings, does it's class object need to be one of the classes that is used within the application, or do you create a special configuration class and the translate the values inside you application to the other objects that use those values?
For example
Say I want to keep track of these 3 settings for a product
Name
ID
Color
So My config file looks something simple like
<Product>
<Name>product1</Name>
<ID>2343435</ID>
<Color>Blue</Color>
</Product>
But my Product class that I'm using in the application has many more properties and methods
like
class Product{
string Name;
string Color;
int ID;
bool isObsolete;
SpecialType ProductProperty;
Product(){}
ObsoleteProduct(){
//do stuff
}
OtherMethod(){
//Do stuff
}
}
So then am I supposed to make XML representation from the actual Product class I'm using, or do I use the simpler form that only contains the settings I care about? Because if I use the simpler form, then I'll have two classes, and I'll need to move the values between objects.
The xml serialization and deserialization can be configured a lot using attributes, as described here. For instance, properties can be omitted from serialization, the names of properties can be explicitly specified and the serialization styles for array types can be selected.
Furthermore, the access on array types is done via the ICollection interface, which permits to provide additional logic on insertion of elements, which is discussed in this article.

What to use instead ini in C#

There must be a program that should generate WORD document (but that's not the point). It generates a document by data that the user writes in the program. And sometimes there is need to close application and do some other work and user don't want to lose all progress. And here we must keep all the "changes" that user have entered. Previously, I have saved all .ini file (under the instruction http://www.codeproject.com/Articles/1966/An-INI-file-handling-class-using-C) it was enough for me for test, but in real cases ini was not enough, because if I save the textbox with multiline so record to inin file goes wrong, and when reading ini file - readed was only the first line and then only the first 255 characters.
Here is an example of what should be saved:
information about all checked checkboxes radiobuttons etc. (in
INI-expample I show it in CHECKOUTS and COMPARING sections)
the data from all textboxes on the main form (MAIN section)
most importantly, objects of 'implementation' and 'screens' class.
Now about class 'implementation': Each implementation may have a name, description, status, and a list of links to screenshots. To do this, I created a listbox with list of screenshots for each implementation (ScreenList) and a separate listbox for all implementations. Ie when I fill the data I store object in listbox, and then if I need I can just get access to it. And when I save a list of all implementations into ini I first of all write the number of all implementations to be able get access in loops (for, while etc) to each object (all in INI and CODE examples: Section IMPLEMENTATIONS, IMPLEMENTATION_n ...)
And the question is: how to save these Data? As I know Microsoft has abandoned ini and use the xml, but I can't google it correctly. Someone suggested I use serialization of data in xml, but as far as I could google - Serialization is used only for one object of class, and I have a lot of these objects are, othervide I still have and values ​​of all the checkboxes and more. Ie I need to save all the values ​​of controls , all the objects of classes implement and screen, and then read these values ​​and write them right back to where they were taken . How to do that?
Code examples:
//........save object to listbox
Implement imp = new Implement(impName.Text, impDescr.Text, impStatus.Text, ScreenList);
listBox1.Items.Add(imp);
//......
//in implement class, Screens is list of screenshots that is get from another listbox
private List<string> _Screens = new List<string>();
public Implement(string Name, string Description, string Status, ListBox Screen)
{
_Name = Name;
_Description = Description;
_Status = Status;
for(int i=0;i<Screen.Items.Count;i++)
{
_Screens.Add(Screen.Items[i].ToString());
}
}
//....getting access to implementation
Implement imp = (Implement)listBox1.SelectedItem;
....
Ini example:
[MAIN]
Languages=Polish
Comment=Comment lalarar larl alrlalrl
Status=Correct
[CHECKOUTS]
Enable=True
SLDoc=False
SLDocTab=True
SaveDoc=True
LoadDoc=False
SendDoc=False
Correctly=True
CorrNum=50
[COMPARING]
Enable=True
NoDif=False
Declar=True
UnDecl=False
UnDeclDESCR=
[IMPLEMENTATIONS]
COUNT=2
[IMPLEMENTATION_0]
Name=Implement 1 CORRECT
Descr=text text test text
Status=Correct
ScreenCount=2
Screen_0=C:\1.png
Screen_1=C:\2.png
[IMPLEMENTATION_1]
Name=IMPLEMENT 2 INCORRECT
Descr=lala
Status=Incorrect
ScreenCount=2
Screen_0=C:\2.png
Screen_1=C:\3.jpg
[SCREENS]
COUNT=2
[SCREEN_0]
Descr=Screen 1
Screen=C:\1.png
[SCREEN_1]
Descr=Screen 2
Screen=C:\1.png
If I understood you correctly you should take a look at settings mechanism in c#.
I hope that this chapter of MSDN will be useful.
What you have to do is create some kind of Settings object. This should be a class that either has a specific property (or class for nested values) for each setting you like (e.g. public string Language {get; set; }) or you take a more generic way by using two dictionaries Dictionary<string, string> (for simple values), Dictionary<string, Settings> (a recursive structure for complex types).
Then your form should be able to create such a settings object an fill it with the desired data it needs to recreate the current state and it should be able to take such a settings object and change its current state to this settings object by setting all inner variable to the values within this object.
The next step would be to make this object serializable by either using XML serialization or Data Contract or whatever you like. Then you can write/load this object to/from disk and afterwards push it into the class that needs this state.

How to read old version of MongoDb document with new model in code

Lets say my c# model updated while correspondent collection still contains old documents, I want old and new documents to coexist in the collection, while using only new version of c# model to read them. I wish no inheritance is used if possible. So I wonder which of this issues are solvable and how:
there is a new property in c# model which does not present in database. I think it never should be an issue, Mongo knows nothing about it, and it will be initialized with default value. The only issue here is to initialize it with particular value for all old documents, anybody knows how?
one of property has gone from model. I want MongoDb to find out there is no more property in c# class to map the field of old document to, and to ignore it instead of crashing. This scenario probably sounds a bit strange as it would mean some garbage left in database, but anyway, is the behavior possible to implement/configure?
type if changed, new type is convertible to old one, like integer->string. Is there any way to configure mapping for old docs?
I can consider using inheritance for second case if it is not solvable otherwise
Most of the answers to your questions are found here.
BsonDefaultValue("abc") attribute on properties to handle values not present in the database, and to give them a default value upon deserialization
BsonIgnoreExtraElements attribute on the class to ignore extra elements found during deserialization (to avoid the exception)
A custom serializer is required to handle if the type of a member is changed, or you need to write an upgrade script to fix the data. It would probably be easier to leave the int on load, and save to a string as needed. (That will mean that you'll need a new property name for the string version of the property.)

Custom XML Serialization, how to write custom root element?

I'm probably just doing this wrong, i know.
I'm using custom serialization and when the xml is generated it's putting the class name as the root element
Example:
<MyClassName>
<MyIntendedRootNode>
<ObjectType>
<Property1/>
<Property2/>
...
I'm invoking the serialization by calling xmlserializer.Serialize(writer,Me) so I'm sure that has something to do with it.
I've tried putting XMLRoot onto the class, but I think as vb is compiling this partial class with its aspx page, it's either overwriting this property or ignoring it entirely.
Ideally I'd like to just tell it to either throw away everything it has and use a different root element.
Anybody else do this except me?
Thanks
You can use either IXmlSerializable or use the XML attributes. I use XmlSerializer passing the root in the constructor.
var MemoryStream ms;
var customRoot = dataObject as XmlRootAttribute;
var xml = new XmlSerializer(dataObject.GetType(), customRoot);
xml.Serialize(ms, dataObject);
In ASP.NET, the actual class that is loaded is a generated class that inherits from your class. (It turns out--surprisingly--that this generated code is actually separate from the additional generated code that is combined with your code using the partial class technique. The generated class has the same name as the class you are working on, but it is in a different namespace.) Since XmlRoot is not an inherited attribute, the XmlSerializer does not see it.
I don't think there is any solution (other than modify the document after you have generated it).
Are you trying to serialize a codebehind file?
I would suggest writing a model to contain the data that needs to be saved, and then serializing that instead. Then use the appropriate XMLWriter attributes to make sure your root element is correctly named.
Or you could implement IXmlSerializable and have full control over your Xml but its a bit of extra effort just to change a root element name.
You can create a wrapper class and give that wrapper class with the name that you wish to be shown in the xml root.

Categories

Resources