Runtime: لا يقوم Asp.NET Core 3.0 Json الجديد بإجراء تسلسل للقاموس<key/>

تم إنشاؤها على ٧ أغسطس ٢٠١٩  ·  51تعليقات  ·  مصدر: dotnet/runtime

معاينة .NET Core 3.0 7

Asp.NET Web Apis ، عند إعادة قاموس فإنه يفشل مع NotSupportedException. لقد قمت بتضمين الاستثناء أدناه.

أيضًا ، تأخذ طريقة ControllerBase.BadRequest ModelStateDictionary ، ولكن عندما يتم إرجاعها ، يتم تفجير جهاز التسلسل أيضًا مع NotSupportedException ، ولكن رسالة مختلفة قليلاً.

متى سيتم إضافة هذا الدعم؟ نظرًا لأن هذا تم دعمه في Json.net والمسلسلات الأخرى لفترة من الوقت ، آمل أن يكون هذا على الرادار.

أقدر حقًا حقيقة أنه يمكنني إعادة الاشتراك في استخدام Json.net ، لذا شكرًا جزيلاً لك على ذلك!

استثناء عند إرجاع قاموس
System.NotSupportedException: نوع المجموعة 'System.Collections.Generic.Dictionary`2 [System.Int32، System.String]' غير مدعوم.
في System.Text.Json.JsonClassInfo.GetElementType (النوع propertyType ، Type parentType ، MemberInfo memberInfo ، JsonSerializerOptions options)
في System.Text.
في System.Text.Json.JsonClassInfo.AddProperty (النوع propertyType و PropertyInfo propertyInfo و Type classType و JsonSerializerOptions options)
في System.Text.Json.JsonClassInfo.AddPolicyProperty (اكتب propertyType وخيارات JsonSerializerOptions)
في System.Text.Json.JsonClassInfo..ctor (نوع النوع ، خيارات JsonSerializerOptions)
في System.Text.Json.JsonSerializerOptions.GetOrAddClass (النوع classType)
في System.Text.Json.WriteStackFrame.Initialize (نوع النوع ، خيارات JsonSerializerOptions)
في System.Text.Json.JsonSerializer.WriteAsyncCore (Stream utf8Json، Object value، Type type، JsonSerializerOptions options، CancellationToken cancellationToken)
في Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync (سياق OutputFormatterWriteContext ، الترميز المحدد الترميز)
في Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync (سياق OutputFormatterWriteContext ، الترميز المحدد الترميز)
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged | 21_0 (مستدعي ResourceInvoker ، نتيجة IActionResult)
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__ جاهز | 29_0 مرشح TF ، مرشح TF
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow (سياق ResultExecutedContextSealed)
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext TFilter ، TFilterAsync
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters ()
--- نهاية تتبع المكدس من الموقع السابق حيث تم إلقاء الاستثناء ---
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited | 19_0 (ResourceInvoker Invoker، Task lastTask، State next، Scope range، Object state، Boolean isCompleted)
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged | 17_1 (مستدعي ResourceInvoker)
في Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask | 6_0 (نقطة نهاية نقطة النهاية ، مهمة طلب المهمة ، مسجل ILogger)
في Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke (سياق HttpContext)
في Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke (سياق HttpContext)
في Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke (سياق HttpContext)
في Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke (HttpContext httpContext)
في Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke (HttpContext httpContext ، ISwaggerProvider swaggerProvider)
في Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke (سياق HttpContext)

استثناء عند إرجاع BadRequest
System.NotSupportedException: نوع المجموعة "Microsoft.AspNetCore.Mvc.SerializableError" غير مدعوم.
في System.Text.Json.JsonClassInfo.GetElementType (النوع propertyType ، Type parentType ، MemberInfo memberInfo ، JsonSerializerOptions options)
في System.Text.
في System.Text.Json.JsonClassInfo.AddProperty (النوع propertyType و PropertyInfo propertyInfo و Type classType و JsonSerializerOptions options)
في System.Text.Json.JsonClassInfo.AddPolicyProperty (اكتب propertyType وخيارات JsonSerializerOptions)
في System.Text.Json.JsonClassInfo..ctor (نوع النوع ، خيارات JsonSerializerOptions)
في System.Text.Json.JsonSerializerOptions.GetOrAddClass (النوع classType)
في System.Text.Json.WriteStackFrame.Initialize (نوع النوع ، خيارات JsonSerializerOptions)
في System.Text.Json.JsonSerializer.WriteAsyncCore (Stream utf8Json، Object value، Type type، JsonSerializerOptions options، CancellationToken cancellationToken)
في Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync (سياق OutputFormatterWriteContext ، الترميز المحدد الترميز)
في Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync (سياق OutputFormatterWriteContext ، الترميز المحدد الترميز)
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged | 21_0 (مستدعي ResourceInvoker ، نتيجة IActionResult)
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__ جاهز | 29_0 مرشح TF ، مرشح TF
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow (سياق ResultExecutedContextSealed)
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext TFilter ، TFilterAsync
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters ()
--- نهاية تتبع المكدس من الموقع السابق حيث تم إلقاء الاستثناء ---
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited | 19_0 (ResourceInvoker Invoker، Task lastTask، State next، Scope range، Object state، Boolean isCompleted)
في Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Logged | 17_1 (مستدعي ResourceInvoker)
في Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask | 6_0 (نقطة نهاية نقطة النهاية ، مهمة طلب المهمة ، مسجل ILogger)
في Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke (سياق HttpContext)
في Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke (سياق HttpContext)
في Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke (سياق HttpContext)
في Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke (HttpContext httpContext)
في Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke (HttpContext httpContext ، ISwaggerProvider swaggerProvider)
في Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke (سياق HttpContext)

