Cara menangani satu item dan larik untuk properti yang sama menggunakan JSON.net


101

Saya mencoba memperbaiki pustaka SendGridPlus saya untuk menangani acara SendGrid, tetapi saya mengalami masalah dengan perlakuan kategori yang tidak konsisten di API.

Dalam contoh payload berikut yang diambil dari referensi SendGrid API , Anda akan melihat bahwa categoryproperti untuk setiap item dapat berupa string tunggal atau larik string.

[
  {
    "email": "john.doe@sendgrid.com",
    "timestamp": 1337966815,
    "category": [
      "newuser",
      "transactional"
    ],
    "event": "open"
  },
  {
    "email": "jane.doe@sendgrid.com",
    "timestamp": 1337966815,
    "category": "olduser",
    "event": "open"
  }
]

Tampaknya pilihan saya untuk membuat JSON.NET seperti ini memperbaiki string sebelum masuk, atau mengkonfigurasi JSON.NET untuk menerima data yang salah. Saya lebih suka tidak melakukan parsing string apa pun jika saya bisa lolos begitu saja.

Apakah ada cara lain saya dapat menangani ini menggunakan Json.Net?

Jawaban:


203

Cara terbaik untuk menangani situasi ini adalah dengan menggunakan kebiasaan JsonConverter.

Sebelum kita masuk ke konverter, kita perlu menentukan kelas untuk deserialisasi datanya. Untuk Categoriesproperti yang dapat bervariasi antara satu item dan larik, tentukan sebagai a List<string>dan tandai dengan [JsonConverter]atribut sehingga JSON.Net akan tahu untuk menggunakan konverter khusus untuk properti itu. Saya juga akan merekomendasikan penggunaan [JsonProperty]atribut sehingga properti anggota dapat diberi nama yang bermakna terlepas dari apa yang didefinisikan di 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; }
}

Berikut adalah bagaimana saya akan menerapkan konverter. Perhatikan saya telah membuat konverter generik sehingga dapat digunakan dengan string atau jenis objek lain sesuai kebutuhan.

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();
    }
}

Berikut adalah program singkat yang mendemonstrasikan konverter beraksi dengan data sampel Anda:

class Program
{
    static void Main(string[] args)
    {
        string json = @"
        [
          {
            ""email"": ""john.doe@sendgrid.com"",
            ""timestamp"": 1337966815,
            ""category"": [
              ""newuser"",
              ""transactional""
            ],
            ""event"": ""open""
          },
          {
            ""email"": ""jane.doe@sendgrid.com"",
            ""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();
        }
    }
}

Dan terakhir, inilah keluaran dari di atas:

email: john.doe@sendgrid.com
timestamp: 1337966815
event: open
categories: newuser, transactional

email: jane.doe@sendgrid.com
timestamp: 1337966815
event: open
categories: olduser

Biola: https://dotnetfiddle.net/lERrmu

EDIT

Jika Anda perlu menggunakan cara lain, yaitu membuat serial, dengan tetap mempertahankan format yang sama, Anda dapat menerapkan WriteJson()metode konverter seperti yang ditunjukkan di bawah ini. (Pastikan untuk menghapus CanWritepenggantian atau mengubahnya untuk mengembalikan true, atau tidak WriteJson()akan pernah dipanggil.)

    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);
    }

Biola: https://dotnetfiddle.net/XG3eRy


5
Sempurna! Kamulah orangnya. Untungnya, saya telah melakukan semua hal lain tentang penggunaan JsonProperty untuk membuat properti lebih bermakna. Terima kasih atas jawaban yang sangat lengkap. :)
Robert McLaws

Tidak masalah; senang Anda merasa terbantu.
Brian Rogers

1
Luar biasa! Inilah yang saya cari-cari. @BrianRogers, jika Anda pernah ke Amsterdam, minuman ada pada saya!
Mad Dog Tannen

2
@israelaltar Anda tidak perlu menambahkan konverter ke DeserializeObjectpanggilan jika Anda menggunakan [JsonConverter]atribut pada properti list di kelas Anda, seperti yang ditunjukkan pada jawaban di atas. Jika Anda tidak menggunakan atribut tersebut, ya, Anda harus meneruskan konverter ke DeserializeObject.
Brian Rogers

