from a C# aspnet core controller I produce the following output :
[
{
"info": {
"type": 6,
"message": "a message"
}
},
{
"detail": {
"type": 8,
"something": "a different thing"
}
}
]
I'm doing this at the moment with:
Dictionary<string, object> Result = new Dictionary<string, object>();
Result.Add("info", new Info() { Type = 6, message = "a message"});
Result.Add("detail", new Detail() { Type = 8, something = "a different thing" });
JsonConvert.SerializeObject(new object[] { _Errors });
But this won't work when it comes to an output like this:
[
{
"info": {
"type": 6,
"message": "a message"
}
},
{
"info": {
"type": 6,
"message": "another message"
}
}
]
Since this would need duplicate keys in the dictionary I have no idea how which structure will produce this output.
KeyValuePair wont work since this results in "key": "info"... and so on. Also a class with several members using the same JsonProperty attribute wont work since the number of elements is dynamic.
I assume what you want is this output:
[
{
"Info": {
"Type": 5,
"Message": "A message 1"
}
},
{
"Info": {
"Type": 6,
"Message": "A message 3"
}
},
{
"Info": {
"Type": 7,
"Message": "A message 2"
}
},
{
"Error": {
"Type": 8,
"Something": "A different thing"
}
}
]
Implement your own JsonConvert, here is an example that provides the above serialization
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
namespace JsonSerialization
{
public class ResultsEntrySerializer : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var entry = value as IResultsEntry;
if (entry == null) throw new ArgumentException("Cannot convert parameter", nameof(value));
writer.WriteStartObject();
writer.WritePropertyName(entry.Name);
serializer.Serialize(writer, entry.Entry);
writer.WriteEndObject();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
//TODO: I leave this up to the reader
throw new NotImplementedException();
}
public override bool CanConvert(Type objectType)
{
return objectType.GetInterfaces().Contains(typeof(IResultsEntry));
}
}
[JsonConverter(typeof(ResultsEntrySerializer))]
interface IResultsEntry
{
string Name { get; }
object Entry { get; set; }
}
class Info
{
public int Type { get; set; }
public string Message { get; set; }
}
class InfoEntry : IResultsEntry
{
string IResultsEntry.Name => "Info";
object IResultsEntry.Entry
{
get => Entry;
set => Entry = (Info)value;
}
public Info Entry { get; set; }
}
class Detail
{
public int Type { get; set; }
public string Something { get; set; }
}
class DetailEntry : IResultsEntry
{
string IResultsEntry.Name => "Error";
object IResultsEntry.Entry
{
get => Entry;
set => Entry = (Detail)value;
}
public Detail Entry { get; set; }
}
class Program
{
static void Main(string[] args)
{
var list = new List<IResultsEntry>
{
new InfoEntry
{
Entry = new Info { Type = 5, Message = "A message 1" }
},
new InfoEntry
{
Entry = new Info { Type = 6, Message = "A message 3" }
},
new InfoEntry
{
Entry = new Info { Type = 7, Message = "A message 2" }
},
new DetailEntry
{
Entry = new Detail { Type = 8, Something = "A different thing" }
}
};
Console.WriteLine(JsonConvert.SerializeObject(list));
Console.ReadLine();
}
}
}
Also, if you want them lowercase that's trivial too see this Stackoverflow post: Json keys lowercase
sorry for the confusion. After checking the things a bit I found (not really) a solution. I came up with a dictionary which has a special key. Json.Net just uses ToString() for the dictionary keys so something like this seemed to do what I wanted.
public class DupKey {
public string Name { get; set; }
public int Index { get; set; }
public override string ToString() {
return Name;
}
public override bool Equals(object obj) {
if(!(obj is DupKey)) return false;
return Index == ((DupKey)obj).Index;
}
public override int GetHashCode() {
return Index.GetHashCode();
}
}
But finally I found that this produces a wrong result. Last not least I found a solution (without the need for an own serializer) which gives the correct result.
Since this looks some kind of universal for me I post it here.
public class DynamicJsonEntry : DynamicObject {
private string _JsonName;
public object Element { get; set; }
public DynamicJsonEntry(string pJsonName, object pElement) : this(pJsonName) {
Element = pElement;
}
public DynamicJsonEntry(string pJsonName) {
if(string.IsNullOrWhiteSpace(pJsonName)) {
throw new ArgumentNullException(nameof(pJsonName));
}
_JsonName = pJsonName;
}
public override IEnumerable<string> GetDynamicMemberNames() {
yield return _JsonName;
foreach(var prop in GetType().GetProperties().Where(a => a.CanRead && a.GetIndexParameters().Length == 0 && a.Name != nameof(Element))) {
yield return prop.Name;
}
}
public override bool TryGetMember(GetMemberBinder pBinder, out object pResult) {
if(pBinder.Name == _JsonName) {
pResult = Element;
return true;
}
return base.TryGetMember(pBinder, out pResult);
}
}
Now I can add any entry with the name I want simply like this:
List<DynamicJsonEntry> lRet = new List<DynamicJsonEntry>();
lRet.Add(new DynamicJsonEntry("info", new Info() { Type = 6, message = "a message" }));
lRet.Add(new DynamicJsonEntry("detail", new Detail() { Type = 8, something = "a different thing" }));
lRet.Add(new DynamicJsonEntry("info", new Info() { Type = 6, message = "a second message" }));
Thank you Joachim for your help.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.