JSON.net ব্যবহার করে একই সম্পত্তির জন্য কীভাবে একটি একক আইটেম এবং একটি অ্যারে উভয় পরিচালনা করবেন


108

আমি সেন্ডগ্রিড ইভেন্টগুলি মোকাবেলায় আমার সেন্ডগ্রিডপ্লাস লাইব্রেরিটি ঠিক করার চেষ্টা করছি, তবে এপিআই-এর বিভাগগুলির অসঙ্গত চিকিত্সা নিয়ে আমার কিছুটা সমস্যা হচ্ছে।

সেন্ডগ্রিড এপিআই রেফারেন্স থেকে নেওয়া নীচের উদাহরণে পেলোডে , আপনি লক্ষ্য করবেন যে 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 কনফিগার করছে। আমি যদি কোনও স্ট্রিং পার্সিং না করি তবে আমি এটির সাথে দূরে সরে যেতে পারি।

আমি জসন.নেট ব্যবহার করে এটি পরিচালনা করতে অন্য কোনও উপায় আছে?

উত্তর:


211

এই পরিস্থিতিটি পরিচালনা করার সর্বোত্তম উপায় হ'ল একটি কাস্টম ব্যবহার করা JsonConverter

আমরা কনভার্টারে পৌঁছানোর আগে আমাদের ডেটাটি ডিসেরায়ালাইজ করার জন্য একটি শ্রেণি সংজ্ঞায়িত করতে হবে। জন্য Categoriesসম্পত্তি একটি একক আইটেম এবং একটি অ্যারের মধ্যে বিভিন্ন রকমের হতে পারে, একটি যেমন সংজ্ঞায়িত 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ওভাররাইডটি সরিয়ে ফেলার বিষয়ে নিশ্চিত হন বা এটিকে ফিরে আসার জন্য পরিবর্তন করুন 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


4
পারফেক্ট! তুমি সেই লোক. সৌভাগ্যক্রমে, সম্পত্তিগুলি আরও অর্থবহ করে তুলতে আমি জেসনপ্রপার্টি ব্যবহার সম্পর্কে অন্যান্য জিনিসগুলি ইতিমধ্যে করেছি। একটি আশ্চর্যজনক সম্পূর্ণ উত্তরের জন্য আপনাকে ধন্যবাদ। :)
রবার্ট ম্যাকলাউস

সমস্যা নেই; ভাল লাগছে আপনি এটি সহায়ক বলে চিহ্নিত করেছেন.
ব্রায়ান রজারস

4
দুর্দান্ত! Ive এটি খুঁজছিল। @ ব্রায়ানরোজার্স, আপনি যদি কখনও আমস্টারডামে থাকেন তবে আমার কাছে পানীয় রয়েছে!
পাগল কুকুর তন্নেন

4
@ ইস্রায়েললতার উপরের উত্তরে বর্ণিত হিসাবে আপনার ক্লাসের তালিকার সম্পত্তিটিতে DeserializeObjectযদি আপনি [JsonConverter]বৈশিষ্ট্যটি ব্যবহার করেন তবে আপনাকে কলটিতে রূপান্তরকারী যুক্ত করার দরকার নেই । আপনি যদি বৈশিষ্ট্যটি ব্যবহার না করেন তবে হ্যাঁ, আপনাকে রূপান্তরটি পাস করতে হবে DeserializeObject
ব্রায়ান রজার্স

4
@ শাঁনল্যাংলে রূপান্তরকারীকে তালিকার পরিবর্তে একটি অ্যারের ব্যবহার করতে, সমস্ত উল্লেখকে List<T>রূপান্তরকারীতে পরিবর্তিত করুন T[]এবং এতে পরিবর্তন .Countকরুন .Lengthdotnetfiddle.net/vnCNgZ
ব্রায়ান রজার্স

7

আমি যুগে যুগে এটি নিয়ে কাজ করছিলাম, এবং তার উত্তরটির জন্য ব্রায়ানকে ধন্যবাদ জানাই। আমি যুক্ত করছি সবই 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)

আশা করি এটি আপনার কিছুটা সময় সাশ্রয় করবে


প্রকারভেদসমূহ: <জসনকনভার্টার (গেটটাইপ (এককভ্যালিউআরাই কনভার্টার (আপনার অফজেক্ট)))> _ সর্বজনীন সম্পত্তি আপনার লোকাল নাম হিসাবে তালিকা (আপনার অফজেক্ট)
গ্লেনজি

3

