JIL json serializer does not serialize properties from derived class - c#

JIL json serializer does not serialize properties from derived class
Below are the code snippet:
public async Task WriteAsync(OutputFormatterWriteContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var response = context.HttpContext.Response; response.ContentType = "application/json";
using (var writer = context.WriterFactory(response.Body, Encoding.UTF8))
{
Jil.JSON.Serialize(context.Object, writer);
await writer.FlushAsync();
}
}
1) Model Type:
public class BaseBOResponse
{
public string pk { get; set; }
}
public class PaymentTypeBOResponse : BaseBOResponse
{
public string description { get; set; }
public bool isSystem { get; set; }
public bool isActive { get; set; }
}
Here when i set something to BaseBOResponse's response property "pk", then JIL serializer eliminate this property.
Please suggest if you have any solution.

You have to tell Jil to include inherited properties as well:
Jil.JSON.Serialize(context.Object, writer, Jil.Options.IncludeInherited);

Related

Json not serializing all object in Azure

I have POCO which is as simple as
public partial class Member
{
public int ID { get; set; }
[Required]
[StringLength(100)]
public string MemberId { get; set; }
public DateTime CreatedOn { get; set; }
[Required]
[StringLength(100)]
public string FirstName { get; set; }}
and a Add command which looks like this
public class AddMemberCommand : ICommand
{
public AddMemberCommand(Member member )
{
ID = Guid.NewGuid();
MemberData = member;
}
public Member MemberData { get; private set; }
public Guid ID { get; }
public string CommandName
{
get { return "AddMemberCommand"; }
}
}
which inherits from
public interface ICommand
{
/// <summary>
/// Gets the command identifier.
/// </summary>
Guid ID { get; }
string CommandName { get; }
}
Now I send this code to a method which initializes Newton Json's serializing setting class with some parameters to return an object. The serializer looks like this
public class JsonTextSerializer
{
private readonly JsonSerializer _serializer;
public JsonTextSerializer()
{
_serializer = JsonSerializer.Create(new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
});
}
public void Serialize(TextWriter writer, object graph)
{
var jsonWriter = new JsonTextWriter(writer);
jsonWriter.Formatting = Formatting.Indented;
_serializer.Serialize(jsonWriter, graph);
writer.Flush();
}
public object Deserialize(TextReader reader)
{
var jsonReader = new JsonTextReader(reader);
try
{
return this._serializer.Deserialize(jsonReader);
}
catch (JsonSerializationException e)
{
// Wrap in a standard .NET exception.
throw new SerializationException(e.Message, e);
}
}
}
The serializer is used to convert the command into a payload for the brokered message as shown below
private BrokeredMessage CreateMessage(POCOS.Member member)
{
var serializer = new JsonTextSerializer();
var command = new AddMemberCommand(member);
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
serializer.Serialize(writer, command);
stream.Position = 0;
BrokeredMessage message = new BrokeredMessage(stream, true);
return message;
}
and there is a another method which receives the method
private POCOS.Member GetPocoFromMessage(BrokeredMessage message)
{
ITextSerializer serializer = new JsonTextSerializer();
AddMemberCommand command;
using (var stream = message.GetBody<Stream>())
{
using (var reader = new StreamReader(stream))
{
var payload = serializer.Deserialize(reader);
command = payload as AddMemberCommand;
}
}
return command.MemberData;
}
The issue is on deserializing some properties ( ID, CommandName) are filled with value except for MemberData which is null.
I can read the stream (by doing a reader.ReadToEnd()) and see it was transferred over the wire but Json can't deserialize all its object
At one time I also thought it perhaps picks only fields in the Interface but that's not the case
Your MemberData property has a private setter. Since the serializer needs access to the property externally, this setter should be public.

Ignore null values - Serialization

