JSON.net을 사용하여 동일한 속성에 대해 단일 항목과 배열을 모두 처리하는 방법


101

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

SendGrid API 참조 에서 가져온 다음 예제 페이로드에서 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.Net을 사용하여 이것을 처리 할 수있는 다른 방법이 있습니까?

답변:


203

이 상황을 처리하는 가장 좋은 방법은 사용자 지정 JsonConverter.

변환기에 도달하기 전에 데이터를 역 직렬화 할 클래스를 정의해야합니다. Categories단일 항목과 배열간에 다를 수 있는 속성의 경우 속성을 a로 정의 List<string>하고 [JsonConverter]속성으로 표시하여 JSON.Net이 해당 속성에 대한 사용자 지정 변환기를 사용하도록 알립니다. 또한 [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

편집하다

동일한 형식을 유지하면서 직렬화와 같은 다른 방법으로 이동해야하는 경우 WriteJson()아래와 같이 변환기 의 메서드를 구현할 수 있습니다. ( CanWrite재정의 를 제거 하거나 return으로 변경해야합니다 . true그렇지 않으면 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


5
완전한! 당신은 남자입니다. 다행히도 JsonProperty를 사용하여 속성을보다 의미있게 만드는 다른 모든 작업을 이미 수행했습니다. 놀랍도록 완전한 답변에 감사드립니다. :)
Robert McLaws 2013 년

문제 없어요; 도움이 되셨 다니 다행입니다.
Brian Rogers

1
우수한! 이것이 바로 ive가 찾고 있던 것입니다. @BrianRogers, 당신이 암스테르담에 있다면, 음료수는 나에게 있습니다!
Mad Dog Tannen 2015

2
@israelaltar 위의 답변과 같이 클래스의 목록 속성에 속성을 DeserializeObject사용하는 경우 변환기를 호출 에 추가 할 필요가 없습니다 [JsonConverter]. 속성을 사용 하지 않는 경우 예, 변환기를 DeserializeObject.
Brian Rogers

1
@ShaunLangley 변환기가 목록 대신 배열을 사용하도록하려면 변환기의 모든 참조를 List<T>T[]변경 .Count하고 .Length. dotnetfiddle.net/vnCNgZ
Brian Rogers

6

나는 오랫동안 이것을 작업하고 있었고 그의 대답에 대해 Brian에게 감사드립니다. 내가 추가하는 것은 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)

이것이 시간을 절약하기를 바랍니다.


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

3

Brian Rogers훌륭한 답변 에 대한 사소한 변형으로 , 여기에 .SingleOrArrayConverter<T>

첫째, 그 자체가 컬렉션이 아닌 List<T>모든 유형에 대해 작동하는 버전이 T있습니다.

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

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

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.

둘째, 다음과 같은 다른 일반 컬렉션과 함께 작동하는 버전이 있습니다 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();
        }
    }
}

그런 다음 모델이를 사용하는 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; }
}

노트:

  • 노트와에 대한 제한 이외에 SingleOrArrayListConverterTCollection유형은 읽기 / 쓰기 및 매개 변수없는 생성자가 있어야합니다.

여기에 기본 단위 테스트를 포함한 데모 바이올린이 있습니다 .


0

나는 매우 유사한 문제가 있었다. 내 Json 요청은 완전히 알려지지 않았습니다. 나는 알 뿐이었다.

여기에는 objectId가 있고 일부 익명 키 값 쌍과 배열이 있습니다.

내가 한 EAV 모델에 사용했습니다.

내 JSON 요청 :

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

내 클래스 정의 :

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

이제 그 값과 배열을 사용하여 알 수없는 속성을 역 직렬화하고 싶습니다. 변환기는 다음과 같습니다.

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

이제 AnonymObject를 얻을 때마다 사전을 반복 할 수 있고 "ValueDummyForEAV"플래그가있을 때마다 목록으로 전환하고 첫 번째 줄을 읽고 값을 분할합니다. 그 후 목록에서 첫 번째 항목을 삭제하고 사전에서 반복을 계속합니다.