area-System.Text.Json enhancement

التعليق الأكثر فائدة

بالنسبة للوافدين الجدد ، فإن الحل المؤقت هو العودة إلى Newtonsoft.Json .

  1. أضف مرجع الحزمة إلى Microsoft.AspNetCore.Mvc.NewtonsoftJson .
  2. أضف .AddNewtonsoftJson() بعد .AddControllers() / .AddMvc() أو أي مجموعة أخرى.

ال 51 كومينتر

كلا أخطاء "الاستثناء غير المدعوم" هي قيود داخل جهاز التسلسل المدمج وهي حسب التصميم (على الأقل لما يتم الشحن في 3.0).

متى سيتم إضافة هذا الدعم؟ نظرًا لأن هذا تم دعمه في Json.net والمسلسلات الأخرى لفترة من الوقت ، آمل أن يكون هذا على الرادار.
أقدر حقًا حقيقة أنه يمكنني إعادة الاشتراك في استخدام Json.net ، لذا شكرًا جزيلاً لك على ذلك!

هناك مجموعة من إمكانيات المتسلسل الموجودة على رادارنا لدعمها في vNext (حتى 5.0) وما بعده ، مع دعم القاموس المخصص كونها واحدة منها.

Asp.NET Web Apis ، عند إعادة قاموس فإنه يفشل مع NotSupportedException

عند التسلسل ، يتم دعم Dictionary<string, TValue> اليوم (أي TKeys التي هي سلسلة). قاموسك هو <int, string> وهو غير مدعوم.
https://github.com/dotnet/corefx/blob/93d7aa1c1737b6da29d04b78557215e18eb786d4/src/System.Text.Json/tests/Serialization/DictionaryTests.cs#L385 -L390

steveharter ، layomia - هل هناك حل بديل محتمل هنا في هذه الأثناء؟ ما الذي يتطلبه الأمر لإضافة دعم لقاموس بدون سلسلة مفاتيح داخل المسلسل لـ 5.0؟

System.NotSupportedException: نوع المجموعة "Microsoft.AspNetCore.Mvc.SerializableError" غير مدعوم.

~ إضافة دعم لنوع مثل SerializableError لم يكن على الرادار الخاص بي. pranavkm ، rynowak - ما هو السياق هنا؟ لست على دراية بـ ModelStateDictionary ، فهل يمكن دعم ذلك داخل mvc نفسها باستخدام محول مخصص؟ ~

تحرير: لا تهتم ، هذا ثابت بالفعل.

System.NotSupportedException: نوع المجموعة "Microsoft.AspNetCore.Mvc.SerializableError" غير مدعوم.

كانت هذه مشكلة معروفة https://github.com/aspnet/AspNetCore/issues/11459 تم إصلاحها مؤخرًا (كجزء من المعاينة 8): https://github.com/dotnet/corefx/pull/39001

شكرا جزيلا على ردودكم السريعةahsonkhan!

إن "تحديد" المفتاح باعتباره سلسلة منطقية بالفعل عندما أفكر في الأمر. أرى الآن أن Json.net تقوم بالفعل بإنشاء json مع كون المفتاح عبارة عن سلسلة ، عند إلغاء تسلسلها ستعيدني إلى Int. سيكون من الجيد بالتأكيد الحصول على دعم للمفاتيح غير الخيطية في المستقبل ، ولكن ليس سدادة العرض.

حسنًا ، سعيد لسماع أنه تم إصلاح خطأ Mvc.SerializableError غير المدعوم. هل لديك أي أفكار حول ما إذا كان هناك تاريخ مأمول لإصدار Preview 8؟ حاولت البحث والعثور على شيء ما ، ولكن لم أر شيئًا عن ذلك.

بمجرد إصدار المعاينة 8 ، سنحاول إعطاء مكتبة التسلسل .net core 3 json المحاولة مرة أخرى ، ولكن في الوقت الحالي نحتاج إلى التمسك بـ Json.net

steveharter ، layomia - هل هناك حل بديل محتمل هنا في هذه الأثناء؟ ما الذي يتطلبه الأمر لإضافة دعم لقاموس بدون سلسلة مفاتيح داخل المسلسل لـ 5.0؟

>

ahsonkhan @ willyt150 الحل لهذا هو استخدام محول مخصص يقوم بتنفيذ JsonConverter<T> حيث T هو Dictionary<int, string> .
راجع https://github.com/dotnet/corefx/issues/36639#issue -429928740 للحصول على بعض الأمثلة.

هل لديك أي أفكار حول ما إذا كان هناك تاريخ مأمول لإصدار Preview 8؟

في وقت لاحق من هذا الشهر.

