System.Text.Json JsonSerializer:不支持“System.Type”实例的序列化和反序列化

Posted

技术标签:

【中文标题】System.Text.Json JsonSerializer:不支持“System.Type”实例的序列化和反序列化【英文标题】:System.Text.Json JsonSerializer: Serialization and deserialization of 'System.Type' instances are not supported 【发布时间】:2021-10-05 07:55:07 【问题描述】: 当我尝试使用 `System.Text.Json JsonSerializer` 进行反序列化时,出现与安全性相关的错误。

我想实现什么? 我想让用户控制我的数据库中的一些记录,所以使用可以遵循这个场景:

1- 用户可以选择我的类库的模型。 2- 选择一个类后,用户将从该类中选择一个属性(归档)。 3-用户将获得所选属性的值列表。 4- 最后一步现在不在这里,用户可以编辑一个特定的值。

这是我的一段代码:

MyPage.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】:

出于安全原因,System.Text.Json 不支持 Type 类。您将完整的程序集名称作为字符串发送,然后再次尝试在客户端构造类型。

【讨论】:

嗨@Mayur,我知道Type class 会导致问题,请您帮我实现您所说的“您将完整的程序集名称作为字符串发送,然后再次尝试构造类型在客户端。” 您能否详细说明您的用例/流程? 好的,我会添加一些解决方案,但效率不是很高,所以请阅读它,如果你能做得更好,那就太好了!。 我认为我们遇到了 XY 问题。使用动态,尤其是在 HTTP 请求等中,并不是很有用。您不妨使用字典。如果您能说明您的职能/业务目标,这将有助于我们更快地找到解决方案。【参考方案2】:

public async ValueTask&lt;List&lt;T&gt;&gt; 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>();

【讨论】:

谢谢 Gordon,你说得对,但我这里没有特定的类,选择的类来自 HTML 选择,我的意思是用户必须选择类,然后我必须获取数据 【参考方案3】:

就像@Mayur Ekbote 提到的那样,“由于安全原因,System.Text.Json 不支持 Type 类。”我会添加一个解决方案,但我认为这个解决方案效率不高。

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 而不是所选类的列表。

【讨论】:

以上是关于System.Text.Json JsonSerializer:不支持“System.Type”实例的序列化和反序列化的主要内容,如果未能解决你的问题,请参考以下文章

System.Text.Json.JsonSerializer.Serialize 返回空 Json 对象“”[重复]

如何在反序列化之前使用 System.Text.Json 验证 JSON

使用 System.Text.Json 修改 JSON 文件

从 Newtonsoft.Json 迁移到 System.Text.Json

将 Newtonsoft.Json 代码迁移到 System.Text.Json

使用 System.Text.Json 转换不一致的 json 值 [重复]