How to serialize C# objects to generate specific JSON - c#

I am trying to create JSON like the following to pass to an external via TCP.
{"method": "dither", "params": [10, false, {"pixels": 1.5, "time": 8, "timeout": 40}], "id": 42}
I came close, but this is what I got instead:
{"method": "dither", "params": [10, false,"{"pixels": 1.5, "time": 8, "timeout": 40}"], "id": 42}
Notice the quote marks around the 3rd element of the params array.
I would appreciate any help in resolving this. Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Collections;
using System.Xml;
using System.Reflection;
namespace DitherTest
{
[CollectionDataContract]
public class DitherParametersList : ArrayList
{
public DitherParametersList() : base()
{}
}
[DataContract]
public class Dither
{
[DataMember( Name="method", Order=1)]
public string Method { get; set; }
[DataMember( Name="params", Order=2)]
public DitherParametersList Parameters { get; set; }
[DataMember( Name="id", Order=3)]
public int Id { get; set; }
}
[DataContract( Namespace="")]
public class Settle
{
[DataMember( Name = "pixels" )]
public double Pixels { get; set; }
[DataMember( Name = "time" )]
public int Time { get; set; }
[DataMember( Name = "timeout" )]
public int Timeout { get; set; }
public string SerializeJson()
{
return this.ToJSON();
}
}
static class Extensions
{
public static string ToJSON<T>( this T obj ) where T : class
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer( typeof( T ) );
using ( MemoryStream stream = new MemoryStream() )
{
serializer.WriteObject( stream, obj );
return Encoding.Default.GetString( stream.ToArray() );
}
}
}
class Program
{
static void Main( string[] args )
{
double ditherAmount = 10.0;
bool ditherRaOnly = false;
Settle settle = new Settle { Pixels = 1.5, Time = 8, Timeout = 40 };
DitherParametersList parameterList = new DitherParametersList();
parameterList.Add( ditherAmount );
parameterList.Add( ditherRaOnly );
string settleStr = settle.SerializeJson();
parameterList.Add( settleStr );
Dither dither = new Dither { Method = "dither", Parameters = parameterList, Id=42 };
string temp = dither.ToJSON();
}
}
}
Thanks in advance

you told it to make the third arg a string. You serialized it to a string then stuck it in as an arg.
you need
parameterList.Add( settle );

First of all, be sure to use newtonsoft.com/json like pm100 mentioned in his comment.
I've changed your code so that it would work with newtonsoft.json and got exactly what you've asked for:
{"method": "dither", "params": [10, false, {"pixels": 1.5, "time": 8, "timeout": 40}], "id": 42}
I removed the DitherParametersList you've created and used those models:
public class Dither
{
[JsonProperty("method", Order = 1)]
public string Method { get; set; }
[JsonProperty("params", Order = 2)]
public ArrayList Parameters { get; set; }
[JsonProperty("id", Order = 3)]
public int Id { get; set; }
}
public class Settle
{
[JsonProperty("pixels")]
public double Pixels { get; set; }
[JsonProperty("time")]
public int Time { get; set; }
[JsonProperty("timeout")]
public int Timeout { get; set; }
}
And serialized them easily:
class Program
{
static void Main(string[] args)
{
var settle = new Settle { Pixels = 1.5, Time = 8, Timeout = 40 };
var parameterList = new ArrayList { 10, false, settle };
var dither = new Dither { Method = "dither", Parameters = parameterList, Id = 42 };
string temp = JsonConvert.SerializeObject(dither);
}
}

The quotes are coming from the first serialization that you did here:
string settleStr = settle.SerializeJson();
Assuming that you want to avoid using the Newtonsoft library, an immediate fix would be to simply trim them off:
string settleStr = settle.SerializeJson().Trim('"');
A more robust solution would only require serialization one time. If you used a List{string} instead of a DitherParamtersList, you could do this:
Settle settle = new Settle { Pixels = 1.5, Time = 8, Timeout = 40 };
var parameterList = new List<string>()
{
ditherAmount.ToString(),
ditherRaOnly.ToString(),
string.Join(",", settle.Pixels, settle.Time, settle.Timeout)
};
Dither dither = new Dither { Method = "dither", Parameters = parameterList, Id = 42 };
string temp = dither.ToJSON();

Related

How to convert microsoft graph api json response to object [duplicate]