بالتفكير في هذا الأمر أكثر ، وإزالة الخيارات الجاهزة في الوقت الحالي نظرًا لأنه قد يكون شيئًا لا نريد دعمه افتراضيًا.

شكرًا لك layomia ، سألقي نظرة على ذلك.

شكرًا ahsonkhan ، أتطلع إلى الإصلاح القادم!

من namse (من https://github.com/dotnet/corefx/issues/40404):

أهلا. عندما أحاول إجراء تسلسل للقاموس باستخدام مفتاح عدد صحيح ، فإنه يرمي System.NotSupportedException.

أعتقد أنه من المنطقي دعم تسلسل Json الذي يحتوي على قاموس ToString مفتاح. على سبيل المثال ، عندما نقوم بتشغيل ToString لـ int أو boolean ، فإنها تُرجع "123" أو "true". أعتقد أن هذا المفتاح هو ToString مفتاح قابل.

فيريسون

System.Text.Json Nuget الإصدار: 4.6.0-preview8.19405.3

الشفرة

var dictionary = new Dictionary<int, string>
{
  [5] = "five"
};
JsonSerializer.Serialize(dictionary);

متوقع

"{"5": "five"}"

لكن ماذا حدث

خطأ System.NotSupportedException إلقاؤه

في الواقع ، هناك مشكلة في التوافق عندما أقوم بتغيير Newtonsoft.Json إلى System.Text.Json. يعيدون السلسلة كما توقعت. أعتقد أنه ليس من الضروري أن يكون System.Text.Json متوافقًا ولكن ... كما تعلم.

لقد قمت بتطبيق محول يدعم كلاً من التسلسل وإلغاء التسلسل لـ IDictionary<TKey, TValue> حيث يحتوي TKey على طريقة ثابتة TKey Parse(string) :

using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace JsonDictionaryConverter
{
    sealed class JsonNonStringKeyDictionaryConverter<TKey, TValue> : JsonConverter<IDictionary<TKey, TValue>>
    {
        public override IDictionary<TKey, TValue> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            var convertedType = typeof(Dictionary<,>)
                .MakeGenericType(typeof(string), typeToConvert.GenericTypeArguments[1]);
            var value = JsonSerializer.Deserialize(ref reader, convertedType, options);
            var instance = (Dictionary<TKey, TValue>)Activator.CreateInstance(
                typeToConvert,
                BindingFlags.Instance | BindingFlags.Public,
                null,
                null,
                CultureInfo.CurrentCulture);
            var enumerator = (IEnumerator)convertedType.GetMethod("GetEnumerator")!.Invoke(value, null);
            var parse = typeof(TKey).GetMethod("Parse", 0, BindingFlags.Public | BindingFlags.Static, null, CallingConventions.Any, new[] { typeof(string) }, null);
            if (parse == null) throw new NotSupportedException($"{typeof(TKey)} as TKey in IDictionary<TKey, TValue> is not supported.");
            while (enumerator.MoveNext())
            {
                var element = (KeyValuePair<string?, TValue>)enumerator.Current;
                instance.Add((TKey)parse.Invoke(null, new[] { element.Key }), element.Value);
            }
            return instance;
        }

        public override void Write(Utf8JsonWriter writer, IDictionary<TKey, TValue> value, JsonSerializerOptions options)
        {
            var convertedDictionary = new Dictionary<string?, TValue>(value.Count);
            foreach (var (k, v) in value) convertedDictionary[k?.ToString()] = v;
            JsonSerializer.Serialize(writer, convertedDictionary, options);
            convertedDictionary.Clear();
        }
    }

    sealed class JsonNonStringKeyDictionaryConverterFactory : JsonConverterFactory
    {
        public override bool CanConvert(Type typeToConvert)
        {
            if (!typeToConvert.IsGenericType) return false;
            if (typeToConvert.GenericTypeArguments[0] == typeof(string)) return false;
            return typeToConvert.GetInterface("IDictionary") != null;
        }

        public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
        {
            var converterType = typeof(JsonNonStringKeyDictionaryConverter<,>)
                .MakeGenericType(typeToConvert.GenericTypeArguments[0], typeToConvert.GenericTypeArguments[1]);
            var converter = (JsonConverter)Activator.CreateInstance(
                converterType,
                BindingFlags.Instance | BindingFlags.Public,
                null,
                null,
                CultureInfo.CurrentCulture);
            return converter;
        }
    }
}

اختبار:

class Entity
{
    public string Value { get; set; }
}
class TestClass
{
    public Dictionary<int, Entity> IntKey { get; set; }
    public Dictionary<float, Entity> FloatKey { get; set; }
    public Dictionary<double, Entity> DoubleKey { get; set; }
    public Dictionary<DateTime, Entity> DateTimeKey { get; set; }
    public Dictionary<string, Entity> StringKey { get; set; }
}
class Program
{
    static void Main(string[] args)
    {
        var options = new JsonSerializerOptions();
        options.Converters.Add(new JsonNonStringKeyDictionaryConverterFactory());
        var x = new TestClass
        {
            IntKey = new Dictionary<int, Entity> { [1] = new Entity { Value = "test" } },
            FloatKey = new Dictionary<float, Entity> { [1.3f] = new Entity { Value = "test" } },
            DoubleKey = new Dictionary<double, Entity> { [1.35] = new Entity { Value = "test" } },
            DateTimeKey = new Dictionary<DateTime, Entity> { [DateTime.Now] = new Entity { Value = "test" } },
            StringKey = new Dictionary<string, Entity> { ["test"] = new Entity { Value = "test" } }
        };

        var value = JsonSerializer.Serialize(x, options);
        Console.WriteLine(value);
        var obj = JsonSerializer.Deserialize<TestClass>(value, options);
        Console.WriteLine(JsonSerializer.Serialize(obj, options));
    }
}

