I have a datacontract like this
[DataContract]
class MyDC
{
[DataMember]
public string DM1;
[DataMember]
public string DM2;
[DataMember]
public string DM3;
}
and sometimes I want to prevent DM2 from being deserialized when being returned from an OperationContract. Something like this:
[OperationContact]
public MyDC GetMyDC()
{
MyDC mdc = new MyDC();
if (condition)
{
// Code to prevent DM2 from being deserialized
}
return mdc;
}
I could always make a new DataContract that has only DM1 and DM3 and generate that from the MyDC instance but I want to see if it is possible to programatically remove DM2. Is it possible? How?
One way to do this is to set the EmitDefaultValue property of the DataMemberAttribute to false:
[DataContract]
class MyDC
{
[DataMember]
public string DM1;
[DataMember(EmitDefaultValue = false)]
public string DM2;
[DataMember]
public string DM3;
}
Then setting this property to null:
[OperationContact]
public MyDC GetMyDC()
{
MyDC mdc = new MyDC();
if (condition)
{
// Code to prevent DM2 from being deserialized
mdc.DM2 = null;
}
return mdc;
}
This way, that property doesn't get written to the output stream on serialization.
http://msdn.microsoft.com/en-us/library/aa347792.aspx
What you mean is serialization and not deserialization.
If you prepare a class for serialization applying the [DataContract] attribute to the class, only the members of the class that has [DataMember] attribute will be serialized:
[DataContract]
class MyDC
{
[DataMember]
public string DM1;
public string DM2;
[DataMember]
public string DM3;
}
In some more complex cases the usage of [IgnoreDataMember] can solve your problem. (See http://msdn.microsoft.com/en-us/library/ms733127.aspx)
By the way, you can serialize fields and properties, regardless of accessibility: private, protected, internal, protected internal, or public. You can serialize any read/write properties and not only fields. About serialization of collection types see http://msdn.microsoft.com/en-us/library/aa347850.aspx.
[DataContract]
class MyDC
{
[DataMember]
public string DM1;
public string DM2;
public bool IsDM2Serializable;
[DataMember(Name="DM2", EmitDefaultValue = false)]
public string DM2SerializedConditionally
{
get
{
if(IsDM2Serializable)
return null;
return DM2;
}
set { DM2=value; }
}
[DataMember]
public string DM3;
}
Then set IsDM2Serializable to false when you need to hide it:
[OperationContact]
public MyDC GetMyDC()
{
MyDC mdc = new MyDC();
if (condition)
{
// Code to prevent DM2 from being serialized
mdc.IsDM2Serializable = false;
}
return mdc;
}
Yes, we can prevent an attribute from serialization.
Put [DataContract] Annotation on class and [DataMember] for only serialized attribute. if you want to skip attribute when that attribute value is null then put [DataMember(EmitDefaultValue = false)] on that attribute.
Example:
[DataContract]
public class MyClass
{
[DataMember]
public int Id{ get; set; }
[DataMember]
public string Title { get; set; }
[DataMember]
public string MessageBody { get; set; }
[DataMember(EmitDefaultValue = false)]
public DateTime SentOn { get; set; }
}
Note: SentOn will be serialized when it is not null and others will be serialized in every condition.
Related
I am working on a wcf webservice. This service uses a third party webservice which I have added as a service reference.
Now I want to publish some properties of this proxyclient to clients who uses my wcfservice, without defining an own class and doing the mapping.
The auto generated code is done as partial class.
public partial class Person : object,
System.ComponentModel.INotifyPropertyChanged
{
public string FirstName;
public string LastName;
...
}
I tried to override these properties by using the MetadataType-Attribute and adding the [DataMember]-Attribute to properties. But this seams to work only for EF.
[DataContract]
[MetadataType(typeof(PersonMetaData))]
public partial class Person
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
public class PersonMetaData
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string LastName { get; set; }
}
Trying to implement an interface didn't help, the properties are invisible on client.
[DataContract]
public partial class Person : IPerson
{}
public interface IPerson
{
[DataMember]
string FirstName { get; set; }
[DataMember]
string LastName { get; set; }
}
Any idea?
Guido
On my service XmlSerializer failed to serialize the auto-generated class cause of PropertyChanged-event.
If I work with DataContractSerializer and decorate my auto-generated class with [DataContract], I'm not able to decorate the properties by inheritance with [DataMember] because the attibute is not inheritable.
So I extended this partial class by wrapper properties.
[DataContract]
public partial class Person
{
[DataMember]
public string FirstNameWrapper
{
get
{
return this.FirstName;
}
set
{
this.FirstName = value;
}
}
}
On the service side I have an abstract base class like so:
[DataContract]
public abstract class EntityBase : IObjectState, IDatabaseMetaData
{
[NotMapped]
[DataMember]
public ObjectState ObjectState { get; set; }
#region IDatabaseMetaData Members
[DataMember] public DateTime InsertDatetime { get; set; }
[DataMember] public int InsertSystemUserId { get; set; }
[DataMember] public DateTime? UpdateDatetime { get; set; }
[DataMember] public int? UpdateSystemUserId { get; set; }
public virtual SystemUser InsertSystemUser { get; set; }
public virtual SystemUser UpdateSystemUser { get; set; }
#endregion
}
Here is an implementing class (data contract):
[DataContract(Namespace = Constants.MyNamespace)]
public class AccountClass : EntityBase
{
[DataMember] public int AccountClassId { get; set; }
[DataMember] public string AccountClassCode { get; set; }
[DataMember] public string AccountClassDesc { get; set; }
}
On the client side I have essentially duplicated contracts. Here is the Client.AccountClass:
public class AccountClass : ObjectBase
{
private int _accountClassId;
private string _accountClassCode;
private string _accountClassDesc;
public int AccountClassId
{
get { return _accountClassId;}
set
{
if (_accountClassId == value) return;
_accountClassId = value;
OnPropertyChanged(() => AccountClassId);
}
}
public string AccountClassCode
{
get { return _accountClassCode; }
set
{
if (_accountClassCode == value) return;
_accountClassCode = value;
OnPropertyChanged(() => AccountClassCode);
}
}
public string AccountClassDesc
{
get { return _accountClassDesc; }
set
{
if (_accountClassDesc == value) return;
_accountClassDesc = value;
OnPropertyChanged(() => AccountClassDesc);
}
}
}
..and here is the parts of ObjectBase that matter:
public abstract class ObjectBase : IObjectState, IDatabaseMetaData
{
public ObjectState ObjectState { get; set; }
#region IDatabaseMetaData Members
public DateTime InsertDatetime { get; set; }
public int InsertSystemUserId { get; set; }
public DateTime? UpdateDatetime { get; set; }
public int? UpdateSystemUserId { get; set; }
#endregion
}
When I debug the service in my WcfMessageInspector.BeforeSendReply, I can see the message correctly sending the IObjectState and IDatabaseMetaData values. However, on the client side, they are always null (or default values). I have tried using KnownTypes, applying the namespace to the abstract class. The only way I can serialize everything correctly is to get rid of the interfaces and base classes all together and put the properties directly on the Client/Server AccountClass object. What am I missing here? Thanks.
Update 1
This seems to be a namespace thing. If I move my EntityBase and ObjectBase into the same CLR Namespace, everything works (with no KnownType attributes). In my client contract's AssemblyInfo.cs file I have this:
[assembly: ContractNamespace(Constants.MyNamespace, ClrNamespace = "Project.Name.Client.Entities")]
I tried adding ContractNamespaces here to no avail. Like I said, unless the EntityBase and ObjectBase are in the same namespace, it won't work. However, this is a problem for me because it creates a circular reference, unless I move a lot of stuff around.
Any idea how I can see what the full data contract (namespaces, DataMembers, etc) looks like just before/after serialization on the client/server? I tried intercepting the OnSerializing event without much luck. Thanks again.
This was a namespace issue.
I explicitly add the correct namespace to all parties involved and everything works great. One thing I notice is that the ContractNamespace's ClrNamespace in your AssemblyInfo.cs file should match the AssemblyTitle. Also, putting more than one ContractNamespace in the AssemblyInfo.cs does nothing. For example, I was doing this:
[assembly: ContractNamespace(Constants.MyNamespace, ClrNamespace = "Company.Project.Client.Entities")]
[assembly: ContractNamespace(Constants.MyNamespace, ClrNamespace = "Company.Project.Client.Entities.Core")]
Any POCO in the Company.Project.Client.Entities.Core would not serialize correctly until I explicitly put the DataContract namespace on it like so
[DataContract(Namespace = Constants.MyNamespace)]
public class SomeObject
{
[DataMember] public string SomeProperty { get; set; }
//..etc
}
Alternatively, I could have restructured the project so SomeObject was in the Company.Project.Client.Entities namespace and that would have worked.
Finally, the most helpful thing to debugging this was looking at the WSDL, and then using a custom IDispatchMessageInspector to see the actual messages AfterReceiveRequest and BeforeSendReply. Hopefully this helps someone.
I have a ServiceContract as such :
bool CreateSlideshow(Slideshow current, string path, string name);
When I run my program calling the service, I get the following exception :
There was an error while trying to serialize parameter
http://tempura.org/:current. The InnerException message was 'Type
'System.DelegateSerializationHolder+DelegateEntry' with data contract
name
'DelegateSerializationHolder.DelegateEntry:http://schemas.datacontract.org/2004/07/System'
is not expected. Consider using a DataContractResolver or add any
types not known statically to the list of known types.....
Apparently the problem lies in Slideshow. My class Slideshow has the following members :
private String name;
private String path;
private List<Slide> slides;
and the class Slide has the following members :
private String title;
private ContentTypeEnum contentType;
private String textContent;
private String pictureContextPath;
where ContentTypeEnum is an enumeration.
Any idea how to resolve the exception? Hope for some advice/suggestions. Thanks in advance.
Your used types have to be marked with the [DataContract] attribute. The properties have to be marked with the [DataMember] attribute.
Furthermore your fields should be public properties, because a datacontract doesn't make any sense with private fields only.
[DataContract]
public class Slideshow
{
[DataMember]
public String Name { get; set; }
[DataMember]
public String Path { get; set; }
[DataMember]
public List<Slide> Slides { get; set; }
}
[DataContract]
public class Slide
{
[DataMember]
public String Title { get; set; }
[DataMember]
public ContentTypeEnum ContentType { get; set; }
[DataMember]
public String TextContent { get; set; }
[DataMember]
public String PictureContextPath { get; set; }
}
I have a WCF service and want to ignore some parts in serialization. How do I do that? I tested with IgnoreDatamember() but it did not work.
[DataContract(Name = "M")]
public class Message
{
[DataMember(Name = "H"), IgnoreDataMember()]
public MessageHeader Header { get; set; }
[DataMember(Name = "B")]
public string Body { get; set; }
}
Simply remove the complete DataMember attribute.
I have a XML structure like this:
<Message>
<Messagehead>
<OSType>Android</OSType>
<RouteDest>SiteServerName</RouteDest>
<ActionType>Enroll</ActionType>
</Messagehead>
<MessageBody>
<Raw>
<![CDATA[OrienginalMessageContent]]>
</Raw>
</MessageBody>
</Message>
and I want upload this XML to WCF 4.0 my rest service:
public string Enroll(Message instance)
{
// TODO: Add the new instance of SampleItem to the collection
return "success";
}
the Message is a DataContract type, I setup it like below:
[DataContract(Namespace = "")]
public class Message
{
[DataMember]
public MessageHead MessageHead { get; set; }
[DataMember]
public MessageBody MessageBody { get; set; }
}
public class MessageHead
{
public OSType OSType { get; set; }
public string RouteDest { get; set; }
public Action Action { get; set; }
}
public class MessageBody
{
public string RawRequestContent { get; set; }
}
but when I get the Message instance from the server side, all the property is null, except the OSType, can anybody tell me why? How could I solve this problem?
Besides being a really bad name for a class (since it's already used in the WCF runtime), your Message class also has some flaws:
<Message>
<Messagehead>
....
</Messagehead>
Your <Messagehead> has a lower-case h in the middle - yet your class defines it to be upper case:
[DataContract(Namespace = "")]
public class Message
{
[DataMember]
public MessageHead MessageHead { get; set; }
This will not work - case is important and relevant in a WCF message! If your XML has a lower-case h, so must your DataContract class!
Your XML also requires a <Raw> tag inside your <MessageBody>
<MessageBody>
<Raw>
<![CDATA[OriginalMessageContent]]>
</Raw>
</MessageBody>
yet your data contract doesn't respect that:
public class MessageBody
{
public string RawRequestContent { get; set; }
}
Again - those don't line up! Names are important - and they must match between your XML representation of the message, and the C# class representing that message.....