How can I set up the System.Runtime.Serialization serializer to ignore null values?
Or do I have to use the XmlSerializer for that? If so, how?
(I don't want <ecommerceflags i:nil="true"/> tags like this to be written, if it's null then just skip it)
With System.Runtime.Serialization.DataContractSerializer you need to mark the property with [DataMember(EmitDefaultValue = false)].
Example, the code below:
class Program
{
static void Main()
{
Console.WriteLine(SerializeToString(new Person { Name = "Alex", Age = 42, NullableId = null }));
}
public static string SerializeToString<T>(T instance)
{
using (var ms = new MemoryStream())
{
var serializer = new DataContractSerializer(typeof(T));
serializer.WriteObject(ms, instance);
ms.Seek(0, SeekOrigin.Begin);
using (var sr = new StreamReader(ms))
{
return sr.ReadToEnd();
}
}
}
}
[DataContract]
public class Person
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
[DataMember(EmitDefaultValue = false)]
public int? NullableId { get; set; }
}
prints the following:
<Person xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication4" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Age>42</Age>
<Name>Alex</Name>
</Person>
Though it has less value (except that it makes the serialized stream shorter), you can customize your serialization to achieve this.
When using System.Runtime.Serialization, you can implement the ISerializable interface:
[Serializable]
public class MyClass: ISerializable
{
private string stringField;
private object objectField;
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (stringField != null)
info.AddValue("str", stringField);
if (objectField != null)
info.AddValue("obj", objectField);
}
// the special constructor for deserializing
private MyClass(SerializationInfo info, StreamingContext context)
{
foreach (SerializationEntry entry in info)
{
switch (entry.Name)
{
case "str":
stringField = (string)entry.Value;
break;
case "obj":
objectField = entry.Value;
break;
}
}
}
}
When using XML serialization, you can implement the IXmlSerializable interface to customize the output in a similar way.
As far as I read, you could use the Specified-Feature
public int? Value { get; set; }
[System.Xml.Serialization.XmlIgnore]
public bool ValueSpecified { get { return this.Value != null; } }
To only write it if it's specified.
Another way would be
[System.Xml.Serialization.XmlIgnore]
private int? value;
public int Value { get { value.GetValueOrDefault(); } }

How to Customize json? How can override WriteToStreamAsync method in the MediaTypeFormatter for the customization of json Result

I have a webApi Application which is a migration from an existing Api, as per client need json and xml result (which is specified within the URL http://localhost:1518/api/List?type=regions&format=json), So In my application i have a class for xml and json result
public class ContinentData
{
[JsonProperty(PropertyName = "id")]
[XmlElement(ElementName = "id")]
public string Id { get; set; }
[XmlElement(ElementName = "name")]
[JsonProperty(PropertyName = "name")]
public string Name { get; set; }
}
[XmlRoot("response_item")]
public class ContinentsList
{
[XmlArray("regions")]
[XmlArrayItem("region")]
[JsonProperty(PropertyName = "regions")]
public List<ContinentData> Region { get; set; }
public ContinentsList()
{
Region = new List<ContinentData>();
}
}
[XmlRoot("response")]
public class Continents
{
[XmlElement("response_item")]
public ContinentsList Regions { get; set; }
public Continents()
{
Regions = new ContinentsList();
}
}
and I get the xml output,
<response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<response_item>
<regions>
<region>
<id>AFRICA</id>
<name>Africa</name>
</region>
</response_item>
</response>
which is fine, but for the json result i get
{"Regions":{"regions":[{"id":"AFRICA","name":"Africa"}]}}
But what i really want [{"regions":[{"id":"AFRICA","name":"Africa"}]}]I think that there is one class less for the json results. All of my json result is like that.So I try to customize by creating a customJsonFormatter class and Overrides WriteToStreamAsync method in the MediaTypeFormatter class, I do not know this is right method, but i try
public class CustomJsonFormatter : MediaTypeFormatter
{
public CustomJsonFormatter()
{
SupportedMediaTypes.Add(
new MediaTypeHeaderValue("application/json"));
SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/json"));
}
public override bool CanReadType(Type type)
{
if (type == (Type)null)
throw new ArgumentNullException("type");
return true;
}
public override bool CanWriteType(Type type)
{
return true;
}
public override Task WriteToStreamAsync(Type type, object value,
Stream writeStream, System.Net.Http.HttpContent content,
System.Net.TransportContext transportContext)
{
var task = Task.Factory.StartNew( () =>
{
// logic here
var json = JsonConvert.SerializeObject(value);
byte[] buf = System.Text.Encoding.Default.GetBytes(json);
writeStream.Write(buf, 0, buf.Length);
writeStream.Flush();
});
return task;
}
}
The Global.asax file
protected void Application_Start()
{
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(
new QueryStringMapping("format", "json", new MediaTypeHeaderValue("application/json")));
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(
new QueryStringMapping("format", "xml", new MediaTypeHeaderValue("application/xml")));
GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
GlobalConfiguration.Configuration.Formatters.Add(new CustomJsonFormatter());
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.JsonFormatter);
}
While run the application and I get the xml result as default if the format is json in the URL, and also not hit on WriteToStreamAsync method in the customJsonFormatter class. How can I do this? Is this proper way? Suggest solution for this
For the xml case you get your xml formatted to add response_item tag by using the XmlElement attribute. Similarly to work with Newtonsoft (assuming from the serializer syntax) you can your Json specific attribute.
[JsonProperty("response_item")]
[XmlElement("response_item")]
public ContinentsList Regions { get; set; }
Over the property Regions.