어쩌면 누군가가 같은 문제를 가지고 있으며 이것을 사용할 수 있습니다 :)

안드레 안드레


0

당신은 사용할 수 있습니다 JSONConverterAttribute: 여기로 http://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();
  }
}

감사합니다.하지만 여전히 문제가 해결되지는 않습니다. 실제 배열이 들어 오면 내 코드가 실제 배열이있는 객체에 대해 실행되기 전에 여전히 오류가 발생합니다. '추가 정보 : 개체 역 직렬화시 예기치 않은 토큰 : 문자열. 경로 '[2] .category [0]', 17 행, 위치 27. '
로버트 맥 로우

+ "\"이벤트 \ ": \"처리됨 \ ", \ n"+ "} \ n"+ "]";
로버트 맥 로우

첫 번째 개체를 잘 처리하고 배열없이 아름답게 처리했습니다. 그러나 두 번째 개체에 대한 배열을 만들 때 실패했습니다.
로버트 맥 로우

@AdvancedREI 코드를 보지 않고는 JSON을 읽은 후 판독기를 잘못 배치하고 있다고 생각합니다. 판독기를 직접 사용하는 대신 판독기에서 JToken 객체를로드하고 거기에서 이동하는 것이 좋습니다. 변환기의 작동 구현에 대한 내 대답을 참조하십시오.
Brian Rogers

Brian의 답변에서 훨씬 더 자세히 설명합니다. 사용 :)
Tim Gabrhel 2013-09-25

0

이를 처리하려면 사용자 지정 JsonConverter를 사용해야합니다. 하지만 이미 염두에 두셨을 것입니다. 즉시 사용할 수있는 변환기를 찾고 있습니다. 그리고 이것은 설명 된 상황에 대한 해결책 이상의 것을 제공합니다. 나는 질문에 대한 예를 제공합니다.

내 변환기 사용 방법 :

속성 위에 JsonConverter 속성을 배치합니다. 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이거나없는 json 배열을 예상하는 경우 일반 객체에서 사용할 수 있습니다. 또는 IEnumerablejson 객체 또는 json 배열이 필요한 곳에서 사용합니다 . (알고는 것을 array- object[]-입니다 IEnumerable단점은 그가 모든 것을 변환 할 수 있습니다 생각하기 때문에이 변환기는 속성 위에 배치 할 수 있다는 것입니다). 그리고 경고하십시오 . A string는 또한 IEnumerable.

그리고 그것은 질문에 대한 답 이상의 것을 제공합니다 : 만약 당신이 id로 무언가를 검색한다면, 당신은 하나의 결과와 함께 배열을 얻을 것이라는 것을 알고 있습니다. 이 ToObjectCollectionSafe<TResult>()방법은 당신을 위해 그것을 처리 할 수 ​​있습니다.

이것은 JSON.net을 사용하는 단일 결과 대 배열에 사용할 수 있으며 동일한 속성에 대한 단일 항목과 배열을 모두 처리하고 배열을 단일 객체로 변환 할 수 있습니다.

하나의 결과를 배열로 반환하는 필터를 사용하여 서버의 REST 요청에 대해 이것을 만들었지 만 결과를 내 코드에서 단일 객체로 되돌리고 싶었습니다. 또한 배열에 하나의 항목이있는 확장 된 결과가있는 OData 결과 응답의 경우도 있습니다.

재미있게 보내십시오.


-2

개체를 사용하여 범주를 문자열 또는 배열로 처리 할 수있는 또 다른 솔루션을 찾았습니다. 이렇게하면 json serializer를 엉망으로 만들 필요가 없습니다.

시간이 있으시면 한번 보시고 어떻게 생각 하시는지 말씀 해주세요. https://github.com/MarcelloCarreira/sendgrid-csharp-eventwebhook

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

또한 기본 인증을 옵션으로 사용하여 처리기를 만들었습니다. ashx 파일 및 예제를 참조하십시오.

감사합니다!

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.