www type template should net emails content application json.net sendgrid

type - Cómo manejar un solo elemento y una matriz para la misma propiedad usando JSON.net



smtp sendgrid net (5)

Encontré otra solución que puede manejar la categoría como cadena o matriz mediante el uso de objetos. De esta forma no necesito estropear el serializador json.

Por favor échale un vistazo si tienes tiempo y dime lo que piensas. https://github.com/MarcelloCarreira/sendgrid-csharp-eventwebhook

Se basa en la solución en https://sendgrid.com/blog/tracking-email-using-azure-sendgrid-event-webhook-part-1/ pero también agregué la fecha de conversión de la marca de tiempo, actualicé las variables para reflejar modelo actual SendGrid (y las categorías hechas funcionan).

También creé un controlador con autenticación básica como opción. Vea los archivos ashx y los ejemplos.

¡Gracias!

Estoy tratando de arreglar mi biblioteca SendGridPlus para manejar eventos SendGrid, pero estoy teniendo problemas con el tratamiento inconsistente de las categorías en la API.

En el siguiente ejemplo de carga útil tomada de la referencia de API de SendGrid , observará que la propiedad de category para cada elemento puede ser una sola cadena o una matriz de cadenas.

[ { "email": "[email protected]", "timestamp": 1337966815, "category": [ "newuser", "transactional" ], "event": "open" }, { "email": "[email protected]", "timestamp": 1337966815, "category": "olduser", "event": "open" } ]

Parece que mis opciones para hacer JSON.NET como este son arreglar la cadena antes de que entre, o configurar JSON.NET para aceptar los datos incorrectos. Prefiero no hacer ningún análisis de cadenas si puedo salirse con la suya.

¿Hay alguna otra forma en que pueda manejar esto usando Json.Net?


Estuve trabajando en esto por años, y gracias a Brian por su respuesta. ¡Todo lo que estoy agregando es la respuesta de vb.net !:

Public Class SingleValueArrayConverter(Of T) sometimes-array-and-sometimes-object Inherits JsonConverter Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer) Throw New NotImplementedException() End Sub Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object Dim retVal As Object = New [Object]() If reader.TokenType = JsonToken.StartObject Then Dim instance As T = DirectCast(serializer.Deserialize(reader, GetType(T)), T) retVal = New List(Of T)() From { _ instance _ } ElseIf reader.TokenType = JsonToken.StartArray Then retVal = serializer.Deserialize(reader, objectType) End If Return retVal End Function Public Overrides Function CanConvert(objectType As Type) As Boolean Return False End Function End Class

entonces en tu clase:

<JsonProperty(PropertyName:="JsonName)> _ <JsonConverter(GetType(SingleValueArrayConverter(Of YourObject)))> _ Public Property YourLocalName As List(Of YourObject)

Espero que esto te ahorre algo de tiempo


La mejor forma de manejar esta situación es usar un JsonConverter personalizado.

Antes de llegar al convertidor, necesitaremos definir una clase para deserializar los datos. Para la propiedad Categories que puede variar entre un único elemento y una matriz, [JsonConverter] como una List<string> y [JsonConverter] con un atributo [JsonConverter] para que JSON.Net sepa usar el convertidor personalizado para esa propiedad. También recomendaría el uso de atributos [JsonProperty] para que las propiedades del miembro puedan recibir nombres significativos independientemente de lo que se define en el JSON.

class Item { [JsonProperty("email")] public string Email { get; set; } [JsonProperty("timestamp")] public int Timestamp { get; set; } [JsonProperty("event")] public string Event { get; set; } [JsonProperty("category")] [JsonConverter(typeof(SingleOrArrayConverter<string>))] public List<string> Categories { get; set; } }

Aquí es cómo implementaría el convertidor. Tenga en cuenta que he convertido el convertidor genérico para que se pueda usar con cadenas u otros tipos de objetos según sea necesario.

class SingleOrArrayConverter<T> : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(List<T>)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JToken token = JToken.Load(reader); if (token.Type == JTokenType.Array) { return token.ToObject<List<T>>(); } return new List<T> { token.ToObject<T>() }; } public override bool CanWrite { get { return false; } } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } }

Aquí hay un programa corto que demuestra el convertidor en acción con sus datos de muestra:

class Program { static void Main(string[] args) { string json = @" [ { ""email"": ""[email protected]"", ""timestamp"": 1337966815, ""category"": [ ""newuser"", ""transactional"" ], ""event"": ""open"" }, { ""email"": ""[email protected]"", ""timestamp"": 1337966815, ""category"": ""olduser"", ""event"": ""open"" } ]"; List<Item> list = JsonConvert.DeserializeObject<List<Item>>(json); foreach (Item obj in list) { Console.WriteLine("email: " + obj.Email); Console.WriteLine("timestamp: " + obj.Timestamp); Console.WriteLine("event: " + obj.Event); Console.WriteLine("categories: " + string.Join(", ", obj.Categories)); Console.WriteLine(); } } }

Y finalmente, aquí está el resultado de lo anterior:

email: [email protected] timestamp: 1337966815 event: open categories: newuser, transactional email: [email protected] timestamp: 1337966815 event: open categories: olduser

Fiddle: https://dotnetfiddle.net/lERrmu

EDITAR

Si necesita ir por el otro lado, es decir, serializar, manteniendo el mismo formato, puede implementar el método WriteJson() del convertidor como se muestra a continuación. (Asegúrese de eliminar la anulación de CanWrite o cámbiela para que sea true , o de lo WriteJson() nunca se WriteJson() .)

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { List<T> list = (List<T>)value; if (list.Count == 1) { value = list[0]; } serializer.Serialize(writer, value); }

Fiddle: https://dotnetfiddle.net/XG3eRy


Puede usar un JSONConverterAttribute como se encuentra aquí: http://james.newtonking.com/projects/json/help/

Suponiendo que tienes una clase que se parece a

public class RootObject { public string email { get; set; } public int timestamp { get; set; } public string smtpid { get; set; } public string @event { get; set; } public string category[] { get; set; } }

Decorarías la propiedad de categoría como se ve aquí:

[JsonConverter(typeof(SendGridCategoryConverter))] public string category { get; set; } public class SendGridCategoryConverter : JsonConverter { public override bool CanConvert(Type objectType) { return true; // add your own logic } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // do work here to handle returning the array regardless of the number of objects in } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // Left as an exercise to the reader :) throw new NotImplementedException(); } }


Tuve un problema muy similar. My Json Request fue completamente desconocido para mí. Solo lo sabía

Habrá un objectId en él y algunos pares de AND de valor clave de anonimato.

Lo usé para un modelo EAV que hice:

Mi solicitud JSON:

{objectId ": 2," firstName ":" Hans "," email ": [" [email protected] "," [email protected] "]," nombre ":" Andre "," algo ": [" 232 "," 123 "]}

Mi clase yo definí:

[JsonConverter(typeof(AnonyObjectConverter))] public class AnonymObject { public AnonymObject() { fields = new Dictionary<string, string>(); list = new List<string>(); } public string objectid { get; set; } public Dictionary<string, string> fields { get; set; } public List<string> list { get; set; } }

y ahora que quiero deserializar atributos desconocidos con su valor y matrices en él, mi convertidor se ve así:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { AnonymObject anonym = existingValue as AnonymObject ?? new AnonymObject(); bool isList = false; StringBuilder listValues = new StringBuilder(); while (reader.Read()) { if (reader.TokenType == JsonToken.EndObject) continue; if (isList) { while (reader.TokenType != JsonToken.EndArray) { listValues.Append(reader.Value.ToString() + ", "); reader.Read(); } anonym.list.Add(listValues.ToString()); isList = false; continue; } var value = reader.Value.ToString(); switch (value.ToLower()) { case "objectid": anonym.objectid = reader.ReadAsString(); break; default: string val; reader.Read(); if(reader.TokenType == JsonToken.StartArray) { isList = true; val = "ValueDummyForEAV"; } else { val = reader.Value.ToString(); } try { anonym.fields.Add(value, val); } catch(ArgumentException e) { throw new ArgumentException("Multiple Attribute found"); } break; } } return anonym; }

Entonces, cada vez que obtengo un AnonymObject puedo iterar a través del Diccionario y cada vez que aparece mi Marcador "ValueDummyForEAV", cambio a la lista, leo la primera línea y divido los valores. Después de eso elimino la primera entrada de la lista y sigo con la iteración del Diccionario.

Tal vez alguien tenga el mismo problema y pueda usar esto :)

Saludos, Andre