Rename DataMember during Serialization - datamember

I am trying to serialise a DataContract.....
I would like to Rename the DataMember.
This is my DataContract
[DataContract(Name = "Sample")]
[Serializable]
public struct Sample
{
public string CompanyName;
public string AddressLine;
[DataMember(Name="AddressLineRename")]
public string AddressLine2;
public string City;
}
it is serialised to:
<Sample>
<CompanyName>aaa</CompanyName>
<AddressLine>16 aaaa</AddressLine>
<AddressLine2>Unit 66</AddressLine2>
<City>Houston</City>
</Sample>
what i need is:
<Sample>
<CompanyName>aaa</CompanyName>
<AddressLine>16 aaaa</AddressLine>
<AddressLineRename>Unit 66</AddressLineRename>
<City>Houston</City>
</Sample>
I want the "AddressLine2" to be serialised to "AddressLineRename".
Thanks.

This solved to rename the DataMember.
[DataMember(Order = 2, Name = "AddressLineRename", IsRequired = true)]
[XmlElement("AddressLineRename")]
public string AddressLine2;

You may need to implement ISerializable to customize the serialization process yourself.
I think the code you would need to add would look something like:
public Sample(SerializationInfo info, StreamingContext context)
{
CompanyName = info.GetString("CompanyName");
// ...
AddressLine2 = info.GetString("AddressLineRename");
// ...
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("CompanyName", CompanyName);
// ...
info.AddValue("AddressLineRename", AddressLine2);
// ...
}
See the MSDN for ISerializable.

In my case I solved just adding the order parameter to DataMember
[DataMember(Order = 2, Name = "AddressLineRename")]
public string AddressLine2;
Don't know why..

Related

Json Serialize an interface's properties which have non primitive types [duplicate]