نتيجة:

{"IntKey":{"1":{"Value":"test"}},"FloatKey":{"1.3":{"Value":"test"}},"DoubleKey":{"1.35":{"Value":"test"}},"DateTimeKey":{"8/25/2019 6:47:48 PM":{"Value":"test"}},"StringKey":{"test":{"Value":"test"}}}
{"IntKey":{"1":{"Value":"test"}},"FloatKey":{"1.3":{"Value":"test"}},"DoubleKey":{"1.35":{"Value":"test"}},"DateTimeKey":{"8/25/2019 6:47:48 PM":{"Value":"test"}},"StringKey":{"test":{"Value":"test"}}}

ومع ذلك ، لا يزال يتعذر عليه إجراء تسلسل لقاموس متداخل مثل Dictionary<int, Dictionary<int, int>> لأن System.Text.Json لا يقبل النوع الداخلي Dictionary<int, int> . أعتقد أنه خطأ.

ومع ذلك ، لا يزال يتعذر إجراء تسلسل لقاموس متداخل مثل القاموس> لأن System.Text.Json لا يقبل قاموس النوع الداخلي. أعتقد أنه خطأ.

دعم <string, x> هو حسب التصميم بسبب تقليص النطاق من أجل الشحن لـ v3.0. الغرض من الإصدار 3.0 هو أن يكون منتجًا قابلاً للتطبيق مع دعم السيناريوهات الأكثر شيوعًا.

steveharter على الأقل ، لا يجب عليك طرح استثناء للدعم عندما يكون هناك محول صالح للاستخدام.

هل هناك أي خطط لدعم هذا في .net core 3.1؟

بالنسبة للوافدين الجدد ، فإن الحل المؤقت هو العودة إلى Newtonsoft.Json .

  1. أضف مرجع الحزمة إلى Microsoft.AspNetCore.Mvc.NewtonsoftJson .
  2. أضف .AddNewtonsoftJson() بعد .AddControllers() / .AddMvc() أو أي مجموعة أخرى.

steveharter على الأقل ، لا يجب عليك طرح استثناء للدعم عندما يكون هناك محول صالح للاستخدام.

نعم هذه نقطة عادلة. ربما يمكننا إزالة هذا القيد لـ 3.1. cc playomia

أيضًا فقط لتوضيح أن عناصر القاموس اليوم متسلسلة مثل الخصائص وهو أمر ممكن لأن المفتاح عبارة عن سلسلة. دعم المفاتيح غير المتسلسلة يعني أنه سيتم إجراء تسلسل للعناصر على أنها KeyValuePair.

يا فتى ، واجهت هذه المشكلة بعد أن قمت بالترقية إلى 3.0.

اضطررت إلى تثبيت حزمة نيوتن مع AddNewtonsoftJson.

من israellot في https://github.com/dotnet/corefx/issues/41345

var dictionary = new Dictionary<int, int>()
            {
                [0] = 1
            };

 var serialized = System.Text.Json.JsonSerializer.Serialize(dictionary);

يتم التعامل مع هذا التسلسل البسيط بشكل جيد بواسطة مكتبة Newtonsoft json الافتراضية السابقة عن طريق إجراء تسلسل للمفتاح int كسلسلة. على System.Text.Json يطرح استثناء غير مدعوم.

israellot و unruledboy وغيرهما في سلسلة Dictionary<string, TValue> لن ينجح؟ أرغب في رؤية بعض الاستخدامات لجمع المتطلبات وللمساعدة في تحفيز الإصلاح.

سيتم تسلسلها كسلاسل على أي حال ، لذلك لا أفهم السيناريوهات التي تريد أن يحتوي قاموسك الأساسي على مفاتيح int32 بدلاً من ذلك.

ahsonkhan أعتقد أن الدافع الرئيسي هو التوافق.
كان المُسلسل الافتراضي السابق هو Newtonsoft ، لذلك ربما كتب المستخدمون نماذج كاملة بالاعتماد على قدرته على إجراء تسلسل للفئات العشوائية وإلغاء تسلسلها. سيؤدي الترحيل من 2.X إلى 3.0 الآن إلى تغيير فاصل صامت لأننا سنعرف فقط عدم التوافق في وقت التشغيل.