1
@ShaunLangley Untuk membuat konverter menggunakan larik alih-alih daftar, ubah semua referensi ke List<T>dalam konverter T[]dan ubah .Countke .Length. dotnetfiddle.net/vnCNgZ
Brian Rogers

6

Saya mengerjakan ini selama berabad-abad, dan terima kasih kepada Brian atas jawabannya. Yang saya tambahkan hanyalah jawaban 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

lalu di kelasmu:

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

Semoga ini menghemat waktu Anda


Typos: <JsonConverter (GetType (SingleValueArrayConverter (Of YourObject)))> _ Properti Umum YourLocalName Sebagai Daftar (Of YourObject)
GlennG

3

Sebagai variasi kecil pada jawaban yang bagus oleh Brian Rogers , di sini adalah dua versi tweak dari SingleOrArrayConverter<T>.

Pertama, berikut adalah versi yang berfungsi untuk semua List<T>untuk setiap jenis Tyang bukan merupakan koleksi itu sendiri:

public class SingleOrArrayListConverter : JsonConverter
{
    // Adapted from this answer https://stackoverflow.com/a/18997172
    // to /programming/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n
    // by Brian Rogers https://stackoverflow.com/users/10263/brian-rogers
    readonly bool canWrite;
    readonly IContractResolver resolver;

    public SingleOrArrayListConverter() : this(false) { }

    public SingleOrArrayListConverter(bool canWrite) : this(canWrite, null) { }

    public SingleOrArrayListConverter(bool canWrite, IContractResolver resolver)
    {
        this.canWrite = canWrite;
        // Use the global default resolver if none is passed in.
        this.resolver = resolver ?? new JsonSerializer().ContractResolver;
    }

    static bool CanConvert(Type objectType, IContractResolver resolver)
    {
        Type itemType;
        JsonArrayContract contract;
        return CanConvert(objectType, resolver, out itemType, out contract);
    }

    static bool CanConvert(Type objectType, IContractResolver resolver, out Type itemType, out JsonArrayContract contract)
    {
        if ((itemType = objectType.GetListItemType()) == null)
        {
            itemType = null;
            contract = null;
            return false;
        }
        // Ensure that [JsonObject] is not applied to the type.
        if ((contract = resolver.ResolveContract(objectType) as JsonArrayContract) == null)
            return false;
        var itemContract = resolver.ResolveContract(itemType);
        // Not implemented for jagged arrays.
        if (itemContract is JsonArrayContract)
            return false;
        return true;
    }

    public override bool CanConvert(Type objectType) { return CanConvert(objectType, resolver); }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        Type itemType;
        JsonArrayContract contract;

        if (!CanConvert(objectType, serializer.ContractResolver, out itemType, out contract))
            throw new JsonSerializationException(string.Format("Invalid type for {0}: {1}", GetType(), objectType));
        if (reader.MoveToContent().TokenType == JsonToken.Null)
            return null;
        var list = (IList)(existingValue ?? contract.DefaultCreator());
        if (reader.TokenType == JsonToken.StartArray)
            serializer.Populate(reader, list);
        else
            // Here we take advantage of the fact that List<T> implements IList to avoid having to use reflection to call the generic Add<T> method.
            list.Add(serializer.Deserialize(reader, itemType));
        return list;
    }

    public override bool CanWrite { get { return canWrite; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var list = value as ICollection;
        if (list == null)
            throw new JsonSerializationException(string.Format("Invalid type for {0}: {1}", GetType(), value.GetType()));
        // Here we take advantage of the fact that List<T> implements IList to avoid having to use reflection to call the generic Count method.
        if (list.Count == 1)
        {
            foreach (var item in list)
            {
                serializer.Serialize(writer, item);
                break;
            }
        }
        else
        {
            writer.WriteStartArray();
            foreach (var item in list)
                serializer.Serialize(writer, item);
            writer.WriteEndArray();
        }
    }
}