With a simple class/interface like this
public interface IThing
{
string Name { get; set; }
}
public class Thing : IThing
{
public int Id { get; set; }
public string Name { get; set; }
}
How can I get the JSON string with only the "Name" property (only the properties of the underlying interface) ?
Actually, when i make that :
var serialized = JsonConvert.SerializeObject((IThing)theObjToSerialize, Formatting.Indented);
Console.WriteLine(serialized);
I get the full object as JSON (Id + Name);
The method I use,
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type _InterfaceType;
public InterfaceContractResolver (Type InterfaceType)
{
_InterfaceType = InterfaceType;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
//IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
IList<JsonProperty> properties = base.CreateProperties(_InterfaceType, memberSerialization);
return properties;
}
}
// To serialize do this:
var settings = new JsonSerializerSettings() {
ContractResolver = new InterfaceContractResolver (typeof(IThing))
};
string json = JsonConvert.SerializeObject(theObjToSerialize, settings);
Improved version with nested interfaces + support for xsd.exe objects
Yet another variation here. The code came from http://www.tomdupont.net/2015/09/how-to-only-serialize-interface.html with the following improvements over other answers here
Handles hierarchy, so if you have an Interface2[] within an Interface1 then it will get serialized.
I was trying to serialize a WCF proxy object and the resultant JSON came up as {}. Turned out all properties were set to Ignore=true so I had to add a loop to set them all to not being ignored.
public class InterfaceContractResolver : DefaultContractResolver
{
private readonly Type[] _interfaceTypes;
private readonly ConcurrentDictionary<Type, Type> _typeToSerializeMap;
public InterfaceContractResolver(params Type[] interfaceTypes)
{
_interfaceTypes = interfaceTypes;
_typeToSerializeMap = new ConcurrentDictionary<Type, Type>();
}
protected override IList<JsonProperty> CreateProperties(
Type type,
MemberSerialization memberSerialization)
{
var typeToSerialize = _typeToSerializeMap.GetOrAdd(
type,
t => _interfaceTypes.FirstOrDefault(
it => it.IsAssignableFrom(t)) ?? t);
var props = base.CreateProperties(typeToSerialize, memberSerialization);
// mark all props as not ignored
foreach (var prop in props)
{
prop.Ignored = false;
}
return props;
}
}
Inspired by #user3161686, here's a small modification to InterfaceContractResolver:
public class InterfaceContractResolver<TInterface> : DefaultContractResolver where TInterface : class
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(typeof(TInterface), memberSerialization);
return properties;
}
}
You can use conditional serialization. Take a look at this link. Basicly, you need to implement the IContractResolver interface, overload the ShouldSerialize method and pass your resolver to the constructor of the Json Serializer.
An alternative to [JsonIgnore] are the [DataContract] and [DataMember] attributes. If you class is tagged with [DataContract] the serializer will only process properties tagged with the [DataMember] attribute (JsonIgnore is an "opt-out" model while DataContract is "op-in").
[DataContract]
public class Thing : IThing
{
[DataMember]
public int Id { get; set; }
public string Name { get; set; }
}
The limitation of both approaches is that they must be implemented in the class, you cannot add them to the interface definition.
You can add the [JsonIgnore] annotation to ignore an attribute.
I'd like to share what we ended up doing when confronted with this task. Given the OP's interface and class...
public interface IThing
{
string Name { get; set; }
}
public class Thing : IThing
{
public int Id { get; set; }
public string Name { get; set; }
}
...we created a class that is the direct implementation of the interface...
public class DirectThing : IThing
{
public string Name { get; set; }
}
Then simply serialized our Thing instance, deserialized it as a DirectThing, then Serialized it as a DirectThing:
var thing = new Thing();
JsonConvert.SerializeObject(
JsonConvert.DeserializeObject<DirectThing>(JsonConvert.SerializeObject(thing)));
This approach can work with a long interface inheritance chain...you just need to make a direct class (DirectThing in this example) at the level of interest. No need to worry about reflection or attributes.
From a maintenance perspective, the DirectThing class is easy to maintain if you add members to IThing because the compiler will give errors if you haven't also put them in DirectThing. However, if you remove a member X from IThing and put it in Thing instead, then you'll have to remember to remove it from DirectThing or else X would be in the end result.
From a performance perspective there are three (de)serialization operations happening here instead of one, so depending on your situation you might like to evaluate the performance difference of reflector/attribute-based solutions versus this solution. In my case I was just doing this on a small scale, so I wasn't concerned about potential losses of some micro/milliseconds.
Hope that helps someone!
in addition to the answer given by #monrow you can use the default [DataContract] and [DataMember]
have a look at this
http://james.newtonking.com/archive/2009/10/23/efficient-json-with-json-net-reducing-serialized-json-size.aspx
Finally I got when it will not work...
If you want to have inside another complex object it will not be properly serialized.
So I have made version which will extract only data stored in specific assembly and for types which have the same base interface.
So it is made as .Net Core JsonContractResolver.
In addition to data extraction it solves:
a) camelCase conversion before sending data to client
b) uses top most interface from allowed scope (by assembly)
c) fixes order of fields: field from most base class will be listed first and nested object will meet this rule as well.
public class OutputJsonResolver : DefaultContractResolver
{
#region Static Members
private static readonly object syncTargets = new object();
private static readonly Dictionary<Type, IList<JsonProperty>> Targets = new Dictionary<Type, IList<JsonProperty>>();
private static readonly Assembly CommonAssembly = typeof(ICommon).Assembly;
#endregion
#region Override Members
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
if (type.Assembly != OutputJsonResolver.CommonAssembly)
return base.CreateProperties(type, memberSerialization);
IList<JsonProperty> properties;
if (OutputJsonResolver.Targets.TryGetValue(type, out properties) == false)
{
lock (OutputJsonResolver.syncTargets)
{
if (OutputJsonResolver.Targets.ContainsKey(type) == false)
{
properties = this.CreateCustomProperties(type, memberSerialization);
OutputJsonResolver.Targets[type] = properties;
}
}
}
return properties;
}
protected override string ResolvePropertyName(string propertyName)
{
return propertyName.ToCase(Casing.Camel);
}
#endregion
#region Assistants
private IList<JsonProperty> CreateCustomProperties(Type type, MemberSerialization memberSerialization)
{
// Hierarchy
IReadOnlyList<Type> types = this.GetTypes(type);
// Head
Type head = types.OrderByDescending(item => item.GetInterfaces().Length).FirstOrDefault();
// Sources
IList<JsonProperty> sources = base.CreateProperties(head, memberSerialization);
// Targets
IList<JsonProperty> targets = new List<JsonProperty>(sources.Count);
// Repository
IReadOnlyDistribution<Type, JsonProperty> repository = sources.ToDistribution(item => item.DeclaringType);
foreach (Type current in types.Reverse())
{
IReadOnlyPage<JsonProperty> page;
if (repository.TryGetValue(current, out page) == true)
targets.AddRange(page);
}
return targets;
}
private IReadOnlyList<Type> GetTypes(Type type)
{
List<Type> types = new List<Type>();
if (type.IsInterface == true)
types.Add(type);
types.AddRange(type.GetInterfaces());
return types;
}
#endregion
}

Deserialization of reference types without parameterless constructor is not supported

