Move Protobuf-net serializable property from subclass to base class? - c#

I have a base class and subclass that are each defined to be serializable using Protobuf-net:
[DataContract]
public class BaseClass
{
[DataMember(Order = 1)]
public string PropertyA { get; set; }
// ...
}
[DataContract]
public class SubClass : BaseClass
{
[DataMember(Order = 101)]
public string PropertyB { get; set; }
// ...
}
Elsewhere:
ProtoBuf.Meta.RuntimeTypeModel.Default[typeof(BaseClass)]
.AddSubType(100, typeof(SubClass));
It has become necessary to move one of the subclass's properties to the base class:
[DataContract]
public class BaseClass
{
[DataMember(Order = 1)]
public string PropertyA { get; set; }
// [DataMember(Order = ?)]
public string PropertyB { get; set; }
// ...
}
[DataContract]
public class SubClass : BaseClass
{
// ...
}
After making this change, is it possible to configure the type model so that PropertyB in BaseClass is serialized at the same position as before to retain compatibility with old clients?
(The ideal solution would use the System.Runtime.Serialization attributes and avoid duplicating the value in the serialized output --as in implementing a new PropertyB in SubClass that uses base.PropertyB to get and set its value.)

Related

how to send a list of derived types over API (WCF) .NET

I've got a service method which returns a List<BaseClass> but sometimes I might send a DerivedClass : BaseClass in the list.
The issue is I want to send the information through. So far I have:
[DataContract]
public class BaseClass {
string Data { get; set; }
}
and
[DataContract(Name="BaseClass")]
public class DerivedClass : BaseClass {
string MoreData { get; set; }
}
But when the client recieves the data, it's all as a type BaseClass.
You should add KnownType attribute to BaseClass and change Name for DerivedClass or remove it:
[DataContract]
[KnownType(typeof(DerivedClass))]
public class BaseClass
{
string Data { get; set; }
}
[DataContract(Name="DerivedType")]
public class DerivedClass : BaseClass
{
string MoreData { get; set; }
}
KnownTypes
Following should fix your issue:
[DataContract]
[KnownType(typeof(DerivedClass))]
public class BaseClass {
string Data { get; set; }
}
public class DerivedClass : BaseClass
{
}

Property overriden with "new" gets dupped in WCF Webservice

I have a problem with a Webservice I'm creating, the thing is, I have a class, name it ClassA with PropertyA, he na ClassB inheriting ClassA that overrides PropertyA using "new" like this:
[DataContract]
public class ClassA
{
[DataMember]
public string PropertyA { get; set; }
[DataMember]
public string PropertyB { get; set; }
}
[DataContract]
public class ClassB : ClassA
{
[DataMember]
public new int PropertyA { get; set; }
}
This should make ClassB "replace" the string PropertyA from ClassA for a int PropertyA in ClassB.
I expose ClassB in a service method like this:
public bool TellMeSomething(ClassB param) { .... whatever .... }
When I add the service reference in the client application, the classes imported show something like this:
public class ClassA
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
}
public class ClassB : ClassA
{
public int PropertyA1 { get; set; }
}
As you can notice, ClassB has no "new int PropertyA" anymore, but a "int PropertyA1". I guess the serializer finds the ancestor has a PropertyA already and doesn't know how to handle the "new" keyword to hide the "string PropertyA", so it creates a new name for the PropertyA in the inherited class...
Is there any way to avoid this behavior? I would need that property to be called like it should...
You should use generics instead of identifier re-using:
[DataContract]
public class ClassA<T>
{
[DataMember]
public T PropertyA { get; set; }
[DataMember]
public int PropertyB { get; set; }
}
// No need to override PropertyA since T is int and ClassB
// inherits both PropertyA and PropertyB...
[DataContract]
public class ClassB : ClassA<int>
{
}

Set requried field while Deserializing using Json.Net

