Система.Текст.Json JsonSerializer: Сериализация и десериализация системы.Экземпляры типа » не поддерживаются

#c# #asp.net-core #blazor #system.text.json

Вопрос:

Я получил ошибку, связанную с безопасностью, когда попытался десериализоваться с помощью System.Text.Json JsonSerializer`.

  • Чего я хочу достичь?
    Я хочу предоставить пользователю возможность управлять некоторыми записями в моей базе данных, чтобы использовать этот сценарий:

    1 — Пользователь может выбрать модель моей библиотеки классов.
    2 — После выбора класса пользователь выберет свойство(файл) из этого класса.
    3 — Пользователь получит список значений выбранного свойства.
    4 — Последнего шага здесь сейчас нет, пользователь может отредактировать значение сертификата.

Это мой фрагмент кода:

  • Моя страница.razor.cs:
     [Inject]
    private  IGenericHttpClient<Type> HttpClient { get; set; }
    private Type SelectedType { get; set; }
    
    // First select a class [Class library] from HTML Select
    private void OnTypeChnage(ChangeEventArgs args)
    {
       string FullName = "My.Models."   args.Value.ToString();
       // Create type of selected class
       SelectedType = Assemble.GetType(FullName, false);
    }
    //Call api to get all fields of this class
    private async Task OnPropertChange(ChangeEventArgs args)
    {
       var list = await 
      HttpClient.GetJsonAsync($"/api/{SelectedType.Name}/all");
    }
     
  • GenericHttpClient.cs
     public async ValueTask<List<T>> GetJsonAsync(string url)
      {
          using HttpResponseMessage response = await _client.GetAsync(url);
          ValidateResponse(response);
          var conetnt =  await response.Content.ReadAsStringAsync();
          //I got the error down
          return JsonSerializer.Deserialize<List<T>>(conetnt, new JsonSerializerOptions() { PropertyNameCaseInsensitive=true});
      }
     

Ответ №1:

Система.Текст.Json не поддерживает класс типа по соображениям безопасности. Вы отправляете полное имя сборки в виде строки и снова пытаетесь создать тип на стороне клиента.

Комментарии:

1. Привет @Mayur, я понимаю, что Type class это вызывает проблему, Не могли бы вы помочь мне выполнить то, что вы сказали о «Вы отправляете полное имя сборки в виде строки и снова пытаетесь создать тип на стороне клиента».

2. Не могли бы вы подробнее рассказать о своем варианте использования/ потоке?

3. Хорошо, я добавлю какое-то решение, но оно не очень эффективное, поэтому, пожалуйста, прочтите его, и если вы сможете сделать его лучше, это будет здорово!.

4. Я думаю, что мы столкнулись с проблемой XY. Использование динамических, особенно в HTTP-запросах и т.д., Не очень полезно. С таким же успехом вы могли бы использовать словарь. Если вы сможете сформулировать свою функциональную/бизнес-цель, это поможет нам быстрее прийти к решению.

Ответ №2:

public async ValueTask<List<T>> GetJsonAsync(string url) это даже не будет компилироваться из-за отсутствия указания общей информации о сигнатуре метода.

Кроме того, ваша проблема будет связана с содержанием http-ответа, в противном случае этот Deserialize шаг должен работать нормально.

Я скопировал ваш код и сделал небольшой блок, который это доказывает.

 // Define somewhere
public class GenericHttpClient
{
    public List<T> GetJsonAsync<T>()
    {
        var content = "[{"TestProp": "This is some test"}]";
        return JsonSerializer.Deserialize<List<T>>(content, new JsonSerializerOptions() { PropertyNameCaseInsensitive=true});
    }
}

public class Test
{
    public string TestProp { get; set; }
}

// Test it
var test = new GenericHttpClient();
var result = test.GetJsonAsync<Test>();
 

Комментарии:

1. Спасибо Гордон, вы правы, но у меня здесь нет определенного класса, выбранный класс происходит из выбора HTML, я имею в виду, что пользователь должен выбрать класс, а затем я должен получить данные

Ответ №3:

Например, то, о чем упоминал @Mayur Ekbote: «System.Text.Json не поддерживает тип класса по соображениям безопасности.» Я добавлю решение, но я не думаю, что это решение очень эффективно.

  • Изменить Type на Dynamic :
       [Inject]
      private  IGenericHttpClient<dynamic> HttpClient { get; set; }
     
  • Используйте JsonElement , чтобы получить значение в виде строки:
           private async Task OnPropertChange(ChangeEventArgs args)
          {
           var langCode = CultureInfo.CurrentCulture.Name;
           PropertyValueList.Clear();
    
          var list = await HttpClient.GetJsonAsync($"/api/{SelectedType.Name}/all");
          List<object> listValue = new List<object>();
    
          SelectedProperty = args.Value.ToString();
          string fieldName = char.ToLower(SelectedProperty[0])   SelectedProperty.Substring(1);
          foreach (var item in list)
          {
              //Convert object to JsonElement
              var val = ((JsonElement)item).GetProperty(fieldName).GetString();
              PropertyValueList.Add(val);
    
          }
    
      }
     
  • Почему это не эффективно?
    Потому что я получил список значений String вместо списка выбранных классов.