أعتقد أن العديد من السيناريوهات تتضمن استخدام json تمامًا مثل النقل عبر السلك ، وفي هذه الحالة ، قد يكون نموذج المجال هو Dictionary. يتلخص اقتراحك في إنشاء قاموس كائن DTO منفصلوالتحويل بين الاثنين ، يبدو غير فعال إلى حد ما لأننا الآن بحاجة إلى تخصيص كائن آخر لمجرد التوافق مع المسلسل.
بالنظر بدقة إلى المسلسل ، فإن تقييد القاموس على وجود مفاتيح سلسلة أمر منطقي لأن هذا هو تمثيل json الوحيد الممكن. لكن بالنظر إلى أن المسلسل يلعب دورًا في التطبيقات ، أعتقد أنه من الأفضل إزالة أكبر قدر ممكن من الاحتكاك.

لقد واجهت هذه المشكلة مع برنامج صغير أكتبه حيث يتم توفير أجزاء من تسمية الإصدار من خلال ملف json.
تحتوي أجزاء الملصق على مفتاح يحدد الفهرس حيث يمكن إدراج جزء التسمية. هذا يعني أن المفاتيح عبارة عن قيم رقمية ، على سبيل المثال

{
  "parts" : {
    "1" : "alpha",
    "3" : "beta"
  }
}

باستخدام Newtonsoft ، يمكن إلغاء تسلسل json بدون إصدار إلى Dictionary<int, string> . بعد التحويل إلى System.Text.Json فشل التسلسل.

لقد قمت بحل هذه المشكلة عن طريق إنشاء DictionaryConverter و DictionaryConverter الخاص بي .
لقد قمت أيضًا بإنشاء محول بسيط يسمح بإلغاء تسلسل الأعداد الصحيحة من سلسلة

ثم يتم تسجيلها من خلال خيارات المسلسل: https://github.com/Kieranties/SimpleVersion/blob/master/src/SimpleVersion.Core/Serialization/Serializer.cs#L22

تسمح هذه التغييرات بإلغاء تسلسل مفاتيح القاموس بدلاً من قراءتها مباشرةً كسلسلة. يفتح هذا أيضًا الدعم للمفاتيح لتكون أنواعًا عشوائية يمكن أن يكون لها محولات خاصة بها مسجلة للتسلسل (على سبيل المثال ، التعداد / النوع / الأنواع التي يمكن تسلسلها كمفاتيح فريدة وما إلى ذلك)

لم أختبر الأشياء رسميًا ولكن في إطار التطوير الحالي يبدو أن هذا قد حل المشكلة.

تعيين معلم لـ 3.1 لإزالة أي قيود تمنع إنشاء محول مخصص يمكنه التعامل مع أي TKey مقابل Dictionary<TKey,TValue> .

تحديث: لقد أضفت عينات تعمل مع 3.0. لم ألاحظ أي مشكلات مثل القواميس المتداخلة كما هو مذكور أعلاه.

هناك نوعان من تنسيقات JSON المستخدمة في العينات:

  • كائن JSON بخصائص سلسلة: {"1":"val1","2":"val2"} بالرغم من أن TKey ليس سلسلة.

    • هذه تعتمد على طريقة TryParse على نوع المفتاح المدعوم المقابل. بالنسبة للإصدار 3.0 ، ليس من المجدي تقديم دعم معمم TKey حيث أن طرق TryParse يمكن أن تكون مختلفة عن أي TKey ولأن هناك إعدادات ثقافية يجب توفيرها (عادة ثابت). لذا فإن العينات أدناه تخص نوعًا واحدًا من TKey .

    • Sample Dictionary<int, string> . هذا مثال بسيط لمجرد TValue == string .

    • Sample Dictionary<Guid, TValue> . هذا يمكن أن يتعامل مع أي TValue .

    • Sample Dictionary<TKey, TValue> where TKey is Enum . من أجل Enums هذا يمكن أن يتعامل مع أي TValue .

  • مصفوفة JSON بإدخالات KeyValuePair: [{"Key":1,"Value":"val1"},{"Key":2,"Value":"val2"}]

إذا كانت هذه العينات مرضية ، فسوف أقوم بتغيير هذه المشكلة إلى 5.0 لمناقشة ما إذا كنا نقدم دعمًا مدمجًا لا يتطلب محولات مخصصة.

تعيين معلم إلى 5.0 للنظر فيه (ماذا لو كان أي من الأمثلة المذكورة أعلاه يجب أن يعمل بشكل افتراضي).

يبدو أيضًا أن إلغاء التسلسل يعين أنواع الكائنات العامة إلى JsonDocument بدلاً من الأنواع العادية (البدائية؟).

مثال:

string test = "[{\"id\":86,\"name\":\"test\"}]";
var SystemTextJson = System.Text.Json.JsonSerializer.Deserialize<List<Dictionary<string, object>>>(test);
var NewtonSoftJson = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(test);

يظهر SystemTextJson [0] ["id"] بالشكل: ValueKind = الرقم: "86"
يظهر NewtonSoftJson [0] ["id"] بالشكل: 86

steveharter يتسلسل قاموس تعداد
{ "Stuff": [ { "Key": 1, "Value": "String" }, { "Key": 3, "Value": "String" }, { "Key": 2, "Value": "String" } ] }

