serializar - serialize object newtonsoft c#
Cambie el nombre de ''Clave'' y ''Valor'' cuando usa JSON.NET para serializar Diccionario complejo (2)
Me encuentro con un problema extraño con la serialización de datos con json.net. Principalmente, estoy tratando de cambiar el nombre de los nombres ''Clave'' y ''Valor'' en el json saliente para que sea algo más descriptivo. Específicamente, quiero que la ''Clave'' relacionada con IRequest se llame ''Solicitud'' y el ''Valor'' de IQuoteTimeSeries sea ''Serie de Datos''
Tenga en cuenta que esto no se deserializará. Solo se usa en el análisis de datos en la página web.
El objeto del repositorio de datos que estoy serializando es un objeto Dictionary<IRequest, IQuoteTimeSeries>
. IRequest representa una solicitud específica de datos y IQuoteTimeSeries es el objeto que contiene los datos de devolución como SortedDictionary<DateTime, IQuote>
. Esta es una serie de datos ordenados por fecha y hora. En este ejemplo, solo tengo un elemento en el TimeSeries para abreviar, pero en la mayoría de los casos habría muchos artículos.
Todo debe organizarse, serializarse y enviarse para ser consumido por JavaScript.
Aquí está el código básico para estos objetos;
[JsonArray]
public class QuoteRepository : Dictionary<IRequest, IQuoteTimeSeries>, IQuoteRepository
{
public QuoteRepository() { }
public void AddRequest(IRequest request)
{
if (!this.ContainsKey(request))
{
IQuoteTimeSeries tSeries = new QuoteTimeSeries(request);
this.Add(request, tSeries);
}
}
public void AddQuote(IRequest request, IQuote quote)
{
if (!this.ContainsKey(request))
{
QuoteTimeSeries tSeries = new QuoteTimeSeries(request);
this.Add(request, tSeries);
}
this[request].AddQuote(quote);
}
IEnumerator<IQuoteTimeSeries> Enumerable<IQuoteTimeSeries>.GetEnumerator()
{
return this.Values.GetEnumerator();
}
}
Una serie de tiempo de citas se ve así;
[JsonArray]
public class QuoteTimeSeries: SortedDictionary<DateTime, IQuote>, IQuoteTimeSeries
{
public QuoteTimeSeries(IRequest request)
{
Request = request;
}
public IRequest Request { get; }
public void AddQuote(IQuote quote)
{
this[quote.QuoteTimeStamp] = quote;
}
public void MergeQuotes(IQuoteTimeSeries quotes)
{
foreach (IQuote item in quotes)
{
this[item.QuoteTimeStamp] = item;
}
}
IEnumerator<IQuote> IEnumerable<IQuote>.GetEnumerator()
{
return this.Values.GetEnumerator();
}
}
El código utilizado para serializar esto es bastante simple:
IQuoteRepository quotes = await requests.GetDataAsync();
JsonSerializerSettings settings = new JsonSerializerSettings
{
ContractResolver = QuoteRepositoryContractResolver.Instance,
NullValueHandling = NullValueHandling.Ignore
};
return Json<IQuoteRepository>(quotes, settings);
Agregué un resolver del contrato con la intención de anular la escritura de la propiedad. El property.PropertyName =
código está siendo golpeado y los nombres de propiedad están siendo cambiados, pero el JSON de salida no se ve afectado.
public class QuoteRepositoryContractResolver : DefaultContractResolver
{
public static readonly QuoteRepositoryContractResolver Instance = new QuoteRepositoryContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.DeclaringType == typeof(KeyValuePair<IRequest, IQuoteTimeSeries>))
{
if (property.PropertyName.Equals("Key", StringComparison.OrdinalIgnoreCase))
{
property.PropertyName = "Request";
}
else if (property.PropertyName.Equals("Value", StringComparison.OrdinalIgnoreCase))
{
property.PropertyName = "Data";
}
}
else if (property.DeclaringType == typeof(KeyValuePair<DateTime, IQuote>))
{
if (property.PropertyName.Equals("Key", StringComparison.OrdinalIgnoreCase))
{
property.PropertyName = "TimeStamp";
}
else if (property.PropertyName.Equals("Value", StringComparison.OrdinalIgnoreCase))
{
property.PropertyName = "Quote";
}
}
return property;
}
}
La salida JSON es impar. Los elementos de clave y valor están completamente sin cambios, aunque cambié sus nombres en el código.
[
{
"Key": {
"QuoteDate": "2016-05-12T00:00:00-04:00",
"QuoteType": "Index",
"Symbol": "SPY",
"UseCache": true
},
"Value": [
{
"Key": "2016-05-11T16:00:01-04:00",
"Value": {
"Description": "SPDR S&P 500",
"High": 208.54,
"Low": 206.50,
"Change": -1.95,
"ChangePer": -0.94,
"Price": 206.50,
"QuoteTimeStamp": "2016-05-11T16:00:01-04:00",
"Symbol": "SPY"
}
}
]
},
{
"Key": {
"QuoteDate": "2016-05-12T00:00:00-04:00",
"QuoteType": "Stock",
"Symbol": "GOOG",
"UseCache": true
},
"Value": [
{
"Key": "2016-05-11T16:00:00-04:00",
"Value": {
"Description": "Alphabet Inc.",
"High": 724.48,
"Low": 712.80,
"Change": -7.89,
"ChangePer": -1.09,
"Price": 715.29,
"QuoteTimeStamp": "2016-05-11T16:00:00-04:00",
"Symbol": "GOOG"
}
}
]
}
]
¿Alguien sabe cómo cambiar los elementos ''Clave'' y ''Valor'' correctamente?
La conversión de su diccionario de Dictionary<IRequest, IQuoteTimeSeries>
a List<KeyValuePair<IRequest, IQuoteTimeSeries>>
también debería funcionar.
Una forma de resolver esto es utilizar un JsonConverter
personalizado para sus clases basadas en el diccionario. El código es bastante directo.
public class CustomDictionaryConverter<K, V> : JsonConverter
{
private string KeyPropertyName { get; set; }
private string ValuePropertyName { get; set; }
public CustomDictionaryConverter(string keyPropertyName, string valuePropertyName)
{
KeyPropertyName = keyPropertyName;
ValuePropertyName = valuePropertyName;
}
public override bool CanConvert(Type objectType)
{
return typeof(IDictionary<K, V>).IsAssignableFrom(objectType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
IDictionary<K, V> dict = (IDictionary<K, V>)value;
JArray array = new JArray();
foreach (var kvp in dict)
{
JObject obj = new JObject();
obj.Add(KeyPropertyName, JToken.FromObject(kvp.Key, serializer));
obj.Add(ValuePropertyName, JToken.FromObject(kvp.Value, serializer));
array.Add(obj);
}
array.WriteTo(writer);
}
public override bool CanRead
{
get { return false; }
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Cuando JsonSerializerSettings
el momento de serializar, agregue los convertidores a JsonSerializerSettings
la JsonSerializerSettings
manera:
JsonSerializerSettings settings = new JsonSerializerSettings
{
Converters = new List<JsonConverter>
{
new CustomDictionaryConverter<IRequest, IQuoteTimeSeries>("Request", "Data"),
new CustomDictionaryConverter<DateTime, IQuote>("TimeStamp", "Quote")
},
Formatting = Formatting.Indented
};
string json = JsonConvert.SerializeObject(repo, settings);
Fiddle: https://dotnetfiddle.net/roHEtx