I have a little problem with .Net Json serializing
I have class withlist of strings an i need to serialize it as attribute for example:
original:
class:
kid{
int age;
String name;
List[String] toys;
}
result:
{
"age":10,
"name": Jane,
"toys":["one", "two", "three"]
}
i need
{
"age":10,
"name": Jane,
"toy_1": "one",
"toy_2": "two",
"toy_3": "three"
}
it's because of api. Is there any way how to do it?
Here's a dynamic solution that does not assume the number of toys:
public class kid
{
public int age;
public String name;
public List<String> toys;
public string ApiCustomView
{
get
{
Dictionary<string, string> result = new Dictionary<string, string>();
result.Add("age", age.ToString());
result.Add("name", name);
for (int ii = 0; ii < toys.Count; ii++)
{
result.Add(string.Format("toy_{0}", ii), toys[ii]);
}
return result.ToJSON();
}
}
}
usage:
static void Main(string[] args)
{
var k = new kid { age = 23, name = "Paolo", toys = new List<string>() };
k.toys.Add("Pippo");
k.toys.Add("Pluto");
Console.WriteLine(k.ApiCustomView);
Console.ReadLine();
}
It uses the extension you can find here: How to create JSON string in C#
namespace ExtensionMethods
{
public static class JSONHelper
{
public static string ToJSON(this object obj)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(obj);
}
public static string ToJSON(this object obj, int recursionDepth)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RecursionLimit = recursionDepth;
return serializer.Serialize(obj);
}
}
}
As dcastro says, it's a weird API, and you should change it if you can to accept an array.
If you cannot you can try to create and anonymous type, so you will have something like that:
public object GetSerializationObjectForKid(Kid kid)
{
return new
{
age = kid.age,
name = kid.name,
toy_1 = toys.ElementAtOrDefault(0),
toy_2 = toys.ElementAtOrDefault(1),
toy_3 = toys.ElementAtOrDefault(2)
}
}
Than you can serialize this new anonymous object.
Here is an example of using an Anonymous Type to select members and give them names to match an api's requirements. It currently assumes that there will always be 3 "toys".
using System.Linq;
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Web.Script.Serialization;
namespace CommandLineProgram
{
public class DefaultProgram
{
public static void Main()
{
var kid1 = new kid()
{
age = 10,
name = "Jane",
toys = new List<String>
{
"one",
"two",
"three"
}
};
var asdf = new
{
age = kid1.age,
name = kid1.name,
toy_1 = kid1.toys[0],
toy_2 = kid1.toys[1],
toy_3 = kid1.toys[2]
};
JavaScriptSerializer ser = new JavaScriptSerializer();
String serialized = ser.Serialize(asdf);
Console.WriteLine(serialized);
}
}
public class kid
{
public int age;
public String name;
public List<String> toys;
}
}
Produces this output
{
"age" : 10,
"name" : "Jane",
"toy_1" : "one",
"toy_2" : "two",
"toy_3" : "three"
}
I ve found solution...it' s not clear, but it works
JObject data = JObject.Parse(JsonConvert.SerializeObject(exportAuc));
int i = 0;
foreach(String file in exportAuc.pdf_ostatni){
data.Add("pdf_ostatni_" + i.ToString(), file);
i++;
}
String output = data.ToString();
You can build a dynamic object adding the properties you need and then serialize it
dynamic jsonData = new System.Dynamic.ExpandoObject();
jsonData.age = kid.age;
jsonData.name = kid.name;
for (int i = 0; i < kid.toys.Count; i++)
{
((IDictionary<String, Object>)jsonData).Add(string.Format("toy_{0}", i), kid.toys[i]);
}
Related
Is it possible to make JavaScriptSerializer also populate properties without a setter? For example, a property like test.ID in the code below:
using System;
using System.Collections.Generic;
using System.Web.Script.Serialization;
namespace JavaScriptConverterTest
{
class Program
{
static void Main(string[] args)
{
List<test> list = new List<test>();
for (int i = 0; i < 2; i++)
{
list.Add(new test(Guid.NewGuid(), "Item #" + i));
}
JavaScriptSerializer serializer = new JavaScriptSerializer();
string jsonString = serializer.Serialize(list);
List<test> newList = serializer.Deserialize<List<test>>(jsonString);
Console.Read();
}
}
class test
{
private Guid id = Guid.Empty;
public Guid ID
{
get { return id; }
// Without a setter, JavaScriptSerializer doesn't populate this property.
// set { id = value; }
}
public string name = "";
public test()
{
}
public test(Guid id, string name)
{
this.id = id;
this.name = name;
}
}
}
You can use DataContractJsonSerializer which is built in .NET Framework and has its home at System.Runtime.Serialization.Json. You just need to decorate your field with DataMemberAttribute. Let's say you have this class:
class Foo
{
private string _boo;
public Foo(string boo) => _boo = boo;
public string Boo => _boo;
}
After decorating:
[DataContract]
class Foo
{
[DataMember] private string _boo;
public Foo(string boo) => _boo = boo;
public string Boo => _boo;
}
And testing:
private static void Main(string[] args)
{
var foo = new Foo("boo");
var serializer = new DataContractJsonSerializer(typeof(Foo));
string str;
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, foo);
str = Encoding.Default.GetString(stream.ToArray());
}
Console.WriteLine(str);
Foo loadedFoo;
using (var stream = new MemoryStream(Encoding.Default.GetBytes(str)))
{
loadedFoo = serializer.ReadObject(stream) as Foo;
}
Console.WriteLine(loadedFoo.Boo);
Console.ReadLine();
}
The loadedFoo that is constructed from the json string gets "boo" as value for _boo field.
Below is my class and code:
public class Properties
{
public string Prop1;
public string[] Prop2;
}
public IEnumerable<Properties> GetProperties()
{
string [] props = new[] { "abc", "xyz", };
for (int i = 0; i < 4; i++)
{
yield return new Properties { Prop1 = "Prop" + i, Prop2 = props};
}
}
var values = GetProperties().Select(x => new {
prop = x.Prop2.ToString()
}).ToList();
Now I want my values variable to contains list of props but here i am getting props as array but I want it as single string.
Expected Output:
Values[0] : Name : abc
Values[1] : Name : xyz
How can I do this with linq?
Try this:
public class Properties
{
public string Prop1;
public string[] Prop2;
}
public List<Properties> GetProperties()
{
var list = new List<Properties>();
var props = new[] { "abc", "xyz", }.toList();
props.ForEach(p=>{
var np = new Properties { Prop1 = "Prop" + i, Prop2 = props};
list.Add(np);
});
return list;
}
var values = GetProperties().Select(x => new {
prop = x.Prop2.ToString()
}).ToList();
If you want to have this output you wrote for all 4 values, you should use SelectMany:
var values = GetProperties().SelectMany(x => x.Prop2).ToList();
if you want to have exact output you wrote, you should take only the first value of GetProperties() and you don't need any Select:
var values = GetProperties().First().Prop2;
i have two list of elements with same length eg.
List 1: profile1, profile2,profile3
List 2: 1,0,1
these lists are the public property in class objects.
i.e:
class Serviceinfo
{
[xmlArray("Profiles")]
[xmlArrayItem("Profile")]
public list<string> Profiles;
public list<int> state;
}
here i need to map each profile with its state. eg.
<serviceinfo>
<profiles>
<profile>profile1</profile>
<state>1</state>
</profiles>
<profiles>
<profile>profile2</profile>
<state>0</state>
</profiles>
<profiles>
<profile>profile3</profile>
<state>1</state>
</profiles>
</serviceinfo>
how do i change my class object, to return the above xml result. is it possible to get the above output in xml serialization method.
I'm not sure if it can be done using XmlSerializer because your desired XML structure is quite strange when compared with your class.
But it definitely can be done using LINQ to XML:
var serviceInfo = new Serviceinfo { Profiles = new List<string> { "one", "two", "three" }, state = new List<int> { 1, 2, 4 } };
var xml = new XDocument(
new XElement("serviceinfo",
serviceInfo.Profiles
.Zip(serviceInfo.state, (p, s) => new { p, s })
.Select(x =>
new XElement("profiles",
new XElement("profile", x.p),
new XElement("state", x.s.ToString())))));
If you really want to XML Serialization you should change your class structure to
[XmlRoot(ElementName = "serviceInfo")]
public class Serviceinfo
{
[XmlElement("profiles")]
public List<Profile> Profiles { get; set; }
}
public class Profile
{
[XmlElement(ElementName = "profile")]
public string Name { get; set; }
[XmlElement(ElementName = "state")]
public int State { get; set; }
}
and use XmlSerializer:
var serviceInfo = new Serviceinfo
{
Profiles = new List<Profile>() {
new Profile { Name = "one", State = 1 },
new Profile { Name = "two", State = 2 }
}
};
var writer = new StringWriter();
var serializer = new XmlSerializer(typeof(Serviceinfo));
serializer.Serialize(writer, serviceInfo);
var xml = writer.ToString();
#Gomathipriya : As per what I understand from your problem, the best solution would be create one single collection with both the values as properties as mentioned in the below example and then convert the entire collection to XML.
convert the Collection to XML : http://www.dotnetcurry.com/showarticle.aspx?ID=428
Sample C# Code:
class Program
{
public static void Main(string[] args)
{
List<string> Profiles = new List<string>();
List<int> state = new List<int>();
// Just filling the entities as per your needs
for (int i = 0; i < 5; i++)
{
Profiles.Add("P-" + i.ToString());
state.Add(i);
}
listOfProfileState ProfileStateColl = new listOfProfileState();
for (int i = 0; i < Profiles.Count; i++)
{
ProfileStateColl.Add(new ProfileState() { Profile = Profiles[i], State = state[i] });
}
}
}
public class ProfileState
{
public string Profile { get; set; }
public int State { get; set; }
}
public class listOfProfileState : List<ProfileState>
{
}
as per the above mentioned example if you convert the collection 'ProfileStateColl' to XML you will have your solution that you need. :)
Let us suppose we have a document to store our client which has fixed and extra fields.
So here goes our sample class for the client:
public class Client
{
public string Name{ get; set; }
public string Address{ get; set; }
public List<ExtraField> ExtraFields{ get; set; } //these fields are extra ones
}
In extra field class we have something like this:
public class ExtraField
{
public string Key{ get; set; }
public string Type { get; set; }
public string Value { get; set; }
}
If I use standard driver's behaviour for serialization I would get smth like this:
{{Name:VName, Address:VAddress, ExtraFields:[{Key:VKey,Type:VType,
Value:VValue},...]}, document2,...,documentn}
While I would like to have something like this:
{{Name:VName, Address:VAddress, VKey:VValue,...}, document2,...,documentn}
This would improve the search performance and is generally the point of document orientation.
How can I customize the serialization to such a way?
Here is the way I solved it (it works fine) and solved the issue.
using System;
using System.Collections.Generic;
using System.Linq; using System.Text;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;
namespace TestDataGeneration {
public class FieldsWrapper : IBsonSerializable
{
public List<DataFieldValue> DataFieldValues { get; set; }
public object Deserialize(MongoDB.Bson.IO.BsonReader bsonReader, Type nominalType, IBsonSerializationOptions options)
{
if (nominalType != typeof(FieldsWrapper)) throw new ArgumentException("Cannot deserialize anything but self");
var doc = BsonDocument.ReadFrom(bsonReader);
var list = new List<DataFieldValue>();
foreach (var name in doc.Names)
{
var val = doc[name];
if (val.IsString)
list.Add(new DataFieldValue {LocalIdentifier = name, Values = new List<string> {val.AsString}});
else if (val.IsBsonArray)
{
DataFieldValue df = new DataFieldValue {LocalIdentifier = name};
foreach (var elem in val.AsBsonArray)
{
df.Values.Add(elem.AsString);
}
list.Add(df);
}
}
return new FieldsWrapper {DataFieldValues = list};
}
public void Serialize(MongoDB.Bson.IO.BsonWriter bsonWriter, Type nominalType, IBsonSerializationOptions options)
{
if (nominalType != typeof (FieldsWrapper))
throw new ArgumentException("Cannot serialize anything but self");
bsonWriter.WriteStartDocument();
foreach (var dataFieldValue in DataFieldValues)
{
bsonWriter.WriteName(dataFieldValue.LocalIdentifier);
if (dataFieldValue.Values.Count != 1)
{
var list = new string[dataFieldValue.Values.Count];
for (int i = 0; i < dataFieldValue.Values.Count; i++)
list[i] = dataFieldValue.Values[i];
BsonSerializer.Serialize(bsonWriter, list);
}
else
{
BsonSerializer.Serialize(bsonWriter, dataFieldValue.Values[0]);
}
}
bsonWriter.WriteEndDocument();
}
} }
Essentially you just need to implement two methods yourself. First one to serialize an object as you want and second to deserialize an object from db to your Client class back:
1 Seialize client class:
public static BsonValue ToBson(Client client)
{
if (client == null)
return null;
var doc = new BsonDocument();
doc["Name"] = client.Name;
doc["Address"] = client.Address;
foreach (var f in client.ExtraFields)
{
var fieldValue = new BsonDocument();
fieldValue["Type"] = f.Type;
fieldValue["Value"] = f.Value;
doc[f.Key] = fieldValue;
}
return doc;
}
2 Deserialize client object:
public static Client FromBson(BsonValue bson)
{
if (bson == null || !bson.IsBsonDocument)
return null;
var doc = bson.AsBsonDocument;
var client = new Client
{
ExtraFields = new List<ExtraField>(),
Address = doc["Address"].AsString,
Name = doc["Name"].AsString
};
foreach (var name in doc.Names)
{
var val = doc[name];
if (val is BsonDocument)
{
var fieldDoc = val as BsonDocument;
var field = new ExtraField
{
Key = name,
Value = fieldDoc["Value"].AsString,
Type = fieldDoc["Type"].AsString
};
client.ExtraFields.Add(field);
}
}
return client;
}
3 Complete test example:
I've added above two method to your client class.
var server = MongoServer.Create("mongodb://localhost:27020");
var database = server.GetDatabase("SO");
var clients = database.GetCollection<Type>("clients");
var client = new Client() {Id = ObjectId.GenerateNewId().ToString()};
client.Name = "Andrew";
client.Address = "Address";
client.ExtraFields = new List<ExtraField>();
client.ExtraFields.Add(new ExtraField()
{
Key = "key1",
Type = "type1",
Value = "value1"
});
client.ExtraFields.Add(new ExtraField()
{
Key = "key2",
Type = "type2",
Value = "value2"
});
//When inseting/saving use ToBson to serialize client
clients.Insert(Client.ToBson(client));
//When reading back from the database use FromBson method:
var fromDb = Client.FromBson(clients.FindOneAs<BsonDocument>());
4 Data structure in a database:
{
"_id" : ObjectId("4e3a66679c66673e9c1da660"),
"Name" : "Andrew",
"Address" : "Address",
"key1" : {
"Type" : "type1",
"Value" : "value1"
},
"key2" : {
"Type" : "type2",
"Value" : "value2"
}
}
BTW: Take a look into serialization tutorial as well.
In the example code below, I get this error:
Element
TestSerializeDictionary123.Customer.CustomProperties
vom Typ
System.Collections.Generic.Dictionary`2[[System.String,
mscorlib, Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089],[System.Object,
mscorlib, Version=2.0.0.0,
Culture=neutral,
PublicKeyToken=b77a5c561934e089]] can
not be serialized because it
implements IDictionary.
When I take out the Dictionary property, it works fine.
How can I serialize this Customer object with the dictionary property? Or what replacement type for Dictionary can I use that would be serializable?
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Text;
namespace TestSerializeDictionary123
{
public class Program
{
static void Main(string[] args)
{
List<Customer> customers = Customer.GetCustomers();
Console.WriteLine("--- Serializing ------------------");
foreach (var customer in customers)
{
Console.WriteLine("Serializing " + customer.GetFullName() + "...");
string xml = XmlHelpers.SerializeObject<Customer>(customer);
Console.WriteLine(xml);
Console.WriteLine("Deserializing ...");
Customer customer2 = XmlHelpers.DeserializeObject<Customer>(xml);
Console.WriteLine(customer2.GetFullName());
Console.WriteLine("---");
}
Console.ReadLine();
}
}
public static class StringHelpers
{
public static String UTF8ByteArrayToString(Byte[] characters)
{
UTF8Encoding encoding = new UTF8Encoding();
String constructedString = encoding.GetString(characters);
return (constructedString);
}
public static Byte[] StringToUTF8ByteArray(String pXmlString)
{
UTF8Encoding encoding = new UTF8Encoding();
Byte[] byteArray = encoding.GetBytes(pXmlString);
return byteArray;
}
}
public static class XmlHelpers
{
public static string SerializeObject<T>(object o)
{
MemoryStream ms = new MemoryStream();
XmlSerializer xs = new XmlSerializer(typeof(T));
XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
xs.Serialize(xtw, o);
ms = (MemoryStream)xtw.BaseStream;
return StringHelpers.UTF8ByteArrayToString(ms.ToArray());
}
public static T DeserializeObject<T>(string xml)
{
XmlSerializer xs = new XmlSerializer(typeof(T));
MemoryStream ms = new MemoryStream(StringHelpers.StringToUTF8ByteArray(xml));
XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
return (T)xs.Deserialize(ms);
}
}
public class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Street { get; set; }
public string Location { get; set; }
public string ZipCode { get; set; }
public Dictionary<string,object> CustomProperties { get; set; }
private int internalValue = 23;
public static List<Customer> GetCustomers()
{
List<Customer> customers = new List<Customer>();
customers.Add(new Customer { Id = 1, FirstName = "Jim", LastName = "Jones", ZipCode = "23434" });
customers.Add(new Customer { Id = 2, FirstName = "Joe", LastName = "Adams", ZipCode = "12312" });
customers.Add(new Customer { Id = 3, FirstName = "Jack", LastName = "Johnson", ZipCode = "23111" });
customers.Add(new Customer { Id = 4, FirstName = "Angie", LastName = "Reckar", ZipCode = "54343" });
customers.Add(new Customer { Id = 5, FirstName = "Henry", LastName = "Anderson", ZipCode = "16623" });
return customers;
}
public string GetFullName()
{
return FirstName + " " + LastName + "(" + internalValue + ")";
}
}
}
In our application we ended up using:
DataContractSerializer xs = new DataContractSerializer(typeof (T));
instead of:
XmlSerializer xs = new XmlSerializer(typeof (T));
which solved the problem as DatacontractSerializer supports Dictionary.
Another solution is ths XML Serializable Generic Dictionary workaround also works in the above example, and there is a long discussion at that link from people using it, might be useful for people working with this issue.
Here's a generic dictionary class that knows how to serialize itself:
public class XmlDictionary<T, V> : Dictionary<T, V>, IXmlSerializable {
[XmlType("Entry")]
public struct Entry {
public Entry(T key, V value) : this() { Key = key; Value = value; }
[XmlElement("Key")]
public T Key { get; set; }
[XmlElement("Value")]
public V Value { get; set; }
}
System.Xml.Schema.XmlSchema IXmlSerializable.GetSchema() {
return null;
}
void IXmlSerializable.ReadXml(System.Xml.XmlReader reader) {
this.Clear();
var serializer = new XmlSerializer(typeof(List<Entry>));
reader.Read(); // Why is this necessary?
var list = (List<Entry>)serializer.Deserialize(reader);
foreach (var entry in list) this.Add(entry.Key, entry.Value);
reader.ReadEndElement();
}
void IXmlSerializable.WriteXml(System.Xml.XmlWriter writer) {
var list = new List<Entry>(this.Count);
foreach (var entry in this) list.Add(new Entry(entry.Key, entry.Value));
XmlSerializer serializer = new XmlSerializer(list.GetType());
serializer.Serialize(writer, list);
}
}
You can't (short of doing it all yourself, which is horrible); the xml serializer isn't going to have a clue what to do with object, as it doesn't include type metadata in the wire format. One (hacky) option would be to stream these all as strings for the purposes of serialization, but then you have a lot of extra parsing (etc) code to write.
You can use Binary serialization instead. (Just make sure all your classes are marked as [Serializable]. Of course, it won't be in XML format, but you didn't list that as a requirement :)
I've just found this blog post by Rakesh Rajan which describes one possible solution:
Override XmlSerialization by making the type implement the System.Xml.Serialization.IXmlSerializable class. Define how you want the object to be serialized in XML in the WriteXml method, and define how you could recreate the object from an xml string in the ReadXml method.
But this wouldn't work as your Dictionary contains an object rather than a specific type.
What about to mark Customer class as DataContract and its properties as DataMembers. DataContract serializer will do the serialization for you.
Try Serializating through BinaryFormatter
private void Deserialize()
{
try
{
var f_fileStream = File.OpenRead(#"dictionarySerialized.xml");
var f_binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
myDictionary = (Dictionary<string, myClass>)f_binaryFormatter.Deserialize(f_fileStream);
f_fileStream.Close();
}
catch (Exception ex)
{
;
}
}
private void Serialize()
{
try
{
var f_fileStream = new FileStream(#"dictionarySerialized.xml", FileMode.Create, FileAccess.Write);
var f_binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
f_binaryFormatter.Serialize(f_fileStream, myDictionary);
f_fileStream.Close();
}
catch (Exception ex)
{
;
}
}