بينما تقدم JSON.NET ما أفترض أن معظم الناس يتوقعونه:
{ "Stuff": { "Item1": "String", "Item2": "String", "Item3": "String" }

يبدو أيضًا أن إلغاء التسلسل يعين أنواع الكائنات العامة إلى JsonDocument بدلاً من الأنواع العادية (البدائية؟).

نعم هذا حسب التصميم. راجع https://github.com/dotnet/corefx/issues/38713

steveharter يتسلسل قاموس تعداد
{"Stuff": [{"Key": 1، "Value": "String"}، {"Key": 3، "Value": "String"}، {"Key": 2، "Value": " سلسلة" } ] }
بينما تقدم JSON.NET ما أفترض أن معظم الناس يتوقعونه:
{"Stuff": {"Item1": "String"، "Item2": "String"، "Item3": "String"}

أفترض أنك تستخدم "نموذج القاموسإذا كان الأمر كذلك ، نعم ، استخدم KeyValuePair الذي يحتوي على خصائص "Key" و "Value". لم أقم بتقديم عينة لقواميس التعداد المستندة إلى TKey والتي تتسلسل كأسماء خصائص ، لكنني سأعمل على إضافة ذلك.

نعم ، هذا واحد. وآه حسنًا ، أعتقد أنك كنت تقصد ذلك كمسلسل عام للقاموس.
مهتم برؤية عينتك الجديدة عندما تكون متاحة ، لأن العينة التي نستخدمها حاليًا لا تبدو بالسرعة التي أريدها.

roguecode هنا نموذج Enum لـ Dictionary<TKey, TValue> حيث TKey هو Enum ويستخدم صيغة JSON "الخاصية" بدلاً من KeyValuePair. لقد قمت أيضًا بتحديث قائمة العينات أعلاه لتشمل هذه العينة الجديدة.

مرحبًا ، لدي شيء مشابه ولكنه مختلف وأتساءل عما إذا كان يمكنك توجيهي إلى مكان آخر للبحث فيه.

نيوتن سوفت. Json: 12.0.2
Microsoft.AspNetCore.Mvc.NewtonsoftJson: 3.0.0

بدء التشغيل ك 3.0:

                .AddMvc(mvcOptions => mvcOptions.EnableEndpointRouting = false)
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .AddNewtonsoftJson();

إذا كانت لدي هذه المشكلة تفاصيل الكائن:

// problemDetails has 2 extension items
{Microsoft.AspNetCore.Mvc.ValidationProblemDetails}
    Detail: "Please refer to the 'errors' property for additional details."
    Errors: Count = 1
    Extensions: Count = 2
    Instance: "/api/test/complex-binding-from-query"
    Status: 400
    Title: "One or more validation errors occurred."
    Type: "https://tools.ietf.org/html/rfc7231#section-6.5.1"

في 2.2 ، تنفيذ عوائد Newtonsoft.Json.JsonConvert.SerializeObject(problemDetails)

{"errors":{"Int":["The value 'a' is not valid for Int."]},"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"detail":"Please refer to the 'errors' property for additional details.","instance":"/api/test/complex-binding-from-query","traceId":"0HLQQ40AFBJNG","correlationId":"0HLQQ40AFBJNG"}

في 3.0 يعود:

{"Errors":{"param":["The value 'a' is not valid."]},"Type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","Title":"One or more validation errors occurred.","Status":400,"Detail":"Please refer to the 'errors' property for additional details.","Instance":"/bad-request","Extensions":{"traceId":"|d0d40f80-48b6c9184401b0e1.","correlationId":"0HLQR10NSMRGD:00000009"}}

تتضمن السلسلة المتسلسلة للإصدار 3.0 IDictionaryاسم الخاصية ، Extensions ، ويمكننا إلغاء تسلسل هذه السلسلة بشكل صحيح في 3.0. يمكنك أن ترى أن اسم الخاصية هذا متروك من الإصدار 2.x.

المشكلة هي أن التسلسل 3.0 الذي يحدث عندما يتم إرجاع الاستجابة من عامل تصفية باستخدام BadRequestObjectResult ، من الكود أدناه:

public sealed class ProblemDetailsResultFilterAttribute : Attribute, IAlwaysRunResultFilter
{
        public void OnResultExecuting(ResultExecutingContext context)
        {
             context.Result = new BadRequestObjectResult(problemDetails);
        }
}

... ، محتوى الاستجابة الذي يتم إرجاعه هو نفس شكل الإصدار 2.2 (تم استبعاد اسم الخاصية Extensions ) ، مما يتسبب في إلغاء تسلسل الخاصية Extensions كمجموعة فارغة (باستخدام Newtonsoft.Json.JsonConvert.DeserializeObject<ValidationProblemDetails>() )

بطريقة ما ، لا يستخدم هذا التسلسل نفس التسلسل مثل مكتبة Newtonsoft التي نحاول إلغاء التسلسل معها.

شكرا للنظر!

لدي شيء مشابه لكن مختلف

@ ts46235 هل يمكنك من فضلك فتح إصدار جديد لهذا لأن هذا يختلف عن الإصدار الحالي؟

@ ts46235 لقد أجبت على سؤالك في الإصدار الآخر الذي فتحته هنا - https://github.com/aspnet/AspNetCore/issues/16618. جعل المحادثة هنا خارج الموضوع.

تم التحديث إلى Core 3.1 وما زال غير ثابت

لقد قمت بالترقية إلى 3.1 للتو وتعرضت لهذا. رجوع إلى JSON.NET أذهب ... (أستخدم مفاتيح GUID)

دوت نت كور 3.1.2
قاموسلا يعمل أيضًا ، حتى الكائن الموجود في المفتاح هو في الواقع سلسلة

أنا أيضًا أصبت بهذا ، ويا ​​له من قيود صامتة مخيفة ، حيث أشار آخرون إلى أنك لن ترى هذا في وقت الترجمة. في حالتي ، أريد إجراء تسلسل لـ Dictionary<int, List<string>> ، والذي لا يبدو لي غريبًا بشكل خاص.

يجب أن يصلحوه ولكني أرى هذا مرارًا وتكرارًا حتى مع المنسق القديم ، والمنسق الثنائي في وقت مبكر newtsoft ، والقواميس في القواميس ، والقواميس ذات الواجهات. يجب عليهم إصلاحها ، ولكن إذا كنت لا تريد المشاكل ، فلا يجب على الأشخاص حقًا وضع أشياء معقدة مثل القواميس في عقود التسلسل ، حيث يطلبون منك مشكلة - لقد أفسد موقع newtsoft الأشخاص. انظر إلى جميع الخصائص العامة في Dictionary count وما إلى ذلك ، فأنت تعتمد على شيء مخصص في المسلسل لتعيين ذلك.

لسوء الحظ ، لا يوجد نوع بسيط لهذا في C # لأسماء الخصائص ، لذلك يتم فرض القاموس. لذلك انا حزين فقط ..

إليك حل بديل ولكنه ليس حلاً كاملاً بأي حال من الأحوال:

   [JsonConverter(typeof(DictionaryConverter))]
   public Dictionary<string, object> ExtraProperties { get; set; } = new Dictionary<string, object>();
public class DictionaryConverter : JsonConverter<Dictionary<string, object>>
{
    public override Dictionary<string, object> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var dictionary = JsonSerializer.Deserialize<Dictionary<string, object>>(ref reader, options);

        foreach (string key in dictionary.Keys.ToList())
        {
            if (dictionary[key] is JsonElement je)
            {
                dictionary[key] = Unwrap(je);
            }
        }

        return dictionary;
    }

    public override void Write(Utf8JsonWriter writer, Dictionary<string, object> value, JsonSerializerOptions options)
        => JsonSerializer.Serialize(writer, value, options);

    private static object Unwrap(JsonElement je)
    {
        return je.ValueKind switch
        {
            JsonValueKind.String => je.ToString(),
            JsonValueKind.Number => je.TryGetInt64(out var l) ? l : je.GetDouble(),
            JsonValueKind.True => true,
            JsonValueKind.False => false,
            JsonValueKind.Array => je.EnumerateArray().Select(Unwrap).ToList(),
            JsonValueKind.Object => je.EnumerateObject().ToDictionary(x => x.Name, x => Unwrap(x.Value)),
            _ => null
        };
    }

ربما يمكن إضافة دعم (بعض) الأنواع الشائعة للمسلسلات OOTB ، على سبيل المثال هذه القائمة ، وأيضًا إذا كان أحد هذه الأنواع .IsAssignableFrom(systemDotObjectInstance.GetType()) لدعم Dictionary<<ins i="7">object</ins>, V> .

إليك اقتراح إضافة دعم لأنواع غير سلسلة TKey في القواميس.
https://github.com/dotnet/runtime/pull/32676

من فضلك دعنا نعرف أي أفكار أو مخاوف.

على وجه التحديد ، يرجى تقديم ملاحظات حول مجموعة الأنواع التي تخطط Jozkee لدعم مفاتيح القاموس ، خاصة إذا كنت بحاجة إلى دعم أنواع أخرى (بشكل أساسي ، جميع الأنواع الرقمية الأولية المضمنة ، والتعدادات ، وعدد قليل من الأنواع الأخرى):
https://github.com/dotnet/runtime/blob/a5d96c0e280b56412d4614848f5ee3b1e0d7f216/src/libraries/System.Text.Json/docs/KeyConverter_spec.md#keyconverter

قاموسلا يعمل أيضًا ، حتى الكائن الموجود في المفتاح هو في الواقع سلسلة

@ andrew-vdb ، دعم تسلسل مفاتيح الكائنات العشوائية سيظل على الأرجح غير مدعوم. ومع ذلك ، إذا كان نوع وقت تشغيل مفاتيح الكائن أحد أنواع "المدعومة حديثًا" ، فسيعمل التسلسل لذلك بمجرد الانتهاء من الميزة. ومع ذلك ، سيظل إلغاء التسلسل على شكل JsonElement (حتى تتم معالجة هذه المشكلة المتعلقة بالاشتراك في السلوك المختلف): https://github.com/dotnet/runtime/issues/29960

Jozkee ما هي الأنواع الممكنة لـ TValue ؟ من المفترض أن أي شيء يمكنك إجراء تسلسل له حاليًا ككائن مستقل؟

من المفترض أن أي شيء يمكنك إجراء تسلسل له حاليًا ككائن مستقل؟

نعم فعلا.

يبدو أيضًا أن إلغاء التسلسل يعين أنواع الكائنات العامة إلى JsonDocument بدلاً من الأنواع العادية (البدائية؟).

مثال:

string test = "[{\"id\":86,\"name\":\"test\"}]";
var SystemTextJson = System.Text.Json.JsonSerializer.Deserialize<List<Dictionary<string, object>>>(test);
var NewtonSoftJson = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(test);

يظهر SystemTextJson [0] ["id"] بالشكل: ValueKind = الرقم: "86"
يظهر NewtonSoftJson [0] ["id"] بالشكل: 86

من بين جميع القضايا المذكورة ، هذا يزعجني أكثر. قائمةأو T [] أو القاموسيجب إلغاء التسلسل بشكل صحيح لأي نوع يمكن تعيينه مباشرة من الأنواع القليلة التي يجب على Json إلى أنواع CLR.

الغرض من الإصدار 3.0 هو أن يكون منتجًا قابلاً للتطبيق مع دعم السيناريوهات الأكثر شيوعًا

أتساءل كيف القائمة> ليس من أكثر السيناريوهات شيوعًا:

[// N objects
{"a":4},
{"b","Bla"},
]

نظرًا لأن هذا يؤدي أيضًا إلى إلغاء التسلسل إلى System.Text.JsonElement ، حيث أتوقع مضاعفة (رقم) وسلسلة (سلسلة)

لقد واجهت هذه المشكلة مع برنامج صغير أكتبه حيث يتم توفير أجزاء من تسمية الإصدار من خلال ملف json.
تحتوي أجزاء الملصق على مفتاح يحدد الفهرس حيث يمكن إدراج جزء التسمية. هذا يعني أن المفاتيح عبارة عن قيم رقمية ، على سبيل المثال

{
  "parts" : {
    "1" : "alpha",
    "3" : "beta"
  }
}

باستخدام Newtonsoft ، يمكن إلغاء تسلسل json بدون إصدار إلى Dictionary<int, string> . بعد التحويل إلى System.Text.Json فشل التسلسل.

لقد قمت بحل هذه المشكلة عن طريق إنشاء DictionaryConverter و DictionaryConverter الخاص بي .
لقد قمت أيضًا بإنشاء محول بسيط يسمح بإلغاء تسلسل الأعداد الصحيحة من سلسلة

ثم يتم تسجيلها من خلال خيارات المسلسل: https://github.com/Kieranties/SimpleVersion/blob/feature/netcore3/src/SimpleVersion.Core/Serialization/Serializer.cs#L20

تسمح هذه التغييرات بإلغاء تسلسل مفاتيح القاموس بدلاً من قراءتها مباشرةً كسلسلة. يفتح هذا أيضًا الدعم للمفاتيح لتكون أنواعًا عشوائية يمكن أن يكون لها محولات خاصة بها مسجلة للتسلسل (على سبيل المثال ، التعداد / النوع / الأنواع التي يمكن تسلسلها كمفاتيح فريدة وما إلى ذلك)

لم أختبر الأشياء رسميًا ولكن في إطار التطوير الحالي يبدو أن هذا قد حل المشكلة.

مرحبا Kieranties ، روابط جيثب 404 بالنسبة لي

مرحبا Kieranties ، روابط جيثب 404 بالنسبة لي

AirEssY لقد صححت الروابط في تعليقي الأصلي ، أعتقد أنها الآن في إتقان على: https://github.com/Kieranties/SimpleVersion/tree/master/src/SimpleVersion.Core/Serialization

إذا كان القاموس مكافئًا لخريطة JavaScript ، فيجب أن يكون أي نوع (JS ممثل في C #) مقبولًا ،

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

A Map's keys can be any value (including functions, objects, or any primitive).

مثال على النهج القياسي لإلغاء تسلسل خريطة في JS هو:

const countries = new Map(JSON.parse('[[1,"Bahamas (the)"],[2,"Bolivia (Plurinational State of)"]]'))

console.log(countries)

والتي تنتج:

Map(2) {
  1 => 'Bahamas (the)',
  2 => 'Bolivia (Plurinational State of)'
}

TL ؛ DR: تقييد المفاتيح بالأوتار لا يعمل بشكل جيد مع JS

Jozkee فهل هذا يأتي في .NET 5 فقط أم أنه سينتقل إلى 3. *؟

onionhammer .NET 5.0 ، يمكنك أيضًا تجربة الميزة في المعاينة التالية (5.0 معاينة 8).
لا توجد خطط لتحويل هذا إلى 3.x.

حل لـ asp net core 3.x:

var dic1 = new Dictionary<TKey, TValue>(); 
return Json(new { dic1 }); // does not work

var dic2 = from i in new Dictionary<TKey, TValue>() select new { i.Key, i.Value }
return Json(new { dic2 });  //works prety well

verloka هذا ليس الناتج المطلوب

Jozkee فهل هذا يأتي في .NET 5 فقط أم أنه سينتقل إلى 3. *؟

لن يتم نقل هذا إلى الإصدار 3.x ولكن يمكنك إضافة استخدام حزمة System.Text.Json NuGet في مشروعك للحصول على جميع الميزات الجديدة في .NET 5.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات