Cách xử lý cả một mục và một mảng cho cùng một thuộc tính bằng cách sử dụng JSON.net


101

Tôi đang cố gắng sửa thư viện SendGridPlus của mình để đối phó với các sự kiện SendGrid, nhưng tôi đang gặp một số rắc rối với việc xử lý các danh mục trong API không nhất quán.

Trong ví dụ về tải trọng sau được lấy từ tham chiếu API SendGrid , bạn sẽ nhận thấy rằng thuộc categorytính cho mỗi mục có thể là một chuỗi đơn hoặc một mảng chuỗi.

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

Có vẻ như các tùy chọn của tôi để làm cho JSON.NET như thế này đang sửa chuỗi trước khi nó đi vào hoặc định cấu hình JSON.NET để chấp nhận dữ liệu không chính xác. Tôi không muốn thực hiện bất kỳ phân tích chuỗi nào nếu tôi có thể thoát khỏi nó.

Có cách nào khác mà tôi có thể xử lý vấn đề này bằng Json.Net không?

Câu trả lời:


203

Cách tốt nhất để xử lý tình huống này là sử dụng JsonConverter .

Trước khi chuyển đến trình chuyển đổi, chúng ta cần xác định một lớp để giải mã dữ liệu vào đó. Đối với thuộc Categoriestính có thể khác nhau giữa một mục và một mảng, hãy xác định nó là a List<string>và đánh dấu nó bằng một [JsonConverter]thuộc tính để JSON.Net biết cách sử dụng trình chuyển đổi tùy chỉnh cho thuộc tính đó. Tôi cũng khuyên bạn nên sử dụng [JsonProperty]các thuộc tính để các thuộc tính thành viên có thể được đặt tên có ý nghĩa độc lập với những gì được định nghĩa trong 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; }
}

Đây là cách tôi sẽ triển khai trình chuyển đổi. Lưu ý rằng tôi đã tạo bộ chuyển đổi chung để nó có thể được sử dụng với chuỗi hoặc các loại đối tượng khác khi cần thiết.

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

Đây là một chương trình ngắn trình bày bộ chuyển đổi hoạt động với dữ liệu mẫu của bạn:

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

Và cuối cùng, đây là kết quả của phần trên:

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

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

Fiddle: https://dotnetfiddle.net/lERrmu

BIÊN TẬP

Nếu bạn cần làm theo cách khác, tức là tuần tự hóa, trong khi vẫn giữ nguyên định dạng, bạn có thể thực hiện WriteJson()phương pháp của trình chuyển đổi như hình dưới đây. (Hãy chắc chắn xóa CanWriteghi đè hoặc thay đổi nó để trả lại true, nếu không WriteJson()sẽ không bao giờ được gọi.)

    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


5
Hoàn hảo! Bạn là một người đàn ông. May mắn thay, tôi đã làm tất cả những thứ khác về việc sử dụng JsonProperty để làm cho các thuộc tính có ý nghĩa hơn. Cảm ơn bạn vì một câu trả lời hoàn chỉnh đáng kinh ngạc. :)
Robert McLaws

Không vấn đề gì; Vui mừng bạn đã tìm thấy nó hữu ích.
Brian Rogers

1
Thông minh! Đây là những gì tôi đã tìm kiếm. @BrianRogers, nếu bạn đã từng ở Amsterdam, tôi sẽ có đồ uống!
Mad Dog Tannen

2
@israelaltar Bạn không cần thêm trình chuyển đổi vào lệnh DeserializeObjectgọi nếu bạn sử dụng [JsonConverter]thuộc tính trên thuộc tính danh sách trong lớp của mình, như được hiển thị trong câu trả lời ở trên. Nếu bạn không sử dụng thuộc tính, thì, có, bạn sẽ cần chuyển trình chuyển đổi sang DeserializeObject.
Brian Rogers

1
@ShaunLangley Để làm cho bộ chuyển đổi sử dụng một mảng thay vì một danh sách, hãy thay đổi tất cả các tham chiếu đến List<T>trong bộ chuyển đổi thành T[]và thay đổi .Countthành .Length. dotnetfiddle.net/vnCNgZ
Brian Rogers

6