I have classes like these:
class MyDate
{
int year, month, day;
}
class Lad
{
string firstName;
string lastName;
MyDate dateOfBirth;
}
And I would like to turn a Lad object into a JSON string like this:
{
"firstName":"Markoff",
"lastName":"Chaney",
"dateOfBirth":
{
"year":"1901",
"month":"4",
"day":"30"
}
}
(Without the formatting). I found this link, but it uses a namespace that's not in .NET 4. I also heard about JSON.NET, but their site seems to be down at the moment, and I'm not keen on using external DLL files.
Are there other options besides manually creating a JSON string writer?
Since we all love one-liners
... this one depends on the Newtonsoft NuGet package, which is popular and better than the default serializer.
Newtonsoft.Json.JsonConvert.SerializeObject(new {foo = "bar"})
Documentation: Serializing and Deserializing JSON
Please Note
Microsoft recommends that you DO NOT USE JavaScriptSerializer
See the header of the documentation page:
For .NET Framework 4.7.2 and later versions, use the APIs in the System.Text.Json namespace for serialization and deserialization. For earlier versions of .NET Framework, use Newtonsoft.Json.
Original answer:
You could use the JavaScriptSerializer class (add reference to System.Web.Extensions):
using System.Web.Script.Serialization;
var json = new JavaScriptSerializer().Serialize(obj);
A full example:
using System;
using System.Web.Script.Serialization;
public class MyDate
{
public int year;
public int month;
public int day;
}
public class Lad
{
public string firstName;
public string lastName;
public MyDate dateOfBirth;
}
class Program
{
static void Main()
{
var obj = new Lad
{
firstName = "Markoff",
lastName = "Chaney",
dateOfBirth = new MyDate
{
year = 1901,
month = 4,
day = 30
}
};
var json = new JavaScriptSerializer().Serialize(obj);
Console.WriteLine(json);
}
}
Use Json.Net library, you can download it from Nuget Packet Manager.
Serializing to Json String:
var obj = new Lad
{
firstName = "Markoff",
lastName = "Chaney",
dateOfBirth = new MyDate
{
year = 1901,
month = 4,
day = 30
}
};
var jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
Deserializing to Object:
var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<Lad>(jsonString );
Use the DataContractJsonSerializer class: MSDN1, MSDN2.
My example: HERE.
It can also safely deserialize objects from a JSON string, unlike JavaScriptSerializer. But personally I still prefer Json.NET.
A new JSON serializer is available in the System.Text.Json namespace. It's included in the .NET Core 3.0 shared framework and is in a NuGet package for projects that target .NET Standard or .NET Framework or .NET Core 2.x.
Example code:
using System;
using System.Text.Json;
public class MyDate
{
public int year { get; set; }
public int month { get; set; }
public int day { get; set; }
}
public class Lad
{
public string FirstName { get; set; }
public string LastName { get; set; }
public MyDate DateOfBirth { get; set; }
}
class Program
{
static void Main()
{
var lad = new Lad
{
FirstName = "Markoff",
LastName = "Chaney",
DateOfBirth = new MyDate
{
year = 1901,
month = 4,
day = 30
}
};
var json = JsonSerializer.Serialize(lad);
Console.WriteLine(json);
}
}
In this example the classes to be serialized have properties rather than fields; the System.Text.Json serializer currently doesn't serialize fields.
Documentation:
System.Text.Json overview
How to use System.Text.Json
You can achieve this by using Newtonsoft.json. Install Newtonsoft.json from NuGet. And then:
using Newtonsoft.Json;
var jsonString = JsonConvert.SerializeObject(obj);
Wooou! Really better using a JSON framework :)
Here is my example using Json.NET (http://james.newtonking.com/json):
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using System.IO;
namespace com.blogspot.jeanjmichel.jsontest.model
{
public class Contact
{
private Int64 id;
private String name;
List<Address> addresses;
public Int64 Id
{
set { this.id = value; }
get { return this.id; }
}
public String Name
{
set { this.name = value; }
get { return this.name; }
}
public List<Address> Addresses
{
set { this.addresses = value; }
get { return this.addresses; }
}
public String ToJSONRepresentation()
{
StringBuilder sb = new StringBuilder();
JsonWriter jw = new JsonTextWriter(new StringWriter(sb));
jw.Formatting = Formatting.Indented;
jw.WriteStartObject();
jw.WritePropertyName("id");
jw.WriteValue(this.Id);
jw.WritePropertyName("name");
jw.WriteValue(this.Name);
jw.WritePropertyName("addresses");
jw.WriteStartArray();
int i;
i = 0;
for (i = 0; i < addresses.Count; i++)
{
jw.WriteStartObject();
jw.WritePropertyName("id");
jw.WriteValue(addresses[i].Id);
jw.WritePropertyName("streetAddress");
jw.WriteValue(addresses[i].StreetAddress);
jw.WritePropertyName("complement");
jw.WriteValue(addresses[i].Complement);
jw.WritePropertyName("city");
jw.WriteValue(addresses[i].City);
jw.WritePropertyName("province");
jw.WriteValue(addresses[i].Province);
jw.WritePropertyName("country");
jw.WriteValue(addresses[i].Country);
jw.WritePropertyName("postalCode");
jw.WriteValue(addresses[i].PostalCode);
jw.WriteEndObject();
}
jw.WriteEndArray();
jw.WriteEndObject();
return sb.ToString();
}
public Contact()
{
}
public Contact(Int64 id, String personName, List<Address> addresses)
{
this.id = id;
this.name = personName;
this.addresses = addresses;
}
public Contact(String JSONRepresentation)
{
//To do
}
}
}
The test:
using System;
using System.Collections.Generic;
using com.blogspot.jeanjmichel.jsontest.model;
namespace com.blogspot.jeanjmichel.jsontest.main
{
public class Program
{
static void Main(string[] args)
{
List<Address> addresses = new List<Address>();
addresses.Add(new Address(1, "Rua Dr. Fernandes Coelho, 85", "15º andar", "São Paulo", "São Paulo", "Brazil", "05423040"));
addresses.Add(new Address(2, "Avenida Senador Teotônio Vilela, 241", null, "São Paulo", "São Paulo", "Brazil", null));
Contact contact = new Contact(1, "Ayrton Senna", addresses);
Console.WriteLine(contact.ToJSONRepresentation());
Console.ReadKey();
}
}
}
The result:
{
"id": 1,
"name": "Ayrton Senna",
"addresses": [
{
"id": 1,
"streetAddress": "Rua Dr. Fernandes Coelho, 85",
"complement": "15º andar",
"city": "São Paulo",
"province": "São Paulo",
"country": "Brazil",
"postalCode": "05423040"
},
{
"id": 2,
"streetAddress": "Avenida Senador Teotônio Vilela, 241",
"complement": null,
"city": "São Paulo",
"province": "São Paulo",
"country": "Brazil",
"postalCode": null
}
]
}
Now I will implement the constructor method that will receives a JSON string and populates the class' fields.
If they are not very big, what's probably your case export it as JSON.
Also this makes it portable among all platforms.
using Newtonsoft.Json;
[TestMethod]
public void ExportJson()
{
double[,] b = new double[,]
{
{ 110, 120, 130, 140, 150 },
{1110, 1120, 1130, 1140, 1150},
{1000, 1, 5, 9, 1000},
{1110, 2, 6, 10, 1110},
{1220, 3, 7, 11, 1220},
{1330, 4, 8, 12, 1330}
};
string jsonStr = JsonConvert.SerializeObject(b);
Console.WriteLine(jsonStr);
string path = "X:\\Programming\\workspaceEclipse\\PyTutorials\\src\\tensorflow_tutorials\\export.txt";
File.WriteAllText(path, jsonStr);
}
If you are in an ASP.NET MVC web controller it's as simple as:
string ladAsJson = Json(Lad);
Can't believe no one has mentioned this.
I would vote for ServiceStack's JSON Serializer:
using ServiceStack;
string jsonString = new { FirstName = "James" }.ToJson();
It is also the fastest JSON serializer available for .NET:
http://www.servicestack.net/benchmarks/
Another solution using built-in System.Text.Json (.NET Core 3.0+) where an object is self-sufficient and doesn't expose all possible fields:
A passing test:
using NUnit.Framework;
namespace Intech.UnitTests
{
public class UserTests
{
[Test]
public void ConvertsItselfToJson()
{
var userName = "John";
var user = new User(userName);
var actual = user.ToJson();
Assert.AreEqual($"{{\"Name\":\"{userName}\"}}", actual);
}
}
}
An implementation:
using System.Text.Json;
using System.Collections.Generic;
namespace Intech
{
public class User
{
private readonly string name;
public User(string name)
{
this.name = name;
}
public string ToJson()
{
var params = new Dictionary<string, string>{{"Name", name}};
return JsonSerializer.Serialize(params);
}
}
}
In your Lad model class, add an override to the ToString() method that returns a JSON string version of your Lad object.
Note: you will need to import System.Text.Json;
using System.Text.Json;
class MyDate
{
int year, month, day;
}
class Lad
{
public string firstName { get; set; };
public string lastName { get; set; };
public MyDate dateOfBirth { get; set; };
public override string ToString() => JsonSerializer.Serialize<Lad>(this);
}
It is as easy as this (it works for dynamic objects as well (type object)):
string json = new
System.Web.Script.Serialization.JavaScriptSerializer().Serialize(MYOBJECT);
Here is another solution using Cinchoo ETL - an open source library
public class MyDate
{
public int year { get; set; }
public int month { get; set; }
public int day { get; set; }
}
public class Lad
{
public string firstName { get; set; }
public string lastName { get; set; }
public MyDate dateOfBirth { get; set; }
}
static void ToJsonString()
{
var obj = new Lad
{
firstName = "Tom",
lastName = "Smith",
dateOfBirth = new MyDate
{
year = 1901,
month = 4,
day = 30
}
};
var json = ChoJSONWriter.Serialize<Lad>(obj);
Console.WriteLine(json);
}
Output:
{
"firstName": "Tom",
"lastName": "Smith",
"dateOfBirth": {
"year": 1901,
"month": 4,
"day": 30
}
}
Disclaimer: I'm the author of this library.
Serializer
public static void WriteToJsonFile<T>(string filePath, T objectToWrite, bool append = false) where T : new()
{
var contentsToWriteToFile = JsonConvert.SerializeObject(objectToWrite, new JsonSerializerSettings
{
Formatting = Formatting.Indented,
});
using (var writer = new StreamWriter(filePath, append))
{
writer.Write(contentsToWriteToFile);
}
}
Object
namespace MyConfig
{
public class AppConfigurationSettings
{
public AppConfigurationSettings()
{
/* initialize the object if you want to output a new document
* for use as a template or default settings possibly when
* an app is started.
*/
if (AppSettings == null) { AppSettings=new AppSettings();}
}
public AppSettings AppSettings { get; set; }
}
public class AppSettings
{
public bool DebugMode { get; set; } = false;
}
}
Implementation
var jsonObject = new AppConfigurationSettings();
WriteToJsonFile<AppConfigurationSettings>(file.FullName, jsonObject);
Output
{
"AppSettings": {
"DebugMode": false
}
}

'List<Choice>' does not contain a definition for 'ChoiceId ' and no extension...are you missing a using directive or an assembly reference?)