Problems with implementation of the factory pattern

I work with web service, and I'm get response from service. Response will be have different structure. For example, API getInfo return response:
{"code":0,"message":"","result":{"nickname":"UserName","age":"22"}}
API signin:
{"code":0,"message":"","result":"user_token"}
etc.
I use HttpWebRequest for POST request. Request and response deserialize/serialize with DataContractSerializer.
So, I want to use factory pattern, this is my implementation:
[DataContract]
public class ResultGetInfo
{
[DataMember(Name = "nickname")]
public int Nickname { get; set; }
[DataMember(Name = "age")]
public int Age { get; set; }
}
[DataContract]
public abstract class Response
{
}
[DataContract]
public class ResponseSignin : Response
{
[DataMember(Name = "code")]
public int Code { get; set; }
[DataMember(Name = "message")]
public string Message { get; set; }
[DataMember(Name = "result")]
public string Result { get; set; }
}
[DataContract]
public class ResponseGetInfo : Response
{
[DataMember(Name = "code")]
public int Code { get; set; }
[DataMember(Name = "message")]
public string Message { get; set; }
[DataMember(Name = "result")]
public ResultGetInfo Result { get; set; }
}
public abstract class CreateResponse
{
public abstract Response CreateResponseObj();
}
public class CreateResponseSignin : CreateResponse
{
public override Response CreateResponseObj()
{
return new ResponseSignin();
}
}
public class CreateResponseGetInfo : CreateResponse
{
public override Response CreateResponseObj()
{
return new ResponseGetInfo();
}
}
I get response in callback function:
private void getResponseCallback(IAsyncResult asynchronousResult)
{
var request = (Request)asynchronousResult.AsyncState;
try
{
HttpWebResponse response;
// End the get response operation
response = (HttpWebResponse)request.HttpRequest.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamReader = new StreamReader(streamResponse);
var gyResponse = streamReader.ReadToEnd();
streamResponse.Close();
streamReader.Close();
response.Close();
Response response_obj = request.Creater.CreateResponseObj();
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(gyResponse)))
{
var serializer = new DataContractJsonSerializer(response_obj.GetType());
response_obj = (Response)serializer.ReadObject(stream);
if (request.CallBack != null)
{
request.CallBack.Invoke(response_obj, null);
}
}
}
catch (WebException e)
{
if (request.CallBack != null)
{
request.CallBack.Invoke(null, e);
}
}
}
For DataContractJsonSerializer I declare the type here:
var serializer = new DataContractJsonSerializer(response_obj.GetType());
Where response_obj is object, which has needed type (ResponseSignin or ResponseGetInfo).
So, I call Invoke() in my delegate.
private void ResponseHandler(Response result, Exception error)
{
if (error != null)
{
string err = error.Message;
}
else
{
Response response = result;
}
}
And here I have a problem. Variable result really contains correct answer, but I don't get properties, because abstract class Response is without properties. And I can't declare properties or override in derived classes. I'm not sure that chose the desired pattern.
Have you tried just casting the result variable to the type you need?
E.g.
private void ResponseHandler(Response result, Exception error)
{
if (error != null)
{
string err = error.Message;
return;
}
var signInResponse = result as ResponseSignin;
if (signInResponse != null)
{
HandleSignInResponse(signInResponse);
}
var infoResponse = result as ResponseGetInfo;
if (infoResponse != null)
{
HandleInfoResponse(infoResponse);
}
}

C# XML Deserialize Array elements null

I'm trying to deserialize a reponse from a REST API.
"<FieldListDTO xmlns=\"api.playcento.com/1.0\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">
<Allfield>
<FieldDTO>
<Fieldname>Mobile nr</Fieldname>
<Fieldtype>T</Fieldtype>
<Fieldvalue>003241234578</Fieldvalue>
<Fk_id_page>CP584ea74ce5ad4e2d8561d75fc6944f96</Fk_id_page>
<Id_field>FI152dcde5ef9849898b12d6a3f2cdb4ee</Id_field>
<Required>true</Required>
</FieldDTO>
</Allfield>
<Totalcount>1</Totalcount>
</FieldListDTO>"
The Field class:
namespace PlaycentoAPI.Model
{
[XmlRoot("FieldListDTO",Namespace = "api.playcento.com/1.0")]
[XmlType("FieldListDTO")]
public class FieldListDTO
{
public FieldListDTO() { }
[XmlElement("Totalcount")]
public int TotalCount { get; set; }
[XmlArray("Allfield")]
[XmlArrayItem("FieldDTO", typeof(Field))]
public Field[] Field { get; set; }
}
[XmlRoot("FieldDTO", Namespace = "api.paycento.com/1.0")]
[XmlType("FieldDTO")]
public class Field
{
public Field()
{
}
[XmlElement("Id_field")]
public string ID_Field { get; set; }
[XmlElement("Fieldtype")]
public string FieldType { get; set; }
[XmlElement("Fk_id_page")]
public string FK_ID_PAGE { get; set; }
[XmlElement("Required")]
public bool Required { get; set; }
[XmlElement("Fieldname")]
public string FieldName { get; set; }
[XmlElement("Fieldvalue")]
public string FieldValue { get; set; }
}
}
My code which calls the API and deserializes it:
string response = Helper.PerformAndReadHttpRequest(uri, "GET", "");
FieldListDTO myObject;
XmlReaderSettings settings = new XmlReaderSettings();
using (StringReader textReader = new StringReader(response))
{
using (XmlReader xmlReader = XmlReader.Create(textReader, settings))
{
XmlSerializer mySerializer = new XmlSerializer(typeof(FieldListDTO));
myObject = (FieldListDTO)mySerializer.Deserialize(xmlReader);
}
}
return myObject.Field;
In my actual response, I'm getting back 14 FieldDTO's. After deserializing the xml, FieldListDTO myObject contains TotalCount = 14 and Field is an array containing 14 Field's. But all the properties of these fields are NULL (or false).
I'm using the same method for several other API calls. I've compared the classes and the only difference that I see is that the class (Field) has an bool property. So I thought that was the problem. I've changed the bool property to a string but still all the properties were NULL after deserialization.
First thing to catch my eye is that the namespace in your FieldDTO class doesn't match the one in the XML document.
"api.paycento.com/1.0"
"api.playcento.com/1.0"

Categories