JSON.NET ব্যবহার করে সিরিয়ালযুক্ত JSON অবজেক্টে ক্ষেত্রগুলির ক্রম নির্দিষ্ট করার কোনও উপায় আছে কি ?
একটি একক ক্ষেত্র সর্বদা প্রথম প্রদর্শিত হবে তা নির্দিষ্ট করে বলা যথেষ্ট হবে।
JSON.NET ব্যবহার করে সিরিয়ালযুক্ত JSON অবজেক্টে ক্ষেত্রগুলির ক্রম নির্দিষ্ট করার কোনও উপায় আছে কি ?
একটি একক ক্ষেত্র সর্বদা প্রথম প্রদর্শিত হবে তা নির্দিষ্ট করে বলা যথেষ্ট হবে।
উত্তর:
সমর্থিত উপায় হ'ল JsonProperty
শ্রেণীর বৈশিষ্ট্যগুলিতে যে বৈশিষ্ট্যটির জন্য আপনি অর্ডার সেট করতে চান তাতে বৈশিষ্ট্যটি ব্যবহার করা। আরও তথ্যের জন্য JsonPropertyAtribute অর্ডার ডকুমেন্টেশন পড়ুন ।
JsonProperty
একটি Order
মান পাস করুন এবং সিরিয়ালাইজারটি বাকীটির যত্ন নেবে।
[JsonProperty(Order = 1)]
এটি খুব অনুরূপ
DataMember(Order = 1)
এর System.Runtime.Serialization
দিন।
@ কেভিন-বাবককের একটি গুরুত্বপূর্ণ নোট এখানে
... 1 এ অর্ডার সেট করা কেবল তখনই কাজ করবে যদি আপনি অন্য সমস্ত বৈশিষ্ট্যে 1 এর চেয়ে বড় অর্ডার সেট করেন। ডিফল্টরূপে অর্ডার সেটিং ব্যতীত যে কোনও সম্পত্তি -1 এর অর্ডার দেওয়া হবে। সুতরাং আপনাকে অবশ্যই সমস্ত ক্রমিক বৈশিষ্ট্য এবং আদেশ দিতে হবে, বা আপনার প্রথম আইটেমটি -2 এ সেট করতে হবে
Order
সম্পত্তি ব্যবহার করে JsonPropertyAttribute
ক্ষেত্রগুলিকে ক্রমযুক্ত / ডিসরিয়ালাইজ করা ক্রম নিয়ন্ত্রণ করতে ব্যবহার করা যেতে পারে। তবে, 1 এ অর্ডার সেট করা কেবল তখনই কাজ করবে যদি আপনি অন্য সমস্ত বৈশিষ্ট্যে 1 এর চেয়ে বড় অর্ডার সেট করেন। ডিফল্টরূপে অর্ডার সেটিং ব্যতীত যে কোনও সম্পত্তি -1 এর অর্ডার দেওয়া হবে। সুতরাং আপনাকে অবশ্যই সমস্ত ক্রমিক বৈশিষ্ট্য এবং আদেশ দিতে হবে, বা আপনার প্রথম আইটেমটি -2 এ সেট করতে হবে।
JavaScriptSerializer
।
আপনি আসলে এর পদ্ধতি প্রয়োগ IContractResolver
বা ওভাররাইড করে অর্ডারটি নিয়ন্ত্রণ করতে পারেন ।DefaultContractResolver
CreateProperties
এখানে আমার সরল বাস্তবায়নের একটি উদাহরণ IContractResolver
যা বৈশিষ্ট্যগুলিকে বর্ণানুক্রমিক অর্ডার দেয়:
public class OrderedContractResolver : DefaultContractResolver
{
protected override System.Collections.Generic.IList<JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization)
{
return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList();
}
}
এবং তারপরে সেটিংসটি সেট করুন এবং অবজেক্টটিকে সিরিয়ালাইজ করুন এবং জেএসএন ক্ষেত্রগুলি বর্ণানুক্রমিক ক্রমে থাকবে:
var settings = new JsonSerializerSettings()
{
ContractResolver = new OrderedContractResolver()
};
var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
আমার ক্ষেত্রে ম্যাটিয়াসের উত্তর কার্যকর হয়নি। CreateProperties
পদ্ধতি কখনোই ডাকা হয়।
Newtonsoft.Json
ইন্টার্নালদের কিছু ডিবাগিংয়ের পরে , আমি আরও একটি সমাধান নিয়ে এসেছি।
public class JsonUtility
{
public static string NormalizeJsonString(string json)
{
// Parse json string into JObject.
var parsedObject = JObject.Parse(json);
// Sort properties of JObject.
var normalizedObject = SortPropertiesAlphabetically(parsedObject);
// Serialize JObject .
return JsonConvert.SerializeObject(normalizedObject);
}
private static JObject SortPropertiesAlphabetically(JObject original)
{
var result = new JObject();
foreach (var property in original.Properties().ToList().OrderBy(p => p.Name))
{
var value = property.Value as JObject;
if (value != null)
{
value = SortPropertiesAlphabetically(value);
result.Add(property.Name, value);
}
else
{
result.Add(property.Name, property.Value);
}
}
return result;
}
}
আমার ক্ষেত্রে নিয়াহের সমাধান কাজ করে না কারণ এটি অ্যারেগুলিতে হ্যান্ডেল করে না।
তার সমাধানের ভিত্তিতে এটিই আমি নিয়ে এসেছি
public static class JsonUtility
{
public static string NormalizeJsonString(string json)
{
JToken parsed = JToken.Parse(json);
JToken normalized = NormalizeToken(parsed);
return JsonConvert.SerializeObject(normalized);
}
private static JToken NormalizeToken(JToken token)
{
JObject o;
JArray array;
if ((o = token as JObject) != null)
{
List<JProperty> orderedProperties = new List<JProperty>(o.Properties());
orderedProperties.Sort(delegate(JProperty x, JProperty y) { return x.Name.CompareTo(y.Name); });
JObject normalized = new JObject();
foreach (JProperty property in orderedProperties)
{
normalized.Add(property.Name, NormalizeToken(property.Value));
}
return normalized;
}
else if ((array = token as JArray) != null)
{
for (int i = 0; i < array.Count; i++)
{
array[i] = NormalizeToken(array[i]);
}
return array;
}
else
{
return token;
}
}
}
চার্লি উল্লিখিত হিসাবে, আপনি কিছুটা শ্রেণিতে থাকা বৈশিষ্ট্যগুলি অর্ডার করে জেএসএন বৈশিষ্ট্যগুলির ক্রম কিছুটা নিয়ন্ত্রণ করতে পারেন। দুর্ভাগ্যক্রমে, এই পদ্ধতিটি বেস শ্রেণীর উত্তরাধিকার সূত্রে প্রাপ্ত সম্পত্তিগুলির জন্য কাজ করে না। বেস শ্রেণীর বৈশিষ্ট্যগুলি কোডে বিভক্ত হওয়ার সাথে সাথে অর্ডার করা হবে তবে বেস শ্রেণীর বৈশিষ্ট্যগুলির সামনে উপস্থিত হবে।
এবং যে কারও জন্য আপনি কেন JSON বৈশিষ্ট্যগুলিকে বর্ণমালা করতে চান তা ভাবতে, কাঁচা JSON ফাইলগুলির সাথে কাজ করা পুরোপুরি সহজ, বিশেষত প্রচুর সংখ্যার সম্পত্তি সহ শ্রেণীর ক্ষেত্রে, যদি তাদের আদেশ দেওয়া হয়।
এটি সাধারণ ক্লাস, অভিধান এবং এক্সপেন্ডোঅবজেক্ট (ডায়নামিক অবজেক্ট) এর জন্যও কাজ করবে।
class OrderedPropertiesContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization)
{
var props = base.CreateProperties(type, memberSerialization);
return props.OrderBy(p => p.PropertyName).ToList();
}
}
class OrderedExpandoPropertiesConverter : ExpandoObjectConverter
{
public override bool CanWrite
{
get { return true; }
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var expando = (IDictionary<string, object>)value;
var orderedDictionary = expando.OrderBy(x => x.Key).ToDictionary(t => t.Key, t => t.Value);
serializer.Serialize(writer, orderedDictionary);
}
}
var settings = new JsonSerializerSettings
{
ContractResolver = new OrderedPropertiesContractResolver(),
Converters = { new OrderedExpandoPropertiesConverter() }
};
var serializedString = JsonConvert.SerializeObject(obj, settings);
CreateProperties
অভিধানের ক্রমিককরণের সময় অনুরোধ করা হয় না। ডিকশনারি এন্ট্রিগুলির মাধ্যমে যন্ত্রপাতি আসলে কী খনন করছে তার জন্য আমি JSON.net রেপো অন্বেষণ করেছি। override
অর্ডার দেওয়ার জন্য এটি কোনও বা অন্য কোনও কাস্টমাইজেশনের মধ্যে পড়ে না । এটি কেবলমাত্র বস্তুর গণকের দ্বারা প্রবেশিকাগুলিকে গ্রহণ করে। দেখে মনে হচ্ছে এটির জন্য আমাকে একটি নির্মাণ করতে SortedDictionary
বা SortedList
জেএসওএন.এন.টাকে বাধ্য করতে হবে। বৈশিষ্ট্য সংক্রান্ত পরামর্শ দাখিল করা হয়েছে: github.com/JamesNK/Newtonsoft.Json/issues/2270
আপনি যদি JsonProperty
Order
প্রতিটি শ্রেণীর সম্পত্তিতে কোনও বৈশিষ্ট্য রাখতে চান না , তবে আপনার নিজের কন্ট্রাক্টস রিসলভারটি করা খুব সহজ ...
আইসিএনট্র্যাকটরসোলভার ইন্টারফেসটি কীভাবে কাস্টমাইজ করার একটি উপায় সরবরাহ করে যে কীভাবে জসনসিরাইজারাইজাল আপনার ডিগ্রিবিহীন বৈশিষ্ট্যগুলি না রেখে JSON এ নেট।
এটার মত:
private class SortedPropertiesContractResolver : DefaultContractResolver
{
// use a static instance for optimal performance
static SortedPropertiesContractResolver instance;
static SortedPropertiesContractResolver() { instance = new SortedPropertiesContractResolver(); }
public static SortedPropertiesContractResolver Instance { get { return instance; } }
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var properties = base.CreateProperties(type, memberSerialization);
if (properties != null)
return properties.OrderBy(p => p.UnderlyingName).ToList();
return properties;
}
}
বাস্তবায়ন:
var settings = new JsonSerializerSettings { ContractResolver = SortedPropertiesContractResolver.Instance };
var json = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
নিম্নলিখিত পুনরাবৃত্তির পদ্ধতিটি JObject
ব্র্যান্ডের নতুন সাজানো অবজেক্ট গ্রাফ তৈরির পরিবর্তে একটি বিদ্যমান উদাহরণে অভ্যন্তরীণ টোকেন তালিকাকে সাজানোর জন্য প্রতিচ্ছবি ব্যবহার করে । এই কোডটি অভ্যন্তরীণ জসন.এনইটি বাস্তবায়নের বিশদগুলির উপর নির্ভর করে এবং উত্পাদনে ব্যবহার করা উচিত নয়।
void SortProperties(JToken token)
{
var obj = token as JObject;
if (obj != null)
{
var props = typeof (JObject)
.GetField("_properties",
BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(obj);
var items = typeof (Collection<JToken>)
.GetField("items", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(props);
ArrayList.Adapter((IList) items)
.Sort(new ComparisonComparer(
(x, y) =>
{
var xProp = x as JProperty;
var yProp = y as JProperty;
return xProp != null && yProp != null
? string.Compare(xProp.Name, yProp.Name)
: 0;
}));
}
foreach (var child in token.Children())
{
SortProperties(child);
}
}
আসলে, যেহেতু আমার অবজেক্টটি ইতিমধ্যে একটি জবজেক্ট ছিল, তাই আমি নিম্নলিখিত সমাধানটি ব্যবহার করেছি:
public class SortedJObject : JObject
{
public SortedJObject(JObject other)
{
var pairs = new List<KeyValuePair<string, JToken>>();
foreach (var pair in other)
{
pairs.Add(pair);
}
pairs.OrderBy(p => p.Key).ForEach(pair => this[pair.Key] = pair.Value);
}
}
এবং তারপরে এটি ব্যবহার করুন:
string serializedObj = JsonConvert.SerializeObject(new SortedJObject(dataObject));
আপনি যদি ক্লাস নিয়ন্ত্রণ করেন (অর্থাত্ লিখুন), বৈশিষ্ট্যগুলি বর্ণানুক্রমিক ক্রমে রাখুন এবং যখন JsonConvert.SerializeObject()
ডাকা হবে তখন তারা বর্ণানুক্রমিক ক্রমে সিরিয়ালাইজ হবে ।
আমি একটি কমব্লেক্স অবজেক্টটি সিরিয়ালাইজ করতে এবং কোডগুলিতে সংজ্ঞায়িত হিসাবে বৈশিষ্ট্যগুলির ক্রম রাখতে চাই। আমি কেবল যুক্ত করতে পারি না [JsonProperty(Order = 1)]
কারণ ক্লাস নিজেই আমার সুযোগের বাইরে।
এই সমাধানটি বিবেচনায় রাখে যে বেস শ্রেণিতে সংজ্ঞাযুক্ত বৈশিষ্ট্যগুলির উচ্চতর অগ্রাধিকার থাকা উচিত।
এটি বুলেটপ্রুফ নাও হতে পারে, যেহেতু কোথাও সংজ্ঞায়িত করা হয়নি যে MetaDataAttribute
সঠিক ক্রমটি নিশ্চিত করে তবে এটি কাজ করে বলে মনে হয়। আমার ব্যবহারের ক্ষেত্রে এটি ঠিক আছে। যেহেতু আমি কেবল একটি স্বয়ংক্রিয় উত্পন্ন কনফিগার ফাইলের জন্য মানুষের পঠনযোগ্যতা বজায় রাখতে চাই।
public class PersonWithAge : Person
{
public int Age { get; set; }
}
public class Person
{
public string Name { get; set; }
}
public string GetJson()
{
var thequeen = new PersonWithAge { Name = "Elisabeth", Age = Int32.MaxValue };
var settings = new JsonSerializerSettings()
{
ContractResolver = new MetadataTokenContractResolver(),
};
return JsonConvert.SerializeObject(
thequeen, Newtonsoft.Json.Formatting.Indented, settings
);
}
public class MetadataTokenContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(
Type type, MemberSerialization memberSerialization)
{
var props = type
.GetProperties(BindingFlags.Instance
| BindingFlags.Public
| BindingFlags.NonPublic
).ToDictionary(k => k.Name, v =>
{
// first value: declaring type
var classIndex = 0;
var t = type;
while (t != v.DeclaringType)
{
classIndex++;
t = type.BaseType;
}
return Tuple.Create(classIndex, v.MetadataToken);
});
return base.CreateProperties(type, memberSerialization)
.OrderByDescending(p => props[p.PropertyName].Item1)
.ThenBy(p => props[p.PropertyName].Item1)
.ToList();
}
}
যদি আপনি বিশ্বব্যাপী আদেশপ্রাপ্ত ক্ষেত্রগুলি সহ আপনার এপিআই কনফিগার করতে চান তবে দয়া করে ম্যাটিয়াস নর্ডবার্গের উত্তরটি একত্রিত করুন:
public class OrderedContractResolver : DefaultContractResolver
{
protected override System.Collections.Generic.IList<JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization)
{
return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList();
}
}
আমার উত্তর সহ এখানে:
কীভাবে এএসপি.নেট ওয়েব এপিআইকে সর্বদা জেএসএন ফেরত পাঠাতে বাধ্য করবেন?
হালনাগাদ
আমি কেবল ডাউনভোটগুলি দেখেছি। এটি কীভাবে করবেন তার জন্য দয়া করে নীচে 'স্টিভ' থেকে উত্তরটি দেখুন।
মূল
আমি JsonConvert.SerializeObject(key)
প্রতিবিম্বের মাধ্যমে পদ্ধতি কলটি অনুসরণ করেছি (যেখানে কীটি একটি আইলিস্ট ছিল) এবং দেখতে পেলাম যে জসনসিরাইজারআইটার্নালাইকার Sসিরাইজলিস্ট কল হয়ে যায়। এটি একটি তালিকা নেয় এবং মাধ্যমে লুপ করে
for (int i = 0; i < values.Count; i++) { ...
যেখানে মানগুলি IList পরামিতি আনা হয়।
সংক্ষিপ্ত উত্তরটি হ'ল ... না, ক্ষেত্রগুলি JSON স্ট্রিংয়ে তালিকাভুক্ত করা হয়েছে তা নির্ধারণের জন্য কোনও বিল্টই নেই।
জেএসওএন ফর্ম্যাটে কোনও ক্ষেত্রের অর্ডার নেই তাই কোনও অর্ডার সংজ্ঞায়িত করার অর্থ হয় না।
{ id: 1, name: 'John' }
সমান { name: 'John', id: 1 }
(উভয়ই কঠোর সমতুল্য বস্তুর উদাহরণ উপস্থাপন করে)