public static partial class JsonExtensions
{
    public static JsonReader MoveToContent(this JsonReader reader)
    {
        while ((reader.TokenType == JsonToken.Comment || reader.TokenType == JsonToken.None) && reader.Read())
            ;
        return reader;
    }

    internal static Type GetListItemType(this Type type)
    {
        // Quick reject for performance
        if (type.IsPrimitive || type.IsArray || type == typeof(string))
            return null;
        while (type != null)
        {
            if (type.IsGenericType)
            {
                var genType = type.GetGenericTypeDefinition();
                if (genType == typeof(List<>))
                    return type.GetGenericArguments()[0];
            }
            type = type.BaseType;
        }
        return null;
    }
}

Ini dapat digunakan sebagai berikut:

var settings = new JsonSerializerSettings
{
    // Pass true if you want single-item lists to be reserialized as single items
    Converters = { new SingleOrArrayListConverter(true) },
};
var list = JsonConvert.DeserializeObject<List<Item>>(json, settings);

Catatan:

  • Konverter menghindari kebutuhan untuk memuat terlebih dahulu seluruh nilai JSON ke dalam memori sebagai JToken hierarki.

  • Konverter tidak berlaku untuk daftar yang itemnya juga diserialkan sebagai koleksi, mis List<string []>

  • Boolean canWriteArgumen diteruskan ke kontrol konstruktor apakah akan menyusun ulang daftar elemen tunggal sebagai nilai JSON atau sebagai array JSON.

  • Konverter ReadJson()menggunakanexistingValue if pra-alokasi untuk mendukung pengisian anggota daftar get-only.

Kedua, berikut adalah versi yang berfungsi dengan koleksi umum lainnya seperti ObservableCollection<T>:

public class SingleOrArrayCollectionConverter<TCollection, TItem> : JsonConverter
    where TCollection : ICollection<TItem>
{
    // Adapted from this answer https://stackoverflow.com/a/18997172
    // to /programming/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n
    // by Brian Rogers https://stackoverflow.com/users/10263/brian-rogers
    readonly bool canWrite;

    public SingleOrArrayCollectionConverter() : this(false) { }

    public SingleOrArrayCollectionConverter(bool canWrite) { this.canWrite = canWrite; }

    public override bool CanConvert(Type objectType)
    {
        return typeof(TCollection).IsAssignableFrom(objectType);
    }

    static void ValidateItemContract(IContractResolver resolver)
    {
        var itemContract = resolver.ResolveContract(typeof(TItem));
        if (itemContract is JsonArrayContract)
            throw new JsonSerializationException(string.Format("Item contract type {0} not supported.", itemContract));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        ValidateItemContract(serializer.ContractResolver);
        if (reader.MoveToContent().TokenType == JsonToken.Null)
            return null;
        var list = (ICollection<TItem>)(existingValue ?? serializer.ContractResolver.ResolveContract(objectType).DefaultCreator());
        if (reader.TokenType == JsonToken.StartArray)
            serializer.Populate(reader, list);
        else
            list.Add(serializer.Deserialize<TItem>(reader));
        return list;
    }

    public override bool CanWrite { get { return canWrite; } }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        ValidateItemContract(serializer.ContractResolver);
        var list = value as ICollection<TItem>;
        if (list == null)
            throw new JsonSerializationException(string.Format("Invalid type for {0}: {1}", GetType(), value.GetType()));
        if (list.Count == 1)
        {
            foreach (var item in list)
            {
                serializer.Serialize(writer, item);
                break;
            }
        }
        else
        {
            writer.WriteStartArray();
            foreach (var item in list)
                serializer.Serialize(writer, item);
            writer.WriteEndArray();
        }
    }
}

Kemudian, jika model Anda menggunakan, katakanlah, an ObservableCollection<T>untuk beberapa T, Anda dapat menerapkannya sebagai berikut:

class Item
{
    public string Email { get; set; }
    public int Timestamp { get; set; }
    public string Event { get; set; }

