具有默认 DotNetCore 活页夹的 JsonExtensionData 属性

JsonExtensionData attribute with default DotNetCore binder

我正在尝试将带有一些动态字段的 JSON 传递给 DotNetCore 3.1 Web API 项目中的控制器操作方法。我在发送有效载荷时使用的 class 看起来像这样:

public class MyDynamicJsonPayload
{
    public string Id { get; set; }
    [JsonExtensionData]
    public IDictionary<string, object> CustomProps { get; set; }
}

我可以看到该对象已正确序列化,并在 JSON 的正文中添加了 props。所以我将它从一项服务发送到另一项服务:

using var response = await _httpClient.PostAsync($"/createpayload", new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json"));

然而,在接收端,当在控制器操作中使用相同的 class 时:

public async Task<ActionResult> CreatePayload([FromBody] MyDynamicJsonPayload payload)
{
    var payload = JsonConvert.SerializeObject(payload);

    return Ok(payload);
}

对象被解析为不同的东西,其中 customProps 是一个包含我的属性的 JSON 对象的实际字段,加上我得到一个 JSON 对象而不是简单值 {"例如,字符串属性的 valueKind":"string"}。我尝试了 Newtonsoft.JsonSystem.Text.Json.Serialization 都没有按预期工作。有人有什么想法吗?

首先欢迎来到 Whosebug。

您可以试试这个解决方案;

拳头像你一样创建一个 class 但没有字典;

public class History
{
    public int Id { get; set; }
    public string DeviceName { get; set; }
    public int DeviceId { get; set; }
    public string AssetName { get; set; }
}

之后请将此属性添加到您的控制器class;

[Produces("application/json")]

你的方法应该是这样的;

[Produces("application/json")]
public class ExampleController: Controller 
{
   [HttpGet]
   public Task<IEnumerable<History>> Get()
   {
       List<History> historyList = new List<History>()
       {
           new History()
           {
             ...
           },
           new History()
           {
             ...
           }
       }
     
       return historyList;
   }
}

感谢 dbc 为我指明了正确的方向,问题是 Newtownsoft vs System.Text.Json serialization/deserialization。我无法更改 Startup class 中的序列化程序,因为该服务有许多其他方法,我不想破坏现有合同。但是,我设法编写了一个自定义模型活页夹来解决问题:

public class NewtonsoftModelBinder : IModelBinder
{
    public async Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));

        string body = string.Empty;
        using (var reader = new StreamReader(bindingContext.HttpContext.Request.Body))
        {
            body = await reader.ReadToEndAsync();
        }

        var result = JsonConvert.DeserializeObject(body, bindingContext.ModelType);

        bindingContext.Result = ModelBindingResult.Success(result);
    }
}

和用法:

public async Task<ActionResult> CreatePayload([ModelBinder(typeof(NewtonsoftModelBinder))] MyDynamicJsonPayload payload)
{
// Process payload...
    return Ok();
}