I have a class Foo as follows
public class Foo
{
public ClassA A {get;set;}
public string B {get;set;}
}
public class ClassA
{
public string C {get;set;}
}
When I get a Json string (say fooJson), I want to deserialize it to a Foo object with following conditions
The object must have the property Foo.A
Foo.B is optional
Foo.A.C is optional
I tried using MissingMemberHandling = MissingMemberHandling.Error as a part of my JsonSerializerSettings. but that throws error even when Foo.B is missing.
If you want some properties to be optional and some required, the easiest way to achieve this is to mark up your classes with [JsonProperty] attributes indicating which properties are required, e.g.:
public class Foo
{
[JsonProperty(Required = Required.Always)]
public ClassA A { get; set; }
public string B { get; set; }
}
public class ClassA
{
public string C { get; set; }
}

Deserializing json issue - inherited linq2SQL object

I have used Linq-to-SQL objects in my web app. My base and inherited classes look like this:
//Base Class: this will define the attributes that is auto-generated
//when using Linq-2-SQL ORM. Note this class is a partial class
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Categories")]
[global::System.Runtime.Serialization.DataContractAttribute()]
public partial class Category : INotifyPropertyChanging, INotifyPropertyChanged
//Inherited Class:
[Serializable]
public class CategoryEntity : Category
{
private int _ActiveAdsCount;
public int ActiveAdsCount
{
get
{
return _ActiveAdsCount;
}
set
{
_ActiveAdsCount = value;
}
}
public int DisplaySequence { get; set; }
}
when serialize, the Json OUTPUT is (note the ActiveAdsCount and DisplaySequence values):
[{"ActiveAdsCount":3429,"DisplaySequence":99,"CategoryID":636,"ParentCategoryID":635,"CategoryName":"propForRent","CategoryImageFN":null}]
When I am calling the deserialze object method
result = JsonConvert.DeserializeObject<T>(responseText);
where T is List
Result: it shows "ActiveAdsCount" and "DisplaySequence" have 0 values while the json shows proper correct information coming from Database. So, the problem is in deserialization.
I am using 4.5.1 version of Newtonsoft.Json.dll of .Net 4.0 framework
Moreover, I have marked my CategoryEntity class with DataContract attribute and its members to Datamember for serialization purpose. I notice that the Serialization attribute is making only the instance as serializable but not its members. So, the new class look like this:
[DataContract]
public class CategoryEntity : Category
{
[DataMember]
public int ActiveAdsCount { get; set; }
[DataMember]
public int DisplaySequence { get; set; }
[DataMember]
public IList<CategoryEntity> SubCategories { get; set; }
[DataMember]
public IList<BasicCategoryInfo> SubCategoriesBasicInfoList { get; set; }
[DataMember]
public string ParentCategoryNameEn { get; set; }
[DataMember]
public int CityID { get; set; }
}
#JasonJong Thanks very much for your comment.

DataContract and inheritance?

How to use DataContract with inheritance? Will code below work?
[DataContract]
public class ConsoleData
{
[DataMember]
public String Description { get; set; }
}
[DataContract]
public class SomeData : ConsoleData
{
[DataMember]
public int Volume { get; set; }
......
Yes, that would work.
The DataContractAttribute has Inherited set to false, so it is necessary to apply the attribute to both the child class and the parent class (as you have done in the question).
You would need to use the KnownType attribute if you want to use your data contracts with polymorphism.
For example
[ServiceContract]
interface MyWcfContract
{
[OperationContract]
HandleData(ConsoleData contractData);
}
If you invoked the method like so:
SomeData someData = new SomeData { Description = "Test", Volume = 30 };
// The method is expecting a ConsoleData instance,
// I'm passing a SomeData instance instead
myWcfProxy.HandleData(someData);
Then the deserializer on the service end will not know that it's an instance of SomeData, just an instance of ConsoleData which it was expecting.
The way to fix this is to register the SomeData class as a known type of the ConsoleData.
[DataContract]
[KnownType(typeof(SomeData))]
public class ConsoleData
{
[DataMember]
public String Description { get; set; }
}
[DataContract]
public class SomeData : ConsoleData
{
[DataMember]
public int Volume { get; set; }
......
You'll need to use the KnownType attribute if you are using the XmlSerializerFormat for your ServiceContract:
[DataContract]
public class ConsoleData
{
[DataMember]
public String Description { get; set; }
}
[DataContract, KnownType(typeof(ConsoleData))]
public class SomeData : ConsoleData
{
[DataMember]
public int Volume { get; set; }
}

Categories

Resources