programing

JSON.net을 사용하여 동일한 속성의 단일 항목과 어레이를 모두 처리하는 방법

madecode 2023. 2. 22. 23:22
반응형

JSON.net을 사용하여 동일한 속성의 단일 항목과 어레이를 모두 처리하는 방법

SendGrid 이벤트를 처리하기 위해 SendGridPlus 라이브러리를 수정하려고 하는데 API에서 카테고리가 일관되지 않아 문제가 있습니다.

SendGrid API 참조에서 가져온 다음 payload 예에서는 다음과 같이 되어 있습니다.category각 항목의 속성은 단일 문자열이거나 문자열 배열일 수 있습니다.

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

JSON을 만드는 게 내 선택인 것 같아.이와 같은 NET은 문자열을 수신하기 전에 수정하거나 JSON을 설정합니다.NET: 잘못된 데이터를 받아들입니다.스트링 파싱은 피할 수 있다면 하고 싶지 않습니다.

Json을 사용하여 이 문제를 해결할 수 있는 다른 방법이 있나요?인터넷?

이 상황에 대처하는 최선의 방법은 커스텀을 사용하는 것입니다.

변환기에 접속하기 전에 데이터를 역직렬화할 클래스를 정의해야 합니다.님의 Categories 사이에 수 으로, 를 일일항항를를를를를를를를를를를를를 라고 정의합니다.List<string> 해서 표시를 해주시면 됩니다.[JsonConverter]아트리뷰트Net은 해당 속성에 대해 사용자 지정 변환기를 사용해야 합니다. 또, 음, 음, 음, 다, 다, 다, 다, 다, 다, i, i, i, i, i, i, i, i, i, i,[JsonProperty]멤버 속성에는 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; }
}

컨버터를 구현하는 방법은 다음과 같습니다.필요에 따라 문자열이나 다른 유형의 개체와 함께 사용할 수 있도록 변환기를 일반으로 만들었습니다.

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

다음은 샘플 데이터와 함께 컨버터의 동작을 보여주는 짧은 프로그램입니다.

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

마지막으로 위의 출력은 다음과 같습니다.

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

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

바이올린: https://dotnetfiddle.net/lERrmu

편집

할 serialize를 할 수 .WriteJson()과 같은).CanWritetrue 그렇지 않으면 " " " "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);
    }

바이올린: https://dotnetfiddle.net/XG3eRy

저는 오랫동안 이 일을 해왔고 브라이언의 답변에 감사드립니다.추가되는 것은 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

그리고 당신의 수업에서:

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

이것으로 시간이 절약되기를 바랍니다.

Brian Rogers의 훌륭한 답변에 대한 작은 변형으로서, 여기 두 가지 수정된 버전이 있습니다.SingleOrArrayConverter<T>.

에서는 모든 , firstly 、 firstly 、 기 、 기 、 firstly 、 firstly 、 firstly 、 firstly 、 firstly 、 。List<T> 타입에 T그 자체는 컬렉션이 아닙니다.

public class SingleOrArrayListConverter : JsonConverter
{
    // Adapted from this answer https://stackoverflow.com/a/18997172
    // to https://stackoverflow.com/questions/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;
    }
}

다음과 같이 사용할 수 있습니다.

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

주의:

  • 값 를 JSON으로 .JToken★★★★★★ 。

  • 이 에는 적용되지 않습니다.를 들어, 「」라고 하는 리스트에는 적용되지 않습니다.List<string []>

  • "canWrite컨스트럭터에 전달되는 인수는 단일 요소 목록을 JSON 값으로 재시리얼화할지 또는 JSON 배열로 재시리얼화할지 제어합니다.

  • 의 ★★★★★★★★★★★★★★★★★」ReadJson()는 을 합니다.existingValue membersget-only의 .get-only의 .

번째, 이 은 다른 과 함께 할 수 입니다.ObservableCollection<T>:

public class SingleOrArrayCollectionConverter<TCollection, TItem> : JsonConverter
    where TCollection : ICollection<TItem>
{
    // Adapted from this answer https://stackoverflow.com/a/18997172
    // to https://stackoverflow.com/questions/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();
        }
    }
}

모델이 그, 델, 델, 델을 사용하고 있다면,ObservableCollection<T>T을 사용하다

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

주의:

  • 의 및 SingleOrArrayListConverter , . . . . . . . .TCollection형식은 읽기/쓰기 형식이어야 하며 매개 변수 없는 생성자가 있어야 합니다.

여기서 기본 장치 테스트를 시연해 보십시오.

이를 처리하려면 커스텀 Json Converter를 사용해야 합니다.하지만 당신은 이미 그것을 염두에 두고 있었을 것이다.바로 사용할 수 있는 컨버터를 찾고 있습니다.이는 단순히 설명되는 상황에 대한 해결책만을 제공하는 것이 아닙니다.질문의 예를 들어 보겠습니다.

컨버터 사용 방법:

Json Converter 속son합 。 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; }
}

그리고 이게 제 변환기입니다.

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

이 변환기는 다음 클래스를 사용합니다.

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