Tôi đã làm việc này trong nhiều thời gian, và cảm ơn Brian vì câu trả lời của anh ấy. Tất cả những gì tôi đang thêm là câu trả lời 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

sau đó trong lớp của bạn:

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

Hy vọng điều này giúp bạn tiết kiệm thời gian


Typos: <JsonConverter (GetType (SingleValueArrayConverter (Of YourObject)))> _ Public Property YourLocalName As List (Of YourObject)
GlennG

3

Là một biến thể nhỏ cho câu trả lời tuyệt vời của Brian Rogers , đây là hai phiên bản đã được tinh chỉnh của SingleOrArrayConverter<T>.

Thứ nhất, đây là một phiên bản hoạt động cho tất cả List<T>mọi loại Tmà bản thân nó không phải là một bộ sưu tập:

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

Nó có thể được sử dụng như sau:

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

Ghi chú:

  • Bộ chuyển đổi tránh yêu cầu tải trước toàn bộ giá trị JSON vào bộ nhớ dưới dạng JTokenphân cấp.

  • Bộ chuyển đổi không áp dụng cho các danh sách có các mục cũng được tuần tự hóa dưới dạng bộ sưu tập, ví dụ: List<string []>

  • Đối canWritesố Boolean được truyền cho hàm tạo kiểm soát việc tuần tự hóa lại danh sách phần tử đơn dưới dạng giá trị JSON hay dưới dạng mảng JSON.

  • Bộ chuyển đổi ReadJson()sử dụng existingValueif được phân bổ trước để hỗ trợ việc điền các thành viên danh sách chỉ nhận.

Thứ hai, đây là một phiên bản hoạt động với các bộ sưu tập chung khác như 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();
        }
    }
}

Sau đó, nếu mô hình của bạn đang sử dụng, chẳng hạn, một ObservableCollection<T>cho một số T, bạn có thể áp dụng nó như sau:

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

Ghi chú:

  • Ngoài các ghi chú và hạn chế SingleOrArrayListConverter, TCollectionkiểu phải được đọc / ghi và có một hàm tạo không tham số.

Demo fiddle với các bài kiểm tra đơn vị cơ bản tại đây .


0

Tôi đã có một vấn đề rất giống nhau. Tôi hoàn toàn không biết Yêu cầu Json của tôi. Tôi chỉ biết.

Sẽ có một objectId trong đó và một số cặp giá trị khóa ẩn danh AND mảng.

Tôi đã sử dụng nó cho Mô hình EAV mà tôi đã làm:

Yêu cầu JSON của tôi:

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

Lớp của tôi mà tôi đã xác định:

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

và bây giờ tôi muốn giải mã các thuộc tính không xác định với giá trị của nó và các mảng trong đó Bộ chuyển đổi của tôi trông như thế này:

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

Vì vậy, bây giờ mỗi khi tôi nhận được AnonymObject, tôi có thể lặp lại từ điển và mỗi khi có Cờ "ValueDummyForEAV" của tôi, tôi sẽ chuyển sang danh sách, đọc dòng đầu tiên và chia nhỏ các giá trị. Sau đó, tôi xóa mục nhập đầu tiên khỏi danh sách và tiếp tục lặp lại từ Từ điển.

Có thể ai đó có cùng một vấn đề và có thể sử dụng cái này :)

Trân trọng Andre


0

Bạn có thể sử dụng một JSONConverterAttributenhư được tìm thấy tại đây: http://james.newtonking.com/projects/json/help/

Giả sử bạn có một lớp học giống như

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

Bạn sẽ trang trí thuộc tính danh mục như đã thấy ở đây:

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

Cảm ơn vì điều này, nhưng nó vẫn không khắc phục được sự cố. Khi một mảng thực sự xuất hiện, nó vẫn phát ra lỗi trước khi mã của tôi thậm chí có thể thực thi cho một đối tượng có một mảng thực tế. 'Thông tin bổ sung: Mã thông báo không mong đợi khi giải mã hóa đối tượng: Chuỗi. Đường dẫn '[2] .category [0]', dòng 17, vị trí 27. '
Robert McLaws

+ "\" sự kiện \ ": \" đã xử lý \ ", \ n" + "} \ n" + "]";
Robert McLaws

