Whenever I use WCF, I always try to make immutable classes that end up going over the wire (i.e. parameters set in constructor, properties are read-only). However, this gets in the way of WCF serialization, which demands that all properties be Public get/set (which makes sense, because it has to deserialize them)
Even in this related post, I see that their solution ended up making everything Public, which violates my sense of good programming. Is there any way around this? Do I have to just settle for this solution or something like popsicle immutability and be happy with it?
The other thing I tried was something like this, where I'd have a base class for everything and a derived class that made the set useless:
/// <summary>
/// This represents a discovered virtual-machine template that can be
/// instantiated into a RunningVirtualMachine
/// </summary>
[DataContract]
[XmlRoot("VMTemplate")]
public class VirtualMachineTemplateBase
{
[DataMember]
public virtual ulong SizeInBytes { get; set; }
}
/// <summary>
/// This class is the real guts of VirtualMachineTemplate that we're hiding
/// from the base class.
/// </summary>
[XmlInclude(typeof(VirtualMachineTemplateBase))]
public class VirtualMachineTemplate : VirtualMachineTemplateBase, IXmlPicklable, IEnableLogger
{
ulong _SizeInBytes;
public override ulong SizeInBytes {
get { return _SizeInBytes; }
set { }
}
}
If you use the DataContractSerializer (which is the default for WCF), you can serialize anyhting that's decorated with the [DataMember] attribute - even a read-only field:
[DataContract]
public class VirtualMachineTemplate : VirtualMachineTemplateBase, IXmlPicklable, IEnableLogger
{
[DataMember]
ulong _SizeInBytes;
}
But you need to use the DataContractSerializer - not the XML serializer. The XML serializer can ONLY serialize public properties (and it will, unless you put a [XmlIgnore] on them).
The DataContractSerializer is different:
it doesn't need a parameter-less default constructor
it will only serialize what you explicitly mark with [DataMember]
but that can be anything - a field, a property, and of any visibility (private, protected, public)
it's a bit faster than XmlSerializer, but you don't get a lot of control over the shape of the XML - you only get a say in what's included
See this blog post and this blog post for a few more tips and tricks.
Marc
To ensure both immutability and easy implementation at the same time add a private setter for the property to serve deserialization. A lot happens under the bonnet, but it works.
Related
In DDD, Value Object and Enumeration are quite beautiful so that I want use both two in the daily program logic, not only domain logic. When use customized value objects and enumerations, serialization problem is coming : should I implemented all the value objects and enumeration with System.Text.Json.JsonConverter<T> , or is there any good way to handle serialization and deserialization ?
Update:
to make it clear, Eumeration demo as below(ValueObject derived classes are same.):
[JsonConverter(typeof(CustomizedConverter))]
public class CustomizedEnumeration1 : Enumeration
{
public string Customized { get; protected set; }
public ... // some other customized property or class
public CustomizedEnumeration(int id, string name, string customized) : base(id, string) {
Customized = customized;
}
}
public class Customized2 : Enumeration
{ ... }
public class OtherCustomized: Enumeration
{ ... }
In DDD, properties sometimes are sealed by protected/private setter, deserialization has no right to set the value. Many derived classes can't deserialize as expected, so we have to rewrite serialization with System.Text.Json.JsonConverter<T> one by one. rewrite every derived Enumeration / Valueobject converter is not good, can any one point out any easy abstraction for that ?
You can achieve your desired result. You need to switch to NewtonsoftJson serialization.
Call this in Startup.cs in the ConfigureServices method:
services.AddControllers().AddNewtonsoftJson();
After this, your constructor will be called by deserialization for classes with private setter.
There is no need for custom converters.
For reference, I am using ASP Net Core 3.1
I have a question about the [DataContract] attribute.
I have written my code like below: here I am not using [DataContract] attribute for my test class.
class test
{
[Datamember]
public string Strproperty
{
get;
set;
}
[Datamemer]
public string Strproperty2
{
get;
set;
}
}
class checktotal:Iservice
{
public string testmethod(test obj)
{
return obj.Strproperty+Strproperty2;
}
}
For that I am sending data from client I am getting the values correctly.
Here is it necessary to use [DataContract] attribute for that test class?
If I removed [Datamember] for test class property is getting error while sending from client. But I am not getting any errors even if I am not using the [DataContract] attribute.
Please give me a brief explanation with example so that I can understand when to give that attribute and when do not give that attribute.
Thanks,
Satya Pratap.
The DataContractSerializer can deal with classes that do not have the DataContract attribute if they provide a default constructor. See the MSDN documentation for more details.
As of .NET 3.5 Service Pack 1, you can omit (not use) the [DataContract] and [DataMember] attributes. If you do that, then the DataContractSerializer in WCF will behave just like the XML serializer - it will serialize all public properties only.
I prefer to use [DataContract] and [DataMember] explicitly anyway - it gives me the opportunity to specify options (like the data contract's XML namespace, the order of the [DataMember]) and it lets me e.g. also exclude certain properties from serialization.
As soon as you start using [DataMember] on one property, then only those properties decorated with a [DataMember] will be looked at for the WCF serialization.
I have a class Car
public class Car
{
private Member _owner;
public string OwnerName
{
get { return _owner.Name; }
}
public Car(Member owner)
{
_owner = owner;
}
}
I'm using it both at Silverlight application and wcf service
So, at application I call WCF service to give me instance of car class, but when I get it at application, I see that _owner is empy.
I know that it is empty because of private, but how can I deal with it?
I'm using this class in my app as model (MVVM) if it could helps :/
For a start none of your properties are marked as DataMembers. The class isn't marked as a DataContract. If this is getting returned from a WCF service I would expect to see:
[Serializable]
[DataContract]
public class Car
{
private Member _owner;
[DataMember]
public string OwnerName
{
//getter
//setter
}
etc..
}
Does Member have to be private? Could it be converted into a property?
Keep in mind that a [DataMember] property needs both a set and a get (so that WCF can read into and from the object).
http://msdn.microsoft.com/en-us/library/ms733127.aspx
From a WCF serialization point of view, your Car class actually looks something like this to the WCF service:
public class Car
{
public string OwnerName { get; set; }
//other public properties here....
}
The WCF serializer uses the .NET class definition as a template for serializing its contents as a simple data transfer object. When the WCF service sends back a Car instance, only the public properties will contain values. The serializer ignores all methods in the class. Also, later versions of WCF don't require the DataContract/DataMember attribute markup.
The _owner variable is never initialized because it is not part of the public properties of the Car class. You'll need to modify the structure of the Car class (maybe add a public Owner property of type Member) to get all the data sent from the WCF service to your client.
When you are using the default Data Contract Serializer with WCF services it serializes and deserializes only the public properties of the class. Also another thing to note is that while deserializing the object graph the constructor is not called. You can have a public property with getter and setter.
Here is a very nice article by Jeremy Likeness explaining the problem similar to yours. From Architecture as well as best practices point of view you can use a POCO class generally called as DTO (Data Transfer Object) when transferring objects between the service layer and the clients.
I use ASP.NET WCF to return .NET objects in JSON format through jquery calls.
When I changed my .NET classes to serializable, which I expose through methods in my WCF class, the objects property names suddenly changed from:
Name to _Name.
So all code in my javascript classes where I access json objects is wrong.
Why do the properties have a underscore prefix now?
And how do I change it back without removing the serializable attribute on the classes?
Thanks.
Christian
When you say that you "changed the class to serializable", does it mean you added the [Serializable] attribute on them? If this is the case: classes marked with that attribute have all of their fields serialized (no properties). In the example below, this class doesn't have any attributes, and it does have a parameter-less constructor, so it's considered a "POCO" (plain-old CLR object) type. POCO types have their public members (fields or properties) serialized. If you decorate it with [Serializable], then it will fall into the serializable rule.
Why do you need to mark your type with [Serializable]? If you really need to do that (for some legacy serializer), you can also decorate your type with [DataContract] and [DataMember] attributes, which are honored by the WCF serializer. You'd add [DataContract] on the type, and [DataMember] on the properties which you want serialized.
public class Person
{
private string _Name;
private int _Age;
public string Name {
get { return this._Name; }
set { this._Name = value; }
}
public string Age {
get { return this._Age; }
set { this._Age = value; }
}
}
I know that a private parameterless constructor works but what about an object with no parameterless constructors?
I would like to expose types from a third party library so I have no control over the type definitions.
If there is a way what is the easiest? E.g. I don't what to have to create a sub type.
Edit:
What I'm looking for is something like the level of customization shown here: http://msdn.microsoft.com/en-us/magazine/cc163902.aspx
although I don't want to have to resort to streams to serialize/deserialize.
You can't really make arbitrary types serializable; in some cases (XmlSerializer, for example) the runtime exposes options to spoof the attributes. But DataContractSerializer doesn't allow this. Feasible options:
hide the classes behind your own types that are serializable (lots of work)
provide binary formatter surrogates (yeuch)
write your own serialization core (a lot of work to get right)
Essentially, if something isn't designed for serialization, very little of the framework will let you serialize it.
I just ran a little test, using a WCF Service that returns an basic object that does not have a default constructor.
//[DataContract]
//[Serializable]
public class MyObject
{
public MyObject(string _name)
{
Name = _name;
}
//[DataMember]
public string Name { get; set; }
//[DataMember]
public string Address { get; set; }
}
Here is what the service looks like:
public class MyService : IMyService
{
#region IMyService Members
public MyObject GetByName(string _name)
{
return new MyObject(_name) { Address = "Test Address" };
}
#endregion
}
This actually works, as long as MyObject is either a [DataContract] or [Serializable]. Interestingly, it doesn't seem to need the default constructor on the client side. There is a related post here:
How does WCF deserialization instantiate objects without calling a constructor?
I am not a WCF expert but it is unlikely that they support serialization on a constructor with arbitrary types. Namely because what would they pass in for values? You could pass null for reference types and empty values for structs. But what good would a type be that could be constructed with completely empty data?
I think you are stuck with 1 of 2 options
Sub class the type in question and pass appropriate default values to the non-parameterless constructor
Create a type that exists soley for serialization. Once completed it can create an instance of the original type that you are interested in. It is a bridge of sorts.
Personally I would go for #2. Make the class a data only structure and optimize it for serialization and factory purposes.