확히히 어떤 할? ???변환기 특성을 배치하면 변환기가 이 속성에 사용됩니다.결과가 1 또는 0인 json 어레이를 예상하는 경우 일반 개체에서 사용할 수 있습니다. ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.IEnumerable배열이 은 json이라는 것을 .)array-object[]- 는 -syslog 입니다IEnumerable단점은 모든 것을 변환할 수 있다고 생각하기 때문에 이 변환기는 속성 위에만 배치할 수 있다는 것입니다.그리고 경고한다.astring또한IEnumerable

또한 다음과 같은 질문에 대한 답변 이상의 것을 제공합니다.ID로 검색하면 결과 하나 또는 아무것도 없는 어레이가 반환된다는 것을 알 수 있습니다.ToObjectCollectionSafe<TResult>()을 사용하다

이는 JSON.net을 사용하는 단일 결과 대 어레이에서 사용할 수 있으며 동일한 속성의 단일 항목과 어레이를 모두 처리할 수 있으며 어레이를 단일 개체로 변환할 수 있습니다.

서버상의 REST 요구에 대해서 작성했습니다만, 필터는 1개의 결과를 어레이로 반환하지만, 그 결과를 코드의 단일 오브젝트로 되돌리고 싶다고 생각하고 있었습니다.또한 ODATA 결과 응답에 대해 하나의 항목을 배열로 확장한 결과를 제공합니다.

그걸로 재미 좀 봐.

SingleOrArrayCollectionConverter에서 위의 @dbc에 우수한 응답을 추가하려고 합니다.HTTP 클라이언트의 스트림에서 사용할 수 있도록 수정할 수 있었습니다.다음은 스니펫입니다(requestUrl(string) 및 httpClient(시스템 사용)를 설정해야 합니다).Net.Http;)

public async Task<IList<T>> HttpRequest<T>(HttpClient httpClient, string requestedUrl, CancellationToken cancellationToken)
    {
       using (var request = new HttpRequestMessage(HttpMethod.Get, requestedUrl))
       using (var httpResponseMessage = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken))
       {
          if (httpResponseMessage.IsSuccessStatusCode)
          {
             using var stream = await httpResponseMessage.Content.ReadAsStreamAsync();    
             using var streamReader = new StreamReader(stream);
             using var jsonTextReader = new JsonTextReader(streamReader );
             var settings = new JsonSerializerSettings
             {
                // Pass true if you want single-item lists to be reserialized as single items
                Converters = { new SingleOrArrayCollectionConverter(true) },
             };
             var jsonSerializer = JsonSerializer.Create(settings);
             return jsonSerializer.Deserialize<List<T>>(jsonTextReader);
     }

괄호나 철자가 틀렸다면 여기에 코드를 붙이기가 쉽지 않아서 죄송합니다.

나도 비슷한 문제가 있었다.나의 Json Request는 나에게 전혀 알려지지 않았다.난 알고 있었어.

objectId와 일부 익명 키 값 쌍 AND 배열이 포함됩니다.

EAV 모델에 사용했습니다.

내 JSON 요청:

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

정의된 My Class i:

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

여기서 알 수 없는 속성과 그 값 및 어레이를 역직렬화하려고 합니다.내 Converter는 다음과 같습니다.

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

따라서 AnonymousObject를 얻을 때마다 사전을 통해 반복할 수 있으며 Flag "ValueDummyForEAV"가 있을 때마다 목록으로 전환하여 첫 번째 줄을 읽고 값을 분할할 수 있습니다.그런 다음 목록에서 첫 번째 항목을 삭제하고 사전에서 반복합니다.

같은 문제를 안고 있는 사람이, 이것을 사용할 수 있을지도 모릅니다.

Andre에 대해서

'어울리다'를 사용할 수 요.JSONConverterAttributehttp://james.newtonking.com/projects/json/help/ 에서 확인하실 수 있습니다.

그런 수업을 듣는다고 가정하면

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

카테고리 속성을 다음과 같이 꾸밀 수 있습니다.

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

커스텀 컨버터는 필요 없습니다.이 경우 보통 매우 단순한 JsonConstructor를 만듭니다.

public partial class Item
{
    // ... all class properties

    [JsonConstructor]
    public Item(JToken category)
    {
        if (category.GetType().Name == "JArray")
            Category = category.ToObject<List<string>>();
        else
            Category = new List<string> { category.ToString() };
    }
    public Item() { }
}

이 후 공통 코드를 사용하여 json을 역직렬화할 수 있습니다.

List<Item> items = JsonConvert.DeserializeObject<List<Item>>(json);

오브젝트를 사용하여 카테고리를 문자열 또는 배열로 처리할 수 있는 다른 솔루션을 찾았습니다.이렇게 하면 json 시리얼라이저를 망가뜨릴 필요가 없어.

시간이 되시면 한번 보시고 어떻게 생각하시는지요.https://github.com/MarcelloCarreira/sendgrid-csharp-eventwebhook

https://sendgrid.com/blog/tracking-email-using-azure-sendgrid-event-webhook-part-1/의 솔루션을 기반으로 하지만 타임스탬프에서 날짜 변환을 추가하고 현재 SendGrid 모델을 반영하도록 변수를 업그레이드했습니다(카테고리가 작동하도록 했습니다).

또, basic auth as 옵션을 가지는 핸들러를 작성했습니다.ashx 파일과 예를 참조하십시오.

감사해요!

언급URL : https://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n

반응형