Nó xử lý đối tượng đầu tiên tốt và xử lý không có mảng nào đẹp mắt. Nhưng khi tôi tạo một mảng cho đối tượng thứ 2, nó không thành công.
Robert McLaws

@AdvancedREI Nếu không nhìn thấy mã của bạn, tôi có thể đoán rằng bạn đang để trình đọc không đúng vị trí sau khi bạn đọc JSON. Thay vì cố gắng sử dụng trình đọc trực tiếp, tốt hơn là tải một đối tượng JToken từ trình đọc và đi từ đó. Xem câu trả lời của tôi để biết cách triển khai hoạt động của bộ chuyển đổi.
Brian Rogers

Nhiều chi tiết tốt hơn trong câu trả lời của Brian. Sử dụng một :)
Tim Gabrhel

0

Để xử lý điều này, bạn phải sử dụng JsonConverter tùy chỉnh. Nhưng bạn có thể đã nghĩ đến điều đó. Bạn chỉ đang tìm kiếm một công cụ chuyển đổi mà bạn có thể sử dụng ngay lập tức. Và điều này không chỉ là một giải pháp cho tình huống được mô tả. Tôi đưa ra một ví dụ với câu hỏi được hỏi.

Cách sử dụng công cụ chuyển đổi của tôi:

Đặt Thuộc tính JsonConverter phía trên thuộc tính. 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; }
}

Và đây là công cụ chuyển đổi của tôi:

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

Và bộ chuyển đổi này sử dụng lớp sau:

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

Làm gì chính xác? Nếu bạn đặt thuộc tính trình chuyển đổi, trình chuyển đổi sẽ được sử dụng cho thuộc tính này. Bạn có thể sử dụng nó trên một đối tượng bình thường nếu bạn mong đợi một mảng json có 1 hoặc không có kết quả. Hoặc bạn sử dụng nó trên mộtIEnumerable nơi bạn mong đợi một đối tượng json hoặc mảng json. (Biết rằng dấu array- object[]- là một IEnumerable) Điểm bất lợi là bộ chuyển đổi này chỉ có thể được đặt phía trên một thuộc tính vì anh ta nghĩ rằng anh ta có thể chuyển đổi mọi thứ. Và được cảnh báo . A stringcũng là một IEnumerable.

Và nó cung cấp nhiều hơn một câu trả lời cho câu hỏi: Nếu bạn tìm kiếm thứ gì đó theo id, bạn biết rằng bạn sẽ nhận được một mảng trở lại với một hoặc không có kết quả. Các ToObjectCollectionSafe<TResult>()phương pháp có thể xử lý điều đó cho bạn.

Điều này có thể sử dụng được cho Kết quả đơn so với Mảng bằng cách sử dụng JSON.net và xử lý cả một mục và một mảng cho cùng một thuộc tính và có thể chuyển đổi một mảng thành một đối tượng.

Tôi đã thực hiện điều này cho các yêu cầu REST trên máy chủ có bộ lọc trả về một kết quả trong một mảng nhưng muốn lấy lại kết quả dưới dạng một đối tượng trong mã của tôi. Và cũng cho một phản hồi kết quả OData với kết quả mở rộng với một mục trong một mảng.

Hãy vui vẻ với nó.


-2

Tôi đã tìm thấy một giải pháp khác có thể xử lý danh mục dưới dạng chuỗi hoặc mảng bằng cách sử dụng đối tượng. Bằng cách này, tôi không cần phải làm rối tung bộ tuần tự json.

Vui lòng xem lại nếu bạn có thời gian và cho tôi biết suy nghĩ của bạn. https://github.com/MarcelloCarreira/sendgrid-csharp-eventwebhook

Nó dựa trên giải pháp tại https://sendgrid.com/blog/tracking-email-using-azure-sendgrid-event-webhook-part-1/ nhưng tôi cũng đã thêm chuyển đổi ngày từ dấu thời gian, nâng cấp các biến để phản ánh mô hình SendGrid hiện tại (và các danh mục đã hoạt động).

Tôi cũng đã tạo một trình xử lý với tùy chọn xác thực cơ bản. Xem các tệp ashx và các ví dụ.

Cảm ơn bạn!

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.