    [JsonConverter(typeof(SingleOrArrayCollectionConverter<ObservableCollection<string>, string>))]
    public ObservableCollection<string> Category { get; set; }
}

Catatan:

  • Selain catatan dan batasan untuk SingleOrArrayListConverter , TCollectionjenisnya harus baca / tulis dan memiliki konstruktor tanpa parameter.

Demo biola dengan tes unit dasar di sini .


0

Saya memiliki masalah yang sangat mirip. Permintaan Json saya sama sekali tidak saya kenal. Saya hanya tahu.

Akan ada objectId di dalamnya dan beberapa pasangan nilai kunci anonim DAN array.

Saya menggunakannya untuk Model EAV yang saya lakukan:

Permintaan JSON Saya:

{objectId ": 2," firstName ":" Hans "," email ": [" a@b.de "," a@c.de "]," name ":" Andre "," something ": [" 232 "," 123 "]}

Kelas saya yang saya tentukan:

[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; }
}

dan sekarang saya ingin deserialize atribut yang tidak diketahui dengan nilai dan array di dalamnya Konverter saya terlihat seperti itu:

   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;
    }

Jadi sekarang setiap kali saya mendapatkan AnonymObject saya dapat beralih melalui Kamus dan setiap kali ada Bendera saya "ValueDummyForEAV" saya beralih ke daftar, membaca baris pertama dan membagi nilainya. Setelah itu saya menghapus entri pertama dari daftar dan melanjutkan iterasi dari Kamus.

Mungkin seseorang memiliki masalah yang sama dan dapat menggunakan ini :)

Salam Andre


0

Anda dapat menggunakan JSONConverterAttributeseperti yang ditemukan di sini: http://james.newtonking.com/projects/json/help/

Menganggap Anda memiliki kelas yang mirip

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; }
}

Anda akan mendekorasi properti kategori seperti yang terlihat di sini:

    [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();
  }
}

Terima kasih untuk ini, tetapi masih belum menyelesaikan masalah. Ketika sebuah array yang sebenarnya masuk, itu masih membuat kesalahan sebelum kode saya bahkan dapat dieksekusi untuk objek yang memiliki array yang sebenarnya. 'Informasi tambahan: Token tak terduga saat deserialisasi objek: String. Jalur '[2] .category [0]', baris 17, posisi 27. '
Robert McLaws

+ "\" acara \ ": \" diproses \ ", \ n" + "} \ n" + "]";
Robert McLaws

Ini memproses objek pertama dengan baik dan menangani tidak ada array dengan indah. Tetapi ketika saya membuat sebuah array untuk objek ke-2, gagal.
Robert McLaws

@AdvancedREI Tanpa melihat kode Anda, saya kira Anda meninggalkan pembaca dengan posisi yang salah setelah Anda membaca JSON. Daripada mencoba menggunakan pembaca secara langsung, lebih baik memuat objek JToken dari pembaca dan pergi dari sana. Lihat jawaban saya untuk implementasi konverter yang berfungsi.
Brian Rogers

Detail yang jauh lebih baik dalam jawaban Brian. Gunakan yang itu :)
Tim Gabrhel

0

Untuk menangani ini, Anda harus menggunakan JsonConverter kustom. Tapi Anda mungkin sudah memikirkannya. Anda hanya mencari konverter yang dapat Anda gunakan segera. Dan ini menawarkan lebih dari sekedar solusi untuk situasi yang dijelaskan. Saya memberi contoh dengan pertanyaan yang diajukan.

Cara menggunakan konverter saya:

Tempatkan Atribut JsonConverter di atas properti. JsonConverter(typeof(SafeCollectionConverter))

public class SendGridEvent
{
    [JsonProperty("email")]
    public string Email { get; set; }

    [JsonProperty("timestamp")]
    public long Timestamp { get; set; }

    [JsonProperty("category"), JsonConverter(typeof(SafeCollectionConverter))]
    public string[] Category { get; set; }

    [JsonProperty("event")]
    public string Event { get; set; }
}

Dan ini konverter saya:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;