করার জন্য একটি ছোটখাট প্রকরণ হিসেবে মহান উত্তর দ্বারা ব্রায়ান রজার্স , এখানে দুটি tweaked, সংস্করণ 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);

মন্তব্য:

  • রূপান্তরকারী JTokenশ্রেণিবদ্ধ হিসাবে মেমরিতে পুরো JSON মানটি পূর্ব-লোড করার প্রয়োজনীয়তা এড়িয়ে চলে ।

  • রূপান্তরকারীগুলির তালিকাগুলিতে প্রয়োগ হয় না যার আইটেমগুলি সংগ্রহ হিসাবে সিরিয়ালযুক্তও করা হয়, যেমন List<string []>

  • বুলিয়ান canWriteআর্গুমেন্টটি কনস্ট্রাক্টরকে দেওয়া হয়েছে যে সিঙ্গল-এলিমেন্ট তালিকাগুলি পুনরায় সিরিয়ালাইজ করতে হবে কিনা JSON মান হিসাবে বা JSON অ্যারে হিসাবে controls

  • কনভার্টার এর 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; }
}

মন্তব্য:

  • এর জন্য নোট এবং বিধিনিষেধের পাশাপাশি SingleOrArrayListConverter, TCollectionটাইপটি অবশ্যই পড়তে / লিখতে হবে এবং একটি প্যারামিটারলেস কনস্ট্রাক্টর থাকতে হবে।

এখানে বেসিক ইউনিট পরীক্ষার সাথে ডেমো ভাজা ।


0

আমার খুব অনুরূপ সমস্যা ছিল। আমার জেসন অনুরোধটি আমার পক্ষে সম্পূর্ণ অজানা ছিল। আমি শুধু জানতাম।

এটিতে একটি অবজেক্টআইডি এবং কিছু বেনামি মূল্যের মান এবং অ্যারে থাকবে।

আমি এটি একটি EAV মডেলের জন্য ব্যবহার করেছি:

আমার JSON অনুরোধ:

{অবজেক্টআইডি ": 2," প্রথম নাম ":" হান্স "," ইমেল ": [" a@b.de "," a@c.de "]," নাম ":" আন্দ্রে "," কিছু ": [" 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;
    }

সুতরাং এখনই আমি যখনই কোনও অ্যানোনিমজ অবজেক্ট পাই আমি অভিধানের মাধ্যমে পুনরাবৃত্তি করতে পারি এবং আমার ফ্ল্যাগ "ValueDummyforEAV" থাকে আমি তালিকায় স্যুইচ করি, প্রথম লাইনটি পড়ি এবং মানগুলি বিভক্ত করি। এর পরে আমি তালিকা থেকে প্রথম এন্ট্রি মুছি এবং অভিধান থেকে পুনরাবৃত্তি নিয়ে যাই।

কারওরও একই সমস্যা রয়েছে এবং এটি ব্যবহার করতে পারেন :)

শুভেচ্ছা আন্দ্রে


0

আপনি JSONConverterAttributeএখানে পাওয়া হিসাবে ব্যবহার করতে পারেন : http://james.newtonking.com / প্রকল্পগুলি / 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] .শ্রেণী [0]', লাইন 17, অবস্থান 27. '
রবার্ট ম্যাকলাউস

+ "\" ইভেন্ট \ ": \" প্রক্রিয়াজাত \ ", \ n" + "} \ n" + "]";
রবার্ট ম্যাকলাউস

এটি প্রথম অবজেক্টটি সূক্ষ্মভাবে প্রক্রিয়াজাত করে এবং কোনও অ্যারের সাথে সুন্দরভাবে আচরণ করে না। তবে আমি যখন ২ য় অবজেক্টের জন্য একটি অ্যারে তৈরি করেছি, এটি ব্যর্থ হয়েছিল।
রবার্ট ম্যাকলাউস

@ অ্যাডভান্সড্রেআই আপনার কোডটি না দেখে আমি অনুমান করব যে আপনি জেএসওএন পড়ার পরে আপনি পাঠককে ভুলভাবে অবস্থান করছেন। পাঠককে সরাসরি ব্যবহার করার চেষ্টা করার পরিবর্তে, জে টোকেন অবজেক্টটি পাঠকের কাছ থেকে লোড করা এবং সেখান থেকে যাওয়া ভাল। রূপান্তরকারী কার্যকরভাবে প্রয়োগের জন্য আমার উত্তর দেখুন।
ব্রায়ান রজার্স