I have this API
public ActionResult AddDocument([FromBody]AddDocumentRequestModel documentRequestModel)
{
AddDocumentStatus documentState = _documentService.AddDocument(documentRequestModel, DocumentType.OutgoingPosShipment);
if (documentState.IsSuccess)
return Ok();
return BadRequest();
}
And this is my request model
public class AddDocumentRequestModel
{
public AddDocumentRequestModel(int partnerId, List<ProductRequestModel> products)
{
PartnerId = partnerId;
Products = products;
}
[Range(1, int.MaxValue, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int PartnerId { get; private set; }
[Required, MustHaveOneElement(ErrorMessage = "At least one product is required")]
public List<ProductRequestModel> Products { get; private set; }
}
so when I'm trying to hit the API with this body
{
"partnerId": 101,
"products": [{
"productId": 100,
"unitOfMeasureId": 102,
"quantity":5
}
]
}
this is the request : System.NotSupportedException: Deserialization of reference types without parameterless constructor is not supported. Type 'Alati.Commerce.Sync.Api.Controllers.AddDocumentRequestModel'
I don't need parameterless constructor,because it doesn't read the body parameters.Is there any other way for deserialization?
You can achieve your desired result. You need to switch to NewtonsoftJson serialization (from package Microsoft.AspNetCore.Mvc.NewtonsoftJson)
Call this in Startup.cs in the ConfigureServices method:
services.AddControllers().AddNewtonsoftJson();
After this, your constructor will be called by deserialization.
Extra info: I am using ASP Net Core 3.1
Later Edit: I wanted to give more info on this, as it seems that this can also be achieved by using System.Text.Json, although custom implementation is necessary. The answer from jawa states that Deserializing to immutable classes and structs can be achieved with System.Text.Json, by creating a custom converter (inherit from JsonConverter) and registering it to the converters collection (JsonSerializerOptions.Converters) like so:
public class ImmutablePointConverter : JsonConverter<ImmutablePoint>
{
...
}
and then...
var serializeOptions = new JsonSerializerOptions();
serializeOptions.Converters.Add(new ImmutablePointConverter());
serializeOptions.WriteIndented = true;
Just in case someone have the same issue I had, I was using abstract class, once removed the abstract key word, it all worked just fine.
Just Add [JsonConstructor] before your constructor
like this
public class Person
{
public string Name { get; set; }
public int LuckyNumber { get; private set; }
[JsonConstructor]
public Person(int luckyNumber)
{
LuckyNumber = luckyNumber;
}
public Person() { }
}
There are still some limitations using System.Text.Json - have a look here: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to#table-of-differences-between-newtonsoftjson-and-systemtextjson
Deserialization without parameterless constructor using a parameterized constructor is not supported yet (but it's on their plan). You can implement your custom JsonConverter (like in this example: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to#deserialize-to-immutable-classes-and-structs) or - like Adrian Nasul above suggested: use Newtonsoft.Json and then you can use the [JsonConstructor] attribute
In my case I had set a class as internal and when I made it public it worked. The error message was really of little help with this specific circumstance.
Old (actual class name changed to ClassName in the example
internal class Rootobject
{
[JsonConstructor]
public Rootobject(ClassName className)
{
ClassName = className?? throw new ArgumentNullException(nameof(className));
}
public ClassName ClassName { get; set; }
}
New:
public class Rootobject
{
[JsonConstructor]
public Rootobject(ClassName className)
{
ClassName = branding ?? throw new ArgumentNullException(nameof(className));
}
public ClassName ClassName { get; set; }
}
In my case error, caused was inside InnerException. There is my class had a field with a custom class type that did not have a parameterless constructor. I've added a parameterless constructor to the inner class and the problem has gone away.

WCF serialization and IEnumerable<T> vs ICollection<T> inheritance

I am aware about the problem when creating custom collections that inherits from List<T> or ICollection<T> with additional custom properties:
public class MyCollection: List<int>
{
public string MyCustomProperty { get; set; }
}
As I know, such collection will passed throw WCF as ArrayOfInt and WCF will not serialize my custom property. The solution is to create the wrapper class that will manage collection inside and will have a custom property.
I want to make a nicer workaround for my needs...does IEnumerable<T> will have the same problem?
public class MyCollection: IEnumerable<int>
{
/**************/
/* Code that implements IEnumerable<int> and manages the internal List<T> */
/* I know I will not able to cast it to List<T>, but I don't need it. */
/* If I will need it, I will implement cast operators later */
/**************/
public string MyCustomProperty { get; set; }
}
Will the class above pass throw WCF include MyCustomProperty value?
Thanks
I tried it and it does not serialize custom property.
I just returned the entire class object from the service method. Result is still ArrayOfInt (i used List as container)
public class MyExtension: IEnumerable<int>
{
public string CustomString { get; set; }
private List<int> lst = new List<int>();
public void Add(int i)
{
lst.Add(i);
}
public IEnumerator<int> GetEnumerator()
{
return lst.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return lst.GetEnumerator();
}
}
I had to mark it as DataContract and every member as DataMember to have all the properties serialized.
<MyExtension xmlns="http://schemas.datacontract.org/2004/07/GetRequestTest" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<CustomString>sunny</CustomString>
<lst xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<a:int>1</a:int>
</lst>
</MyExtension>

Can I use string str="id" and then person.str=1?

I have a class call Person:
public class Person
{
public int id{get;set;}
public string name{get;set;}
//and many others
}
Is there a way to set value to property not in the regular way like: person.id=1
but use something like string str="id" and person.str=1?
I want that because I have many properties and I recieve list with the name of the property and his value. so I want to avoid long switch-case and use :
foreach(var item in MyList.Keys)
{
person.item=MyList[item];
}
public class Person
{
public int Id{get;set;}
public string Name{get;set;}
//and many others
}
Dictionary<string,object> properties = new Dictionary<string,object>();
properties.Add("Id",1);
properties.Add("Name", "TestName");
Person p = new Person();
foreach (KeyValuePair<string, object> obj in properties)
{
p.GetType().GetProperty(obj.Key).SetValue(p, obj.Value, null);
}
This might works for you. Make sure you have proper casing of propertyname.
You can use reflection for this or the dynamic type in .NET 4.0.

How to persist an enum using NHibernate

Is there a way to persist an enum to the DB using NHibernate? That is have a table of both the code and the name of each value in the enum.
I want to keep the enum without an entity, but still have a foreign key (the int representation of the enum) from all other referencing entities to the enum's table.
Why are you guys over complicating this? It is really simple.
The mapping looks like this:
<property name="OrganizationType"></property>
The model property looks like this:
public virtual OrganizationTypes OrganizationType { get; set; }
The Enum looks like this:
public enum OrganizationTypes
{
NonProfit = 1,
ForProfit = 2
}
NHibernate will automatically figure it all out. Why type more than you need????
You can use the enum type directly: http://web.archive.org/web/20100225131716/http://graysmatter.codivation.com/post/Justice-Grays-NHibernate-War-Stories-Dont-Use-Int-If-You-Mean-Enum.aspx. If your underlying type is a string, it should use the string representation, if it is numeric, it will just use the numeric representation.
But your question wording sounds like you're looking for something different, not quite an enum. It seems that you want a lookup table without creating a separate entity class. I don't think this can be done without creating a separate entity class though.
An easy but not so beautiful solution:
Create an integer field with and set the mapping in the mapping file to the field.
Create a public property that uses the integer field.
private int myField;
public virtual MyEnum MyProperty
{
get { return (MyEnum)myField; }
set { myField = value; }
}
I am using NHibernate 3.2, and this works great:
type="NHibernate.Type.EnumStringType`1[[enum_full_type_name, enum_assembly]], NHibernate"
Not sure when the generic EnumStringType got added, though.
Try using a stategy pattern. Uou can then put logic into your inner classes. I use this quite alot espically when there is logic that should be contained in the "enum". For example the code below has the abstract IsReadyForSubmission() which is then implemented in each of the nested subclasses (only one shown). HTH
[Serializable]
public abstract partial class TimesheetStatus : IHasIdentity<int>
{
public static readonly TimesheetStatus NotEntered = new NotEnteredTimesheetStatus();
public static readonly TimesheetStatus Draft = new DraftTimesheetStatus();
public static readonly TimesheetStatus Submitted = new SubmittedTimesheetStatus();
//etc
public abstract int Id { get; protected set; }
public abstract string Description { get; protected set; }
public abstract bool IsReadyForSubmission();
protected class NotEnteredTimesheetStatus: TimesheetStatus
{
private const string DESCRIPTION = "NotEntered";
private const int ID = 0;
public override int Id
{
get { return ID; }
protected set { if (value != ID)throw new InvalidOperationException("ID for NotEnteredTimesheetStatus must be " + ID); }
}
public override string Description
{
get { return DESCRIPTION; }
protected set { if (value != DESCRIPTION)throw new InvalidOperationException("The description for NotEnteredTimesheetStatus must be " + DESCRIPTION); }
}
public override bool IsReadyForSubmission()
{
return false;
}
}
//etc
}