【问题标题】:How do I force .net core 3.1 to deserialize all [FromBody] parameters with Newtonsoft instead of System.Text.Json?如何强制 .net core 3.1 使用 Newtonsoft 而不是 System.Text.Json 反序列化所有 [FromBody] 参数?
【发布时间】:2022-01-06 13:50:01
【问题描述】:

在将现有的 2.1 解决方案转换为 3.1 后,我进行了大量的谷歌搜索以解决中断问题。默认的 Json 序列化程序随着升级而改变,这应该没什么大不了的,除非我不一定让我的 json 参数名称在所有情况下都与我的属性相同。我用过很多次:

[JsonProperty( name = "ALegacyNamedList" , order = 0)]
public List<int> ABetterNamedList { get => aBetterNamedList ; private set => aBetterNamedList = value; }

因为显而易见的原因很好,破坏现有页面并非最不重要。我想你知道接下来会发生什么;一直默认构造的对象,因为 System.Text.Json.Serialization 需要一个不同的属性属性:

[JsonPropertyName( "ALegacyNamedList" )]
public List<int> ABetterNamedList ...

所以我可以到处走走,找出我在哪里命名 Json 参数与类属性有点不同,无论出于何种原因。或者我可以让我的应用程序改用 Newtonsoft,对吗?有很多文章都说明了这一点。

using Microsoft.AspNetCore.Mvc.NewtonsoftJson;
...
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().AddNewtonsoftJson();
    services.AddControllers().AddNewtonsoftJson();
    ...
}

我花了一个小时和 4 篇文章,以及至少六篇相关帖子才到这里,但我知道它没有使用 Newtonsoft 来处理控制器的 [FromBody] 参数:

[HttpPut("action")]
public string PutSomething( [FromBody] MyObject myObject )
{ ... }

MyObject 的属性在哪里归属

    List<int> aBetterNamedList = new List<SomeItems>();

    //[JsonPropertyName("ALegacyNamedList")]  // <-- This works / is not empty
    [JsonProperty("ALegacyNamedList", Order = 0)] // <-- This is default constructed / empty set because it newtonsoft is not used
    public List<int> ABetterNamedList { get => aBetterNamedList ; private set => aBetterNamedList = value; }`

那么我是否需要更新另一个地方,以便管道将使用正确的工具,以便 [FromBody] (application/json) 内容将不由 System.Text 而是由 Newtonsoft.Json 解析?

[编辑] 建议我澄清我的帖子。我不想到处检查所有代码并单独更改请求 [FromBody],也不想检查所有代码并更新有效的 Newtonsoft 属性。下面的答案允许我在一次调用中更改模型绑定。我希望管道本身更新,以便使用 newtonsoft 反序列化完成所有绑定。

【问题讨论】:

  • 我遇到了和你类似的问题,对我来说,最好解析 json 并再次构建整个类。你可以做到here
  • 感谢 dbc。是的,这在每个请求级别上给了我一个积极的结果。不幸的是,我似乎不需要识别我的 json 属性名称与我的类属性不同的每个地方,而是需要在代码中识别我正在执行 [FromBody] 参数反序列化的所有地方。该代码应用于中间件层本身而不是单个请求将非常有用。
  • 那我不确定答案。您可以 edit 问题的标题和正文,并根据该要求对其进行更新。
  • 在使用AddNewtonsoftJson() 时,是什么让您如此确信Json.NET 不用于[FromBody] 参数?我已经用了很多年了,我可以保证它没有使用System.Text.Json

标签: c# asp.net-core .net-core json.net model-binding


【解决方案1】:

我建议你使用这种语法来配置控制器

using Newtonsoft.Json.Serialization;
.....

public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews()
    .AddNewtonsoftJson(options =>
           options.SerializerSettings.ContractResolver =
              new CamelCasePropertyNamesContractResolver());
.....
}

【讨论】:

    【解决方案2】:

    部分答案来自这篇文章:How to use the json.net... 我不喜欢它,因为它仅适用于您专门用于使用自定义模型绑定器的 [FromBody] 标签。但它工作正常。只是不是一个“全面”的解决方案,正如我在文章末尾所阐明的那样,在它到达方法之前,它是使用 Newtonsoft 作为管道中的粘合剂。

    /// <summary>
    /// Custom model binder to be used when TrackableEntities coming in HttpPost Methods.
    /// </summary>
    public class TrackableEntityModelBinder : IModelBinder
    {
        /// <inheritdoc/>
        public async Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
            {
                throw new ArgumentNullException(nameof(bindingContext));
            }
    
            using (var reader = new StreamReader(bindingContext.HttpContext.Request.Body))
            {
                var body = await reader.ReadToEndAsync().ConfigureAwait(continueOnCapturedContext: false);
    
                // Do something
                var value = JsonConvert.DeserializeObject(body, bindingContext.ModelType, new JsonSerializerSettings
                {
                    NullValueHandling = NullValueHandling.Ignore,
                    ContractResolver = new CamelCasePropertyNamesContractResolver(),
                    ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
                    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
                });
    
                bindingContext.Result = ModelBindingResult.Success(value);
            }
        }
    }
    

    如前所述,它确实需要更新您要使用它的每个 put/post:

    [HttpPost]
    public async Task<IActionResult> 
    UpdateDati([ModelBinder(typeof(TrackableEntityModelBinder))] [FromBody] 
    Vehicule model)
    {
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-21
      • 2022-01-02
      • 1970-01-01
      • 2021-03-30
      相关资源
      最近更新 更多