ব্রায়ানের উত্তরে আরও অনেক ভাল বিশদ। এটি ব্যবহার করুন :)
টিম গ্যাবারেল

0

এটি পরিচালনা করতে আপনাকে একটি কাস্টম জসনকনভার্টার ব্যবহার করতে হবে। তবে আপনার মনে সম্ভবত এটি ইতিমধ্যে ছিল। আপনি কেবল এমন রূপান্তরকারীর সন্ধান করছেন যা আপনি অবিলম্বে ব্যবহার করতে পারেন। এবং এটি বর্ণিত পরিস্থিতির সমাধানের চেয়ে আরও বেশি প্রস্তাব দেয় offers জিজ্ঞাসিত প্রশ্ন সহ আমি একটি উদাহরণ দিই।

আমার কনভার্টারটি কীভাবে ব্যবহার করবেন:

সম্পত্তির উপরে একটি জসন কনভার্টার বৈশিষ্ট্য রাখুন। 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 বা কোনও ফলাফল না দিয়ে কোনও জসন অ্যারে আশা করেন তবে আপনি এটি কোনও সাধারণ অবজেক্টে ব্যবহার করতে পারেন। অথবা আপনি এটি কোনও এমন IEnumerableজায়গায় ব্যবহার করেন যেখানে আপনি কোনও জসন অবজেক্ট বা জসন অ্যারে আশা করেন। (জেনে রাখুন যে array- object[]- এবং এ IEnumerable) একটি অসুবিধা হ'ল এই রূপান্তরকারীকে কেবল কোনও সম্পত্তির উপরে স্থাপন করা যেতে পারে কারণ তিনি মনে করেন যে তিনি সবকিছু রূপান্তর করতে পারেন। এবং সতর্ক করা হবে । একজন stringএছাড়াও একটি হল IEnumerable

এবং এটি প্রশ্নের উত্তরের চেয়ে আরও বেশি প্রস্তাব দেয়: আপনি যদি আইডি দ্বারা কোনও কিছু অনুসন্ধান করেন তবে আপনি জানেন যে আপনি কোনও বা কোনও ফলাফল ছাড়াই একটি অ্যারে ফিরে পাবেন। ToObjectCollectionSafe<TResult>()পদ্ধতি আপনার জন্য যে সব ব্যবস্থা করতে সক্ষম।

এটি JSON.net ব্যবহার করে একক ফলাফল বনাম অ্যারের জন্য ব্যবহারযোগ্য এবং একই সম্পত্তির জন্য একটি একক আইটেম এবং অ্যারে উভয়ই হ্যান্ডেল করে এবং একটি অ্যারেকে একক বস্তুতে রূপান্তর করতে পারে।

আমি ফিল্টার সহ একটি সার্ভারে এটি আরএসটি অনুরোধের জন্য তৈরি করেছিলাম যা একটি ফলাফলের অ্যারেতে ফিরে আসে তবে আমার কোডে একক অবজেক্ট হিসাবে ফলাফলটি ফিরে পেতে চেয়েছিল। এবং একটি অ্যারেতে একটি আইটেম সহ প্রসারিত ফলাফল সহ ওডাটা ফলাফল প্রতিক্রিয়ার জন্যও।

এটি সঙ্গে মজা আছে।


-2

আমি অন্য একটি সমাধান পেয়েছি যা অবজেক্টটি ব্যবহার করে স্ট্রিং বা অ্যারে হিসাবে বিভাগটি পরিচালনা করতে পারে। এইভাবে জসন সিরিয়ালাইজারটির সাথে আমার গণ্ডগোলের দরকার নেই।

আপনার কাছে সময় থাকলে তা একবার দেখুন এবং আপনি কী ভাবছেন তা বলুন। https://github.com/MarcelloCarreira/sendgrid-csharp-eventwebhook

এটি https://sendgrid.com/blog/tracking-email-using-azure-sendgrid-event-webhook-part-1/ এ সমাধানের উপর ভিত্তি করেই আমি টাইমস্ট্যাম্প থেকে তারিখ রূপান্তরও যুক্ত করেছি, পরিবর্তনগুলি প্রতিফলিত করার জন্য আপগ্রেড করেছি বর্তমান সেন্ডগ্রিড মডেল (এবং বিভাগগুলিতে কাজ করা হয়)।

আমি বিকল্প হিসাবে বেসিক লেখার সাথে একটি হ্যান্ডলারও তৈরি করেছি। অ্যাশএক্স ফাইল এবং উদাহরণগুলি দেখুন।

ধন্যবাদ!

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.