Title is just a part of the error, here is one of many error:
'List' does not contain a definition for 'ChoiceId' and no extension method 'ChoiceId' accepting a first argument of type 'List' could be found (are you missing a using directive or an assembly reference?)
I am trying to unit test a list of RepaymentPlan as stated below. But I can not seem to fetch the rest of the values in that list since I get red underline error below those keys (I have wrapped those keys with ** ** in unit test below. Something wrong I am doing and not sure how to solve it.
Still learning and fresh new to programming so hopefully you guys can guide me in the right way. Really appreciate your help.
Here is what I have:
Models:
using System.Collections.Generic;
namespace Project.Models
{
public class Repayment
{
public int Amount { get; set; }
public string DueDate { get; set; }
public string RepaymentId { get; set; }
}
public class Choice
{
public string ChoiceId { get; set; }
public List<Repayment> Repayments{ get; set; }
}
public class RepaymentPlan
{
public List<Choice> Choices{ get; set; }
}
}
Repositories:
using System.Collections.Generic;
using System.Linq;
using Project.Models;
using System.Net;
using System.Collections.Specialized;
using System.Text;
namespace Project.Repositories
{
public class OrderRepository
{
private static List<RepaymentPlan> _RepaymentPlan;
static OrderRepository()
{
_RepaymentPlan = new List<RepaymentPlan>();
_RepaymentPlan.Add(new RepaymentPlan
{
Choices = new List<Choice>
{
new Choice
{
ChoiceId = "cho1",
Repayments = new List<Repayment>
{
new Repayment
{
Amount = 200,
DueDate = "2018-06-01"
},
new Repayment
{
Amount = 100,
DueDate = "2018-08-01",
}
}
},
new Choice
{
ChoiceId = "cho2",
Repayments = new List<Repayment>
{
new Repayment
{
RepaymentId = "Choice1",
Amount = 300,
DueDate = "2018-10-01"
},
new Repayment
{
RepaymentId = "Choice2",
Amount = 150,
DueDate = "2018-11-01"
},
}
}
},
});
}
* Unit test *
[Test]
public void ListRepaymentPlan()
{
// Arrange
var controller = new CaseController();
var expectedResult = new List<RepaymentPlan>();
var repaymentPlan = new RepaymentPlan()
{
Choices = new List<Choice>
{
new Choice
{
ChoiceId = "cho1",
Repayments = new List<Repayment>
{
new Repayment
{
Amount = 200,
DueDate = "2018-06-01"
},
new Repayment
{
Amount = 100,
DueDate = "2018-08-01"
},
}
},
new Choice
{
ChoiceId = "cho2",
Repayments = new List<Repayment>
{
new Repayment
{
RepaymentId = "Choice1",
Amount = 300,
DueDate = "2018-10-01"
},
new Repayment
{
RepaymentId = "Choice2",
Amount = 150,
DueDate = "2018-11-01"
},
}
}
},
};
expectedResult.Add(RepaymentPlan );
// Act
var actionResult = controller.FindRepaymentPlan("578", "156");
var result = (List<RepaymentPlan >)actionResult;
// Assert
for (var i = 0; i < result.Count; i++)
{
Assert.AreEqual(expectedResult[i].Choices , result[i].Choices);
Assert.AreEqual(expectedResult[i].Choices.**ChoiceId**, result[i].Choices.**ChoiceId**);
Assert.AreEqual(expectedResult[i].Choices.**ChoiceId**.Repayments, result[i].Choices.**ChoiceId**.Repayments);
Assert.AreEqual(expectedResult[i].Choices.**Repayments**.Amount, result[i].Choices.**Repayments**.Amount);
Assert.AreEqual(expectedResult[i].Choices.**Repayments**.DueDate, result[i].Choices.**Repayments**.DueDate);
}
}
** Updated unit test **
// Assert
for (var i = 0; i < result.Count; i++)
{
CollectionAssert.AreEqual(expectedResult[i].Choices, result[i].Choices);
CollectionAssert.AreEqual(expectedResult[i].Choices[0].ChoiceId, result[i].Choices[0].ChoiceId);
CollectionAssert.AreEqual(expectedResult[i].Choices[0].Repayments, result[i].Choices[0].Repayments);
CollectionAssert.AreEqual(expectedResult[i].Choices, result[i].Choices);
CollectionAssert.AreEqual(expectedResult[i].Choices[1].ChoiceId, result[i].Choices[1].ChoiceId);
CollectionAssert.AreEqual(expectedResult[i].Choices[1].Repayments, result[i].Choices[1].Repayments);
}
Choices is a List<> so you need to index it too, something like this:
expectedResult[i].Choices[0].ChoiceId
However, you'd have to loop around those inner values too. It's much easier to use CollectionAssert:
CollectionAssert.AreEqual(expectedResult, result);

No output of data in JSON - getting 204 error code

I'm trying to output a Paymentplan for a specific customer with a specific order.
I keep getting this error:
info:Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[1]
Executing ObjectResult, writing value of type 'null'.
There is something I'm doing wrong but I'm not sure what it is. Looked for solutions for a long time with no luck. I'm new to programming and C# so still trying to get hang of this. Really appreciate your help and guidance.
Here is what I have so far:
Models:
using System.Collections.Generic;
namespace Project.Models
{
public class Customer
{
public string CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string DateOfBirth { get; set; }
}
public class Order
{
public string OrderId { get; set; }
public string Product { get; set; }
public string Status { get; set; }
public double Price { get; set; }
}
public class CustomerOrder
{
public string CustomerId {get; set;}
public string OrderId { get; set; }
}
public class Repayment
{
public int Amount { get; set; }
public string DueDate { get; set; }
public string RepaymentId { get; set; }
}
public class Choice
{
public string ChoiceId { get; set; }
public List<Repayment> Repayments{ get; set; }
}
public class RepaymentPlan
{
public List<Choice> Choices{ get; set; }
}
}
Repositories:
using System.Collections.Generic;
using System.Linq;
using Project.Models;
using System.Net;
using System.Collections.Specialized;
using System.Text;
namespace Project.Repositories
{
public class OrderRepository
{
private static List<Order> _Orders;
private static List<CustomerOrder> _CustomerOrder;
private static List<RepaymentPlan> _RepaymentPlan;
static OrderRepository()
{
_Orders = new List<Order>();
_CustomerOrder= new List<CustomerOrder>();
_PaymentPlan = new List<PaymentPlan>();
_Orders.Add(new Order
{
OrderId = "124",
Product= "Shirts",
Status= "On it's way",
Price= 100.20,
});
_Orders.Add(new Order
{
OrderId= "122",
Product= "Pants",
Status= "Not ready",
Price= 300.30,
});
_Orders.Add(new Order
{
OrderId= "143",
Product= "Deadpool",
Status= "On it's way",
Price= 6.20,
});
_Orders.Add(new Order
{
OrderId= "156",
Product= "Socks",
Status= "Not ready",
Price= 3.30,
});
_CustomerOrder.Add(new CustomerOrder
{
CustomerId = "578",
OrderId = "156",
});
_RepaymentPlan.Add(new RepaymentPlan
{
choices = new List<Choice>
{
new Choice
{
choiceId = "cho1",
Repayments = new List<Repayment>
{
new Repayment
{
amount = 200,
dueDate = "2018-06-01"
},
new Repayment
{
amount = 100,
dueDate = "2018-08-01",
}
}
},
new Choice
{
choiceId = "cho2",
repayments = new List<Repayment>
{
new Repayment
{
repaymentId = "Choice1",
amount = 300,
dueDate = "2018-10-01"
},
new Repayment
{
repaymentId = "Choice2",
amount = 150,
dueDate = "2018-11-01"
},
}
}
},
});
}
public static RepaymentPlan GetRepaymentPlan(string customerId, string orderId)
{
var customerlist =_CustomerOrder.FindAll(c => c.CustomerId==customerId);
var orderlist= _CustomerOrder.FindAll(c => c.orderId==orderId);
var pplist= new RepaymentPlan();
if (customerlist == orderlist)
{
return pplist;
}
return null;
}
Controllers:
OrderController.cs:
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Mvc;
using Project.Models;
using Project.Repositories;
namespace Project.Controllers
{
public class OrderController : Controller
{
[HttpGet("customers/{customerid}/orders/{orderId}/paymentPlan")]
public RepaymentPlan FindRepaymentPlan(string customerId, string orderId)
{
return OrderRepository.GetRepaymentPlan(customerId, orderId);
}
}
}
OK, after a closer scan of your code, I see that the problem is in this method
public static RepaymentPlan GetRepaymentPlan(string customerId, string orderId)
You will always return null because your condition will always evaluate to false. This is available for any (probably) programming language.
if (customerlist == orderlist) evaluates if the two objects are identical (they reference the same memory address), it doesn't evaluate the content of the objects. To see if two object have the same data, you can use a loop (for, while). But since you used Linq, it is enough to use multiple conditions in FindAll function.
public static RepaymentPlan GetRepaymentPlan(string customerId, string orderId)
{
var customerlist =_CustomerOrder.FindAll(c => c.CustomerId==customerId && c.orderId==orderId);
var pplist= new RepaymentPlan();
if (customerlist.Any())
{
return pplist;
}
return null;
}
Also, you may want to return customerlist.First() instead of pplist. If you return an empty object of type RepaymentPlan, it might not help you.

Polymorphism not working on collections elements using MessagePack-Csharp nuget

I'm not being able to deserialize a collection of elements where the instances have a Inheritance relationship between them.
Does anyone came across this issue?
So my use case is this:
My model is similiar to this:
[DataContract]
public class Item
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public bool Valid { get; set; }
}
[DataContract]
public class IntermediateItem : Item
{
[DataMember]
public int Priority { get; set; }
}
[DataContract]
public class ExtendedItem : IntermediateItem
{
[DataMember]
public int Count { get; set; }
[DataMember]
public ItemsCollection Childs { get; set; }
}
And Items Collection is something like this:
[DataContract]
public class ItemsCollection : Collection<Item>
{
}
The setup that I have made to ensure the proper deserialization is:
Defining the CollectionFormatterBase:
public class ItemCollectionFormatterBase : CollectionFormatterBase<Item, ItemsCollection>
{
protected override ItemsCollection Create(int count)
{
return new ItemsCollection();
}
protected override void Add(ItemsCollection collection, int index, Item value)
{
collection.Add(value);
}
}
The example that is not working, and not working I mean, the deserialized instances are all of base type, some how the inheritance relationship got lost in the serialization.
Example:
MessagePack.Resolvers.CompositeResolver.RegisterAndSetAsDefault(new[] { new ItemCollectionFormatterBase() }, new[] { StandardResolver.Instance });
ExtendedItem instance = new ExtendedItem()
{
Id = 1,
Name = "Extended Item",
Priority = 121,
Valid = true,
Count = 10,
Childs = new ItemsCollection(new List<Item>() { new Item() { Id = 1 }, new IntermediateItem() { Priority = 10 }, new ExtendedItem() { Count = 10 } })
};
byte[] bytes = MessagePackSerializer.Serialize(instance);
using (FileStream file = new FileStream(this.filePath.AbsolutePath, FileMode.Create))
{
await file.WriteAsync(bytes , 0, payload.Length);
await file.FlushAsync();
}
using (FileStream file = new FileStream(testsFolder + #"\ExtendedItem.msgPack-csharp.dat", FileMode.Open))
{
file.Seek(0, SeekOrigin.Begin);
deserializedInstance = MessagePackSerializer.Deserialize<ExtendedItem>(file);
}
looking at the deserializedInstance Childs elements they all are from Item Type.
Can you tell me what I'm doing wrong ? What is missing ?
A small update regarding Item definition:
[DataContract]
[KnownType(typeof(IntermediateItem))]
[KnownType(typeof(ExtendedItem))]
public class Item
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public bool Valid { get; set; }
}
This also does not work. :(
Well looks like MessagePackSerializer static type as a static inner class called Typeless and that solve my problem:
With a instance of a ExtendedItem:
ExtendedItem instance = new ExtendedItem()
{
Id = 1,
Name = "Extended Item",
Priority = 121,
Valid = true,
Count = 10,
Childs = new ItemsCollection(new List<Item>() { new Item() { Id = 1 }, new IntermediateItem() { Priority = 10 }, new ExtendedItem() { Count = 10 } })
};
I was able to serialize that and deserialize with success !
byte[] bytes = MessagePackSerializer.Typeless.Serialize(instance);
await fileManager.WriteAsync(bytes);
ExtendedItem deserializedInstance = null;
deserializedInstance = MessagePackSerializer.Typeless.Deserialize(bytes) as ExtendedItem;
despite the serialization and deserialization worked on .NET this sample did not work when deserializing in nodejs with msgpackjs package.

How to use protobuf-net for xml-serialization?

Maybe i misunderstood something for serialization. i wanna serialize my .net object fastest way. i made some googling i found protobuf. Myfirstquestion is ProtoBuf.Net has avility for xml serailization.if it has, can i use it for xml serialization.
My model:
[XmlType]
public class CT {
[XmlElement(Order = 1)]
public int Foo { get; set; }
}
[XmlType]
public class TE {
[XmlElement(Order = 1)]
public int Bar { get; set; }
}
[XmlType]
public class TD {
[XmlElement(Order = 1)]
public List CTs { get; set; }
[XmlElement(Order = 2)]
public List TEs { get; set; }
[XmlElement(Order = 3)]
public string Code { get; set; }
[XmlElement(Order = 4)]
public string Message { get; set; }
[XmlElement(Order = 5)]
public DateTime StartDate { get; set; }
[XmlElement(Order = 6)]
public DateTime EndDate { get; set; }
}
my serializer :
CT ct = new CT() { Foo = 1 };
List<CT> list = new List<CT>();
list.Add(ct);
TE te = new TE() { Bar = 2 };
List<TE> list2 = new List<TE>();
list2.Add(te);
TD td = new TD() { Code = "Test",Message = "Yusuf",StartDate = DateTime.Now,EndDate = DateTime.Now,CTs = list,TEs = list2 };
List<TD> list3 = new List<TD>();
list3.Add(td);
Stopwatch stopwatch5 = new Stopwatch();
stopwatch5.Start();
string str = String.Empty;
using (MemoryStream stream = new MemoryStream())
{
byte[] data = Serialize(list3);
XmlDocument doc = new XmlDocument();
string xml = Encoding.UTF8.GetString(data); <--SHOULD CREATE XML
doc.LoadXml(xml);
// str = Convert.ToBase64String(stream.GetBuffer(),0,(int)stream.Length);
}
stopwatch5.Stop();
Console.WriteLine(((double)(stopwatch5.Elapsed.TotalMilliseconds * 1000000) / 1000000).ToString("0.00 ns"));
Console.Read();
}
public static byte[] Serialize(List<TD> tData) {
using(var ms = new MemoryStream()) {
ProtoBuf.Serializer.Serialize(ms,tData);
return ms.ToArray();
}
}
public static List<TD> Deserialize(byte[] tData) {
using(var ms = new MemoryStream(tData)) {
return ProtoBuf.Serializer.Deserialize<List<TD>>(ms);
}
}
it should create xml as a result of " string xml = Encoding.UTF8.GetString(data);". But doesn't. How can i produxe xml result?
Protocol buffers doesn't serialize objects to XML.
It produces binary data. And it has its own set of attributes.
Check this answer
Is Protobuf-net's serialization/deserialization faster than XML ? Yes, by far.
However XmlSerializer is fast enough for most of the tasks.
What you should remind when using it though, is:
XmlSerializer instance is generating code on the fly and compile this code into an assembly.
This generated assembly is then used to serialize and deserialize your objects really fast.
So you should cache instances of XmlSerializer (and avoid recreating them)
you could add a warm up by calling Serialize and Deserialize in order to initialize inner objects and jit them.
You could even go further by generating the auto-generated assembly by yourself, but then you should remember to regenerate each time you change the objects (It can be automated with a MsBuild Task).
You can also look further optimizations:
On Stack Overflow
With Sgen
You can only have one tag at the root level of your xml. So either TD cannot be a list, or you must have an outer tag around the List. This code works
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
TD td = new TD()
{
Code = "Test",
Message = "Yusuf",
StartDate = DateTime.Now,
EndDate = DateTime.Now,
CTs = new List<CT>() {
new CT() { Foo = 1},
new CT() { Foo = 2},
new CT() { Foo = 3},
},
TEs = new List<TE>() {
new TE() { Bar = 1},
new TE() { Bar = 2},
new TE() { Bar = 3},
}
};
using (MemoryStream stream = new MemoryStream())
{
byte[] data = Serialize(td);
XmlDocument doc = new XmlDocument();
string xml = Encoding.UTF8.GetString(data);
doc.LoadXml(xml);
// str = Convert.ToBase64String(stream.GetBuffer(),0,(int)stream.Length);
}
}
public static byte[] Serialize(TD tData)
{
using (var ms = new MemoryStream())
{
XmlSerializer serializer = new XmlSerializer(typeof(TD));
serializer.Serialize(ms, tData);
return ms.ToArray();
}
}
public static TD Deserialize(byte[] tData)
{
using (var ms = new MemoryStream(tData))
{
XmlSerializer xs = new XmlSerializer(typeof(TD));
return (TD)xs.Deserialize(ms);
}
}
}
[XmlRoot("CT")]
public class CT
{
[XmlElement(ElementName = "Foo", Order = 1)]
public int Foo { get; set; }
}
[XmlRoot("TE")]
public class TE
{
[XmlElement(ElementName = "Bar", Order = 1)]
public int Bar { get; set; }
}
[XmlRoot("TD")]
public class TD
{
[XmlElement(ElementName = "CTs", Order = 1)]
public List<CT> CTs { get; set; }
[XmlElement(ElementName = "TEs", Order = 2)]
public List<TE> TEs { get; set; }
[XmlElement(ElementName = "Code", Order = 3)]
public string Code { get; set; }
[XmlElement(ElementName = "Message", Order = 4)]
public string Message { get; set; }
[XmlElement(ElementName = "StartDate", Order = 5)]
public DateTime StartDate { get; set; }
[XmlElement(ElementName = "EndDate", Order = 6)]
public DateTime EndDate { get; set; }
}
}
​

Categories