.NET CORE:不同控制器中 json 主体反序列化的行为不一致

问题描述

.NET CORE 3.1 中构建 API,我需要验证 json 主体并将其反序列化为自定义类。 我为我的一个控制器所做的工作:

using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;

namespace MyNS
{
    [JsonObject]
    public class SearchAAA
    {
        [JsonProperty("query",required=required.Always)]
        public Query Query { get; set; }
    }

    public class Query
    {
        [JsonProperty("and",required=required.Always)]
        public List<And> And { get; set; }
    }

    public class And
    {
        [JsonProperty("property",required = required.Always)]
        public string Property { get; set; }

        [JsonProperty("operator",required = required.Always)]
        public string Operator { get; set; }

        [JsonProperty("value",required = required.Always)]
        public object Value { get; set; }
    }
}

接受的 json 应具有以下结构:

{
  "query": {
    "and": [      
      {
          "operator": "eq","property": "prop1","value": "value1"
      }
    ]
  }
}

Controller1.cs

[Route("/v1/aaa/search")]
[HttpPost]
public async Task<JsonResult> Search(SearchAAA data)
{
    foreach (var q in data.Query.And)
    {
        // ...
    }

}

为了处理无效的 json,我在 Startup.cs添加了以下内容

public void ConfigureServices(IServiceCollection services)
{
    // [...]

    services.AddControllers()
        .AddNewtonsoftJson(options => {
            //options.AllowInputFormatterExceptionMessages = false;
        })
        .ConfigureApiBehaviorOptions(options => {
            options.InvalidModelStateResponseFactory = context =>
            {
                string errorMessage = "Validation error";

                foreach (var key in context.ModelState.Keys)
                {
                    if (context.ModelState[key].Errors.Count > 0)
                    {
                        errorMessage = string.Format("Json property '{0}': {1}",key,context.ModelState[key].Errors[0].ErrorMessage);
                        break;
                    }
                }

                int statusCode = (int)HttpStatusCode.BadRequest;

                var dto = new
                {
                    success = false,error = errorMessage
                };

                return new JsonResult(dto) { StatusCode = statusCode };
            };
        });

    services.AddAuthorization();

    // [...]
}

这似乎有效,如果我发送无效的 json,我会收到如下示例所示的错误响应:

POST /v1/aaa/search
{
  "query": {
    "joker": [      
      {
          "operator": "eq","value": "value1"
      }
    ]
  }
}

RESPONSE [400]
{
    "success": false,"error": "Json property 'query.and': required property 'and' not found in JSON. Path 'query',line 10,position 3."
}

我正在尝试在新控制器中做同样的事情(需要将不同的 json 反序列化为不同的类对象)。无论出于何种原因我无法解释,都不会触发验证。使用调试器我只能看到无效的 json 将导致一个空的 data 字段,但 InvalidModelStateResponseFactory 没有被调用。我还注意到,在新控制器中(虽然与第一个基本相同),我需要添加一个 [FromBody] 属性以正确反序列化(而在第一个控制器中这不是必需的)。

using System;
using System.Linq;
using System.Collections.Generic;
using Newtonsoft.Json;
using Microsoft.AspNetCore.Mvc;

namespace MyNS
{
    [JsonObject]
    public class SearchBBB
    {
        [JsonProperty("fields",required=required.Always)]
        public List<Field> Fields { get; set; }
    }

    public class Field
    {
        [JsonProperty("property",required = required.Always)]
        public string Property { get; set; }

        [JsonProperty("value",required = required.Always)]
        public object Value { get; set; }
    }
}

Controller2.cs

[Route("/v1/bbb/search")]
[HttpPost]
public async Task<JsonResult> Search([FromBody] SearchBBB data)
{
    foreach (var field in data.Fields)
    {
        // ...
    }

}

即使我尝试在第二个控制器中重用类 SearchAAA,我也不会收到验证错误

Controller2.cs

[Route("/v1/bbb/search")]
[HttpPost]
public async Task<JsonResult> Search(SearchAAA data)
{
    // ...
}

在我看来,对于同一应用程序的不同控制器,它应该以相同的方式工作,但事实并非如此。知道为什么吗?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)