This question already has answers here:
How to use class fields with System.Text.Json.JsonSerializer?
(3 answers)
Closed 1 year ago.
I can't serialize BaseResponse<NoContent> object. But Device object serialized successfully. I didnt find reason
var data = new BaseResponse<NoContent>();
var json1 = JsonSerializer.Serialize(data);
var data2 = new Device();
var json2 = JsonSerializer.Serialize(data2);
BaseResponse Content :
public class BaseResponse<T> where T : class, new()
{
public BaseResponse()
{
Data = new T();
}
public T Data;
public string Status = "Success";
public List<string> Errors;
public BaseResponse<T> AddError(string message)
{
Errors ??= new List<string>();
Status = "Error";
Errors.Add(message);
return this;
}
}
Edit: Newtonsoft.Json can serialize both of them. I decided use Newtonsoft.
you have to add getters and setters
public class BaseResponse<T> where T : class, new()
{
public BaseResponse()
{
Data = new T();
}
public T Data {get; set;}
public string Status {get; set;} = "Success";
public List<string> Errors {get; set;}
public BaseResponse<T> AddError(string message)
{
Errors ??= new List<string>();
Status = "Error";
Errors.Add(message);
return this;
}
}
test
var data = new BaseResponse<NoContent>();
data.AddError("error message");
var json1 = System.Text.Json.JsonSerializer.Serialize(data);
output
{
"Data": {
"Content": "No Content"
},
"Status": "Error",
"Errors": [
"error message"
]
}
NoContent class
public class NoContent
{
public string Content {get; set;} ="No Content";
}
What's missing is the option to include fields, by default System.Text.Json does not serialize fields, only properties.
You can change this behaviour by supplying JsonSerializerOptions, e.g:
var json1 = JsonSerializer.Serialize(data, new JsonSerializerOptions() { IncludeFields = true });
Related
Imagine I have a class structure like this
class Aggregate
{
string Id {get;set;}
Parameters Parameters {get;set;}
}
class Parameters
{
List<string> Values {get;set;}
// logic based on Values
}
Now I want mongo to store it like this
{
"_id": "...",
"parameters": ["param A", "param B"]
}
How do I configure it using BsonClassMap.RegisterClassMap?
I'm ignoring the fact that the members of your class are private at the moment, as that would mean you couldn't read anything from the class. So let's just make them public
class Aggregate
{
public string Id { get; set; }
public Parameters Parameters { get; set; }
}
class Parameters
{
public List<string> Values { get; set; }
}
So now we'll need a custom serializer to deal with flattering the object and then also reading back the flattened document.
Below is just a noddy example that delegate serializing Parameters to the BsonArraySerializer.
public class ParametersSerializer : IBsonSerializer
{
private readonly BsonArraySerializer _bsonArraySerializer;
public ParametersSerializer()
{
_bsonArraySerializer = new BsonArraySerializer();
}
public object Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
{
var bsonArray = _bsonArraySerializer.Deserialize(context, args);
var netList = BsonTypeMapper.MapToDotNetValue(bsonArray, new BsonTypeMapperOptions()
{
MapBsonArrayTo = typeof(List<string>)
}) as List<string>;
return new Parameters
{
Values = netList
};
}
public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
{
var typed = (Parameters) value;
var bsonArray = new BsonArray(typed.Values);
_bsonArraySerializer.Serialize(context, args, bsonArray);
}
public Type ValueType { get; } = typeof(Parameters);
}
Now we've got this we can just add an attribute to our class to tell Mongo driver to use it.
class Aggregate
{
public string Id { get; set; }
[BsonSerializer(typeof(ParametersSerializer))]
public Parameters Parameters { get; set; }
}
Now when we write and read documents to mongo:
var pack = new ConventionPack();
pack.Add(new CamelCaseElementNameConvention());
ConventionRegistry.Register(
"My Custom Conventions",
pack,
t => t == typeof(Aggregate) || t == typeof(Parameters));
var client = new MongoClient();
var database = client.GetDatabase("test");
var collection = database.GetCollection<Aggregate>("test");
await database.DropCollectionAsync(collection.CollectionNamespace.CollectionName);
await collection.InsertOneAsync(new Aggregate{Id = "...", Parameters = new Parameters{Values = {"1", "2"}}});
var all = await (await collection.FindAsync(Builders<Aggregate>.Filter.Empty)).ToListAsync();
we'll get the following save in MongoDB collection:
> db.test.find()
{ "_id" : "...", "parameters" : [ "1", "2" ] }
Also notice we're using a custom convention of camel case to deal with creating camel case properties too.
This question already has answers here:
How to ignore JsonProperty(PropertyName = "someName") when serializing json?
(2 answers)
Closed 2 years ago.
I have a class in my project which needs to be serialized for two different use cases.
As I can't add two diffrent attributes to on property I would like to serialize the objects of the class
one time with the [JsonProperty("attributname")] decleration and one time with the property name it self.
For ex:
public class Contact
{
[JsonProperty("name")]
public string Lastname { get; set; }
}
public class Program
{
public void SerializeByJsonPropertyName()
{
var contact = new Contact()
{
Lastname = "Harber"
}
var requestJson = JsonConvert.SerializeObject(contact);
// Serialized Object requestJson:
// {
// "name" = "Harber"
// }
}
public void SerializeByPropertyName()
{
var contact = new Contact()
{
Lastname = "Harber"
}
var requestJson = JsonConvert.SerializeObject(contact /*, ? Setting ?*/);
// Serialized Object requestJson:
// {
// "Lastname" = "Harber"
// }
}
}
The first szenario works totaly fine, but for the second szenario I couldĀ“t find any solution. Except creating two classes or duplicate the properties in my class.. IS there any setting in Newtonsofts JsonConverter for doing this?
Thanks for your help!
You can create different naming strategies, then create different settings, each setting has a Contract resolver, each contract resolver has a naming strategy, then you supply for each settings the naming strategy you want to use,
something like this
public static class JsonSerializingSettings {
public static JsonSerializerSettings JsonUnModified{ get; set; } = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver() {
NamingStrategy = new UnmodifiedNamingStrategy()
}
};
public static JsonSerializerSettings JsonDefault { get; set; } = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver() {
NamingStrategy = new DefaultNamingStrategy()
}
};
}
public class UnmodifiedNamingStrategy : NamingStrategy {
protected override string ResolvePropertyName(string name) {
return name;
}
}
and when you want to use it
var requestJson = JsonConvert.SerializeObject(contact,JsonSerializingSettings.JsonDefault);
// Serialized Object requestJson:
// {
// "name" = "Harber"
// }
var requestJson = JsonConvert.SerializeObject(contact,JsonSerializingSettings.JsonUnModified);
// Serialized Object requestJson:
// {
// "Lastname" = "Harber"
// }
https://dotnetfiddle.net/R96sPn
I am trying to create AddJsonObject such that the name of External.AddParameter obeys whatever the ContractRevolver is set for External.Serialize
In the example below it is camel casing, but as you can see the output is not camel cased. Changing the ContractResolver should effectively determine the formatting of the name parameter. No additional code can be added to External class
This is a class that I cannot modify:
public static class External
{
public static string Serialize(object obj)
{
JsonSerializer ser = new JsonSerializer{
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore
};
using (StringWriter stringWriter = new StringWriter())
{
using (JsonTextWriter jsonTextWriter = new JsonTextWriter((TextWriter)stringWriter))
{
jsonTextWriter.Formatting = Formatting.Indented;
jsonTextWriter.QuoteChar = '"';
ser.Serialize((JsonWriter)jsonTextWriter, obj);
return stringWriter.ToString();
}
}
}
public static void AddParameter(string name, string str)
{
Console.WriteLine(name + " : " + str);
}
}
Just example class:
public class Product { public Product ChildProduct { get; set; } public string Name { get; set; } public DateTime Expiry { get; set; } public string[] Sizes { get; set; } }
Main:
public class Program
{
public void AddJsonObject(object obj)
{
foreach (var property in obj.GetType().GetProperties())
{
var propValue = property.GetValue(obj, null);
External.AddParameter(property.Name, External.Serialize(propValue));
}
}
public void Main()
{
Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Sizes = new string[]{"small", "big"};
product.ChildProduct = new Product();
AddJsonObject(product);
}
}
Output:
ChildProduct : {
"expiry": "0001-01-01T00:00:00"
}
Name : "Apple"
Expiry : "2008-12-28T00:00:00"
Sizes : [
"small",
"big"
]
Desired Output:
childProduct : {
"expiry": "0001-01-01T00:00:00"
}
name : "Apple"
expiry : "2008-12-28T00:00:00"
sizes : [
"small",
"big"
]
This demo showcases Serialize using JSON.net with CamelCase, but AddJsonObject should work independent of what json serializer they use or what formatting. This example just showcases a non-trivial example.
My initial attempt consisted of wrapping the object into a parent object. External.Serialize() the wrapper object then somehow feed the results into AddParameter such that the name is the output of the serialization -- Couldn't get this to work right.
Change Line where you initialize ContractResolver (ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()) to
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new CamelCaseNamingStrategy()
};
Ok I have a solution that works, but Ill hold off anymore clever answers come up
public void AddJsonObject(object obj)
{
var jsonObj = JObject.Parse(External.Serialize(obj));
foreach (var property in jsonObj.Properties())
{
External.AddParameter(property.Name, External.Serialize( property.Value));
}
}
I am trying to create a JSON string which contains one container and one array.
I can do this by using a stringbuilder but I am trying to find a better way to get the JSON string; I want:
{ "message":{ "text":"test sms"},"endpoints":["+9101234"]}
I tried this:
string json = new JavaScriptSerializer().Serialize(new
{
text = "test sms",
endpoints = "[dsdsd]"
});
And the output is:
{"text":"test sms","endpoints":"[dsdsd]"}
Any help or suggestions how to get the required format?
In the most recent version of .NET we have the System.Text.Json namespace, making third party libraries unecessary to deal with json.
using System.Text.Json;
And use the JsonSerializer class to serialize:
var data = GetData();
var json = JsonSerializer.Serialize(data);
and deserialize:
public class Person
{
public string Name { get; set; }
}
...
var person = JsonSerializer.Deserialize<Person>("{\"Name\": \"John\"}");
Other versions of .NET platform there are different ways like the JavaScriptSerializer where the simplest way to do this is using anonymous types, for sample:
string json = new JavaScriptSerializer().Serialize(new
{
message = new { text = "test sms" },
endpoints = new [] {"dsdsd", "abc", "123"}
});
Alternatively, you can define a class to hold these values and serialize an object of this class into a json string. For sample, define the classes:
public class SmsDto
{
public MessageDto message { get; set; }
public List<string> endpoints { get; set; }
}
public class MessageDto
{
public string text { get; set; }
}
And use it:
var sms = new SmsDto()
{
message = new MessageDto() { text = "test sms" } ,
endpoints = new List<string>() { "dsdsd", "abc", "123" }
}
string json = new JavaScriptSerializer().Serialize(sms);
I have to read a JSON stream (which I have no control over), which is in the form:
{"files":
{
"/some_file_path.ext": {"size":"1000", "data":"xxx", "data2":"yyy"},
"/other_file_path.ext": {"size":"2000", "data":"xxx", "data2":"yyy"},
"/another_file_path.ext": {"size":"3000", "data":"xxx", "data2":"yyy"},
}
}
So, I have an object named files, which has a number of properties, which have 1) different names every time, 2) different number of them every time, and 3) names with characters which can't be used in C# properties.
How do I deserialize this?
I'm putting this into a Portable Library, so I can't use the JavaScriptSerializer, in System.Web.Script.Serialization, and I'm not sure about JSON.NET. I was hoping to use the standard DataContractJsonSerializer.
UPDATE: I've changed the sample data to be closer to the actual data, and corrected the JSON syntax in the area the wasn't important. (Still simplified quite a bit, but the other parts are fairly standard)
You can model your "files" object as a Dictionary keyed by the JSON property name:
public class RootObject
{
public Dictionary<string, PathData> files { get; set; }
}
public class PathData
{
public int size { get; set; }
public string data { get; set; }
public string data2 { get; set; }
}
Then, only if you are using .Net 4.5 or later, you can deserialize using DataContractJsonSerializer, but you must first set DataContractJsonSerializerSettings.UseSimpleDictionaryFormat = true:
var settings = new DataContractJsonSerializerSettings { UseSimpleDictionaryFormat = true };
var root = DataContractJsonSerializerHelper.GetObject<RootObject>(jsonString, settings);
With the helper method:
public static class DataContractJsonSerializerHelper
{
public static T GetObject<T>(string json, DataContractJsonSerializer serializer = null)
{
using (var stream = GenerateStreamFromString(json))
{
var obj = (serializer ?? new DataContractJsonSerializer(typeof(T))).ReadObject(stream);
return (T)obj;
}
}
public static T GetObject<T>(string json, DataContractJsonSerializerSettings settings)
{
return GetObject<T>(json, new DataContractJsonSerializer(typeof(T), settings));
}
private static MemoryStream GenerateStreamFromString(string value)
{
return new MemoryStream(Encoding.Unicode.GetBytes(value ?? ""));
}
}
Alternatively, you can install Json.NET and do:
var root = JsonConvert.DeserializeObject<RootObject>(jsonString);
Json.NET automatically serializes dictionaries to JSON objects without needing to change settings.
We need to first convert this Invalid JSON to a Valid JSON. So a Valid JSON should look like this
{
"files":
{
"FilePath" : "C:\\some\\file\\path",
"FileData" : {
"size": 1000,
"data": "xxx",
"data2": "yyy"
},
"FilePath" :"C:\\other\\file\\path",
"FileData" : {
"size": 2000,
"data": "xxx",
"data2": "yyy"
},
"FilePath" :"C:\\another\\file\\path",
"FileData" : {
"size": 3000,
"data": "xxx",
"data2": "yyy"
}
}
}
To make it a valid JSON we might use some string functions to make it looks like above. Such as
MyJSON = MyJSON.Replace("\\", "\\\\");
MyJSON = MyJSON.Replace("files", "\"files\"");
MyJSON = MyJSON.Replace("data:", "\"data:\"");
MyJSON = MyJSON.Replace("data2", "\"data2\"");
MyJSON = MyJSON.Replace(": {size", ",\"FileData\" : {\"size\"");
MyJSON = MyJSON.Replace("C:", "\"FilePath\" :\"C:");
Than we can create a class like below to read the
public class FileData
{
public int size { get; set; }
public string data { get; set; }
public string data2 { get; set; }
}
public class Files
{
public string FilePath { get; set; }
public FileData FileData { get; set; }
}
public class RootObject
{
public Files files { get; set; }
}
Assuming you have a valid JSON you could use JavaScriptSerializer to return a list of objects
string json = "{}"
var serializer = new JavaScriptSerializer();
var deserializedValues = (Dictionary<string, object>)serializer.Deserialize(json, typeof(object));
Alternatively you could specify Dictionary<string, List<string>> as the type argument
strign json = "{}";
JavaScriptSerializer serializer = new JavaScriptSerializer();
var deserializedValues = serializer.Deserialize<Dictionary<string, List<string>>>(json);
foreach (KeyValuePair<string, List<string>> kvp in deserializedValues)
{
Console.WriteLine(kvp.Key + ": " + string.Join(",", kvp.Value));
}