however try may way tried, I do not know how can I serialize
(sorry. I found in English dictionary 'What the hell'
is this bad word? anyway i'm sorry)
When I use BinaryFormatter, it throw exception from RelayCommand(I want to use XmlSerializer. I must see the file's text)
I tried using [XmlIgnore], but i think It seems that do not apply.
When I use XmlSerializer, I don't know where throw exception.
DataContractSerializer is throw a lot of exception. so I do not want to use.
please help me.
Please understand, I can't speak English well.
this is my class.
Extension Solution.
Referred from main solution.
[Serializable]
public class SerializableContextBase : INotifyPropertyChanged
{
[field: NonSerialized()]
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
}
Main Solution
Main Top Level class
[Serializable]
public class ResultContext : SerializableContextBase
{
public ResultContext() { }
private PerformanceContextCollection _PerformanceCollection = new PerformanceContextCollection();
public PerformanceContextCollection PerformanceCollection
{
get { return _PerformanceCollection; }
set
{
if (_PerformanceCollection == value) { return; }
_PerformanceCollection = value;
RaisePropertyChanged("PerformanceCollection");
}
}
Bottom Level Class
[Serializable]
public class PerformanceContextCollection : ObservableCollection<PerformanceContext>
{
// some method
// public void Add(string Name){} ~~~
}
[Serializable]
public class PerformanceContext : SerializableContextBase
{
[XmlIgnore]
public RelayCommand<PerformanceContext> RemoveCommand { get; set; }
some string, some guid...~~
}
Your classes are designed as ViewModels, so they have a lot of extra baggage that is related to their interactions with WPF. In order to send the information to another layer, the usual reason why people serialize data, you would normally use another class, a Data Transfer Object of some sort. I know this sounds pedantic, but this solution also frees you from using the same structure when serializing. For example you might want to serialize some data as a comma separated list, instead of an entire list of elements, of you might want to ignore properties that in the ViewModel are used for ease of interaction with the WPF engine like having a Visibility property instead or together with a boolean IsVisible.
That being said, if you still want to serialize your classes as they are no matter what, the simplest way (for me at least) would be to implement IXmlSerializable and thus control the serialization output yourself. Understand that while the default serialization works well and usually doesn't need much developer work, it also usually renders a horrendously verbose and hard to read XML output. For example most primitive properties look better as attributes to an element, but the serialization creates child elements for each.
Related
I've a class with some properties which I want to serialize. My problem is that
I can't serialize the "CustomCanvasClass". I only need the X/Y properties of it.
So I created a new property and marked the "CustomCanvasClass" property as [NonSerialized].
Unfortunatly it won't works. Maybe have somebody another idea to copy this data out of the class.
[Serializable]
public class CustomClass
{
//won't serialized
public double X
{
get
{
return Canvas.GetLeft(CustomCanvasClass);
}
set
{
Canvas.SetLeft(CustomCanvasClass, value);
}
}
public string Property1 { get; set; }
//CanvasElement inherits from Canvas. Serialization would throw a Exception.
public CanvasElement CustomCanvasClass
{
get
{
return _CustomCanvasClass;
}
set
{
_CustomCanvasClass = value;
}
}
[NonSerialized]
private CanvasElement _CustomCanvasClass;
}
Use a DTO for the properties you need and serialize that.
DTO stands for data transfer object. It contains data you want to transfer only and no logic.
E.g. Add a class like this:
class MyCustomClassDto
{
public double X {get;set;}
public double Y {get;set;}
}
So instead of trying to serialize your custom class directly, you would initialize an instance of this with your X and Y values and serialize that.
Then in your main class you could add this:
public MyCustomClassDto GetData()
{
return new MyCustomerClassDto{X = X, Y = Y};
}
You could add a serialization method to your DTO also.
Alternatively you can use a mapping tool like automapper - which would be suitable if you have many DTOs or corresponding objects in different layers.
Hope that makes the idea clear. Can't see other ways of expanding without seeing more details/context.
The proper mvvm itemspanel approach in the comment on the question is preferable, but it might require substantial rewriting depending on your existing codebase. You might want to consider the business case for such refactoring imo, considering the effort against how much more is likely to be built on top of it.
We have an existing WCF service which uses several DataContracts. We want to modify the serialization based on the device, so that when accessed from mobile devices, the service should serialize only some important data members(not all)
We have 2 options here
Create separate operation and data contracts for different types of
devices
Mess with the actual xml serialization and suppress creating
unnecessary elements based on the device
We don't want to go with the first option since it introduces a lot of redundant code problems in the future
Small research showed that we need to use IXmlSerializable and override the readXML() and writeXML() methods. But at the same time, I have seen somewhere that DataContract and IXmlSerializable should not be used together
Any example to mess with actual serialization is greatly appreciated .
[DataContract]
public class TokenMessage
{
string tokenValue;
string extraValue;
[DataMember]
public string Token
{
get { return tokenValue; }
set { tokenValue = value; }
}
[DataMember]
public string Extra
{
get { return extraValue; }
set { extraValue = value; }
}
}
Now when i access the service which returns a typical TokenMessage data contract, from a mobile device, i don't want the "Extra" data member to be serialized i.e. When I supply a different argument to the operation contract, it should be able to serialize some/all the data members(depending on the action)
PS: For now please ignore the device detection part. Lets assume we have an argument in the operation contract, which helps us identify the device
I'm not convinced that some variant of #Pranav Singh's answer isn't a better design, but that's not your question...
As you mentioned in a comments attributes in .NET are static by design. This means dynamically adding/removing [DataMember] isn't a good option. It is possible. There are options like using Reflection.Emit to recreate the instance with the meta data changes (see all the answers to Can attributes be added dynamically in C#?) but all of those routes are complicated.
I see two reasonable options:
1) Implement an IParameterInspector for the service. In the AfterCall() method you could inspect and alter the parameters being returned to the client before they are serialized. There is some work to use reflection to dynamically determine the parameter types and set their values, but its not complicated. This is the better design that enables reuse of the behavior across many contracts or services. Carlos Figueira's blog is the best source for WCF extension examples.
2) Use the [OnSerializing] and [OnSerialized] events. In the [DataContract] you could temporarily alter what the properties are returning during serialization. The events are actually designed to enable initialization and as such this solution is a bit of a hack. This solution is also not thread safe. But it does keep the code contained to the DataContract class and solves the problem quickly (and I think you are looking for quick).
Solution #2 mights look something like:
[DataContract]
public class TokenMessage
{
string tokenValue;
string extraValue;
bool enableExtraValue = true;
[DataMember]
public string Extra
{
get {
if (enableExtraValue)
return extraValue;
return null;
}
set { extraValue = value; }
}
[OnSerializing()]
internal void OnSerializingMethod(StreamingContext context)
{
enableExtraValue = false;
}
[OnSerialized()]
internal void OnSerializedMethod(StreamingContext context)
{
enableExtraValue = true;
}
}
Solution #2 is a quick fix (which is what I think you are looking for).
Solution #1 is the better design.
Try using IgnoreDataMemberAttribute
There is a approach, but I think this will require extra DataContract to be generated but still no need for separate operation and data contracts for different types of devices.
It can classic implementation to run-time polymorphism. I am just giving idea:
Say you have a generic DataContract like :
[DataContract]
[KnownType(typeof(Extra))]
[KnownType(typeof(Extra2))]
public class TokenMessage
{
string tokenValue;
string extraValue;
[DataMember]
public string Token
{
get { return tokenValue; }
set { tokenValue = value; }
}
}
Other device specific contracts can inherit TokenMessage as base class like:
[DataContract]
public class Extra:TokenMessage
{
[DataMember]
public string Extra
{
get ;set;
}
}
[DataContract]
public class Extra2:TokenMessage
{
[DataMember]
public string Extra2
{
get ;set;
}
}
Now at run-time as you say you know an argument in the operation contract, which helps us identify the device. Say based on device type, you can instantiate base class with derived class like:
TokenMessage tm= new Extra();
OR
TokenMessage tm= new Extra2();
So at run-time you will decide which device contract will be part of genric response.
Note: Adding KnownType will generate the separate xsd within wsdl for all known types within base class, but saves serialization for data at run-time as this should depend on actual inheritance chosen.
In your model add a property 'ShouldSerializeYOUR_PROPERTY_NAME', set it to false when you do not want the property serialized.
See more here: http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject.shouldserializeproperty(v=vs.110).aspx
I have a pecular problem in my WCF in the web services layer.
When I instantiate a private member (_Wagon) of my class (This instantiation is not null) in WCF, after few seconds, it's become null.
I've been trying to diagnose the problem, but no result so far.
So I'm turning to you people to help me solve this problem.
Thank you.
Hence there is my code :
[DataContract]
public class RemoteWagon
{
private readonly IWagon _Wagon;
public RemoteWagon(IWagon Wagon)
{
_Wagon = Wagon; //_Wagon isn't null here
}
~RemoteWagon()
{
Trace.WriteLine("Do nothing");
}
[DataMember]
public RemoteBreakpoint Breakpoint
{
set
{
if (value == null)
{
_Wagon.Breakpoint = null; //_Wagon member is NULL...
}
else
{
//... useless code in this context.
}
}
}
}
This would happen if your class had been serialized and deserialized by DataContractSerializer (for example when sending data between client and server)
Some reference: DataContractSerializer doesn't call my constructor?
If this is the case, then one possible solution, that worked for me: https://stackoverflow.com/a/9419943/724944
So a quick check&fix for this problem (I assume that you want to initialize the field yourself and not serialize it) would be to create method:
[OnDeserializing]
private void OnDeserializing(StreamingContext c)
{
_Wagon = initializeWagon();
}
however, as you probably noticed, you won't be able to pass Wagon during deserialization - you'll have to initialize it differently.
On the other hand, If you want _Wagon serialized, then expose it as public [DataMember] property
It seems that if you want _Wagon serialized you should mark it as a DataMember and ditch the "readonly" on it. If you don't want it serialized, show us your code to construct and fill this object.
Sometimes the .NET runtime requires us to create public setters for properties which should really be read-only. For example:
XmlSerializer requires serialized properties to be writable, even if we only serialize one-way.
I have an unusual case in WPF where I need to have a TwoWay binding within a MultiBinding, even though conceptually the bound value will never change. This requires properties to be writable.
In each of these cases, I can leave the setter empty without affecting the functionality, but this is likely to lead to confusion down the line.
Given that I can't avoid having public setters on these properties, is there a way to generate compiler warnings when the setters are accessed? The attributes [Deprecated] and [Obsolete] would do the job, but the wording/intent isn't right.
The way I approach this problem is that I simply don't compromise the integrity my types for the purposes of serialization. The process of serialization is all about data and very little about behavior. I refuse to compromise the behavior of my types for a data only scenario.
Instead I design my types for the most efficient + safe usage. If the resulting type is not serializable and I find a scenario that requires it, I will create separate types which exist solely for the purpose of serializing my other types.
Here's a quick sample.
// My Core Immutable Type
namespace MyProject {
public sealed class Student {
private readonly string _name;
public string Name {
get { return _name; }
}
public Student(string name) {
_name = name;
}
}
}
// My Xml Serialization Type
namespace MyProject.Serialization {
public class SerializableStudent {
public string Name;
public SerializableStudent(Student source) {
Name = source.Name;
}
public Student ConvertToStudent() {
return new Student(Name);
}
}
}
For serialization, specifically, you can define the process manually by implementing the ISerializable interface.
I noticed the XmlSerializer is more forgiving to adding new members, removing existing ones, etc to the serialized types.
When I did this with the BinaryFormatter, and tried to deserialize the old data, it threw an exception.
What other alternatives are there for forgiving options, i.e. one that doesn't throw an exception just uses default values, skips them, etc?
Are protocol buffers forgiving in this regard?
You mention binary, and indeed BinaryFormatter is very brittle here. The problem is that BinaryFormatter is type and field based. Instead, you want a contract-based serializer, such as XmlSerialzier, DataContractSerializer (3.0), etc.
Or for binary, protobuf-net is a C# implementation of Google's "protocol buffers" wire format, but re-implemented along .NET lines; (note: I'm the author...).
It is (like the others) data-contract based, but instead of <CustomerName>asdasd</CustomerName> etc, it uses numeric tags to identify things instead; so:
[ProtoContract]
public class Customer {
[ProtoMember(1)]
public string Name {get;set;}
// ...
}
As you add more members you give them new unique numbers; this keeps it extensible without relying on any names etc. Plus it is very fast ;-p As with XmlSerializer, it will ignore things it doesn't expect (or it can store them for safe round-trip of unexpected data), and supports the same default things. You can even use your existing xml attributes:
[XmlType]
public class Customer {
[XmlElement(Order=1)]
public string Name {get;set;}
// ...
}
I could talk about this subject all day, so I'd better shut up before [too late].
You could inherit your class from ISerializable and define a custom GetObjectData. I haven't tested this, but such a class might be deserializable from a binary format, even if changes have since been made to the class.
EDIT
I just confirmed that this works. You can use code like the example below to explicitly define how an object is serialized and deserialized. It would then be up to you to make these methods work with older versions of your class. I tested this by serializing an instance of Cereal to a binary file, then making changes to the class and reading the file back in for deserialization.
[Serializable]
private class Cereal : ISerializable
{
public int Id { get; set; }
public string Name { get; set; }
public Cereal()
{
}
protected Cereal( SerializationInfo info, StreamingContext context)
{
Id = info.GetInt32 ( "Id" );
Name = info.GetString ( "Name" );
}
public void GetObjectData( SerializationInfo info, StreamingContext context )
{
info.AddValue ( "Id", Id );
info.AddValue ( "Name", Name );
}
}
I strongly recommend doing your own serialization so that you have well-defined file formats independent of the language schemes.
I actually find that the binary formatter is the most durable in the long run.
It provides excellent forward compatibility. That is to say, if you upgrade the file to a new version, it will not work with the old deserializer.
I generally create some simple data classes that I want to use for serialization. When i need to change the class, I implement the OnDeserialized / OnDeserializing methods. This allows the data to be upgraded.
The binary formatter does not require that you have a public setter for your properties, which to me is a big problem sometimes.
[Serializable]
public class data
{
private int m_MyInteger;
// New field
private double m_MyDouble;
[OnDeserializing]
internal void OnDeserializing(StreamingContext context)
{
// some good default value
m_MyDouble = 5;
}
public int MyInteger
{
get{ return m_MyInteger; }
set { m_MyInteger = value; }
}
}
I think the following post could help you. I also agree with others who said to write your own serializer. It is way better than generated code from xsd.exe .
See the post below:
Serialization and Deserialization into an XML file, C#
You can also look at the OptionalFieldAttribute for use with SerializableAttribute/NonSerializedAttribute and the BinaryFormatter and SoapFormatter
... version 1
[Serializable]
public class MyClass
{
public string field1;
[NonSerialized]
public string field2;
}
... version 2
[Serializable]
public class MyClass
{
public string field1;
[NonSerialized]
public string field2;
[OptionalField]
public string field3;
}