具有默认 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.Json
和 System.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();
}
我正在尝试将带有一些动态字段的 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.Json
和 System.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();
}