namespace stackoverflow.question18994685
{
    public class SafeCollectionConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return true;
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            //This not works for Populate (on existingValue)
            return serializer.Deserialize<JToken>(reader).ToObjectCollectionSafe(objectType, serializer);
        }     

        public override bool CanWrite => false;

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
}

Dan konverter ini menggunakan kelas berikut:

using System;

namespace Newtonsoft.Json.Linq
{
    public static class SafeJsonConvertExtensions
    {
        public static object ToObjectCollectionSafe(this JToken jToken, Type objectType)
        {
            return ToObjectCollectionSafe(jToken, objectType, JsonSerializer.CreateDefault());
        }

        public static object ToObjectCollectionSafe(this JToken jToken, Type objectType, JsonSerializer jsonSerializer)
        {
            var expectArray = typeof(System.Collections.IEnumerable).IsAssignableFrom(objectType);

            if (jToken is JArray jArray)
            {
                if (!expectArray)
                {
                    //to object via singel
                    if (jArray.Count == 0)
                        return JValue.CreateNull().ToObject(objectType, jsonSerializer);

                    if (jArray.Count == 1)
                        return jArray.First.ToObject(objectType, jsonSerializer);
                }
            }
            else if (expectArray)
            {
                //to object via JArray
                return new JArray(jToken).ToObject(objectType, jsonSerializer);
            }

            return jToken.ToObject(objectType, jsonSerializer);
        }

        public static T ToObjectCollectionSafe<T>(this JToken jToken)
        {
            return (T)ToObjectCollectionSafe(jToken, typeof(T));
        }

        public static T ToObjectCollectionSafe<T>(this JToken jToken, JsonSerializer jsonSerializer)
        {
            return (T)ToObjectCollectionSafe(jToken, typeof(T), jsonSerializer);
        }
    }
}

Apa tepatnya yang dilakukannya? Jika Anda menempatkan atribut konverter, konverter akan digunakan untuk properti ini. Anda dapat menggunakannya pada objek normal jika Anda mengharapkan array json dengan 1 atau tanpa hasil. Atau Anda menggunakannya di IEnumerabletempat Anda mengharapkan objek json atau array json. (Ketahuilah bahwa array- object[]- adalah an IEnumerable) Kerugiannya adalah bahwa konverter ini hanya dapat ditempatkan di atas properti karena dia pikir dia dapat mengubah semuanya. Dan berhati-hatilah . A stringjuga merupakanIEnumerable .

Dan itu menawarkan lebih dari satu jawaban untuk pertanyaan: Jika Anda mencari sesuatu dengan id Anda tahu bahwa Anda akan mendapatkan kembali array dengan satu atau tanpa hasil. ItuToObjectCollectionSafe<TResult>() Metode dapat menangani untuk Anda.

Ini dapat digunakan untuk Hasil Tunggal vs Larik menggunakan JSON.net dan menangani satu item dan larik untuk properti yang sama dan dapat mengonversi larik menjadi satu objek.

Saya membuat ini untuk permintaan REST di server dengan filter yang mengembalikan satu hasil dalam array tetapi ingin mendapatkan hasilnya kembali sebagai objek tunggal dalam kode saya. Dan juga untuk respons hasil OData dengan hasil yang diperluas dengan satu item dalam array.

Bersenang-senanglah dengannya.


-2

Saya menemukan solusi lain yang dapat menangani kategori sebagai string atau array dengan menggunakan objek. Dengan cara ini saya tidak perlu mengacaukan serializer json.

Tolong perhatikan jika Anda punya waktu dan beri tahu saya apa yang Anda pikirkan. https://github.com/MarcelloCarreira/sendgrid-csharp-eventwebhook

Ini didasarkan pada solusi di https://sendgrid.com/blog/tracking-email-using-azure-sendgrid-event-webhook-part-1/ tetapi saya juga menambahkan konversi tanggal dari stempel waktu, meningkatkan variabel untuk mencerminkan model SendGrid saat ini (dan membuat kategori berfungsi).

Saya juga membuat penangan dengan autentikasi dasar sebagai opsi. Lihat file ashx dan contohnya.

Terima kasih!

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.