AspNet Core - 控制器级别的输入/输出 JSON 序列化设置

AspNet Core - input/output JSON serialization settings at Controller Level

提问人:ExternalUse 提问时间:5/14/2019 更新时间:9/13/2021 访问量:7871

问:

我的应用程序需要(几乎默认的)JSON 序列化设置:

services.AddMvc()
            .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(options =>
            {
                options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
                options.SerializerSettings.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
                options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
            });

仅对于一个控制器,我需要对两个输入使用不同的命名策略(其中我使用模型绑定和输出[FromBody] myComplexObject

options.SerializerSettings.ContractResolver = new DefaultContractResolver();

我的问题与 Web API 几乎相同:在操作或控制器级别配置 JSON 序列化程序设置,除了我要求 AspNet Core 2.2+,其中不再存在。IControllerConfiguration

Core 2.1+ 等效问题在这里有一个答案:使用 ASP.NET Core 2.1 在控制器上配置输入/输出格式化程序

那里的答案似乎有些零散或不完整——很难想象没有更简单的方法来实现这一目标。 有谁知道如何将 DefaultContractResolver 用于单个控制器中的所有输入和输出?

C# ASP.NET 核心 JSON 序列化

评论


答:

1赞 Samuel Akosile 5/14/2019 #1

对于 Startup.cs 中的全局设置,安装 Newtonsoft.json 后,您将拥有以下

services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
            .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());

对于单个控制器,您可以覆盖下面的全局设置

 public JsonResult GetStates()
    {
        var model = new List<StateObject>();
        if (!string.IsNullOrEmpty(id))
        {
            var schedule = _settingsService.GetStates().ToList();
            return Json(new SelectList(schedule, "StateCode", "Name"), new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() });
        }
        else
            return Json(new SelectList(model, "StateCode", "Name"), new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() });
    }

如果这解决了您的问题,或者您需要进一步的协助,请告诉我。

评论

1赞 ExternalUse 5/14/2019
感谢@Samuel,这解决了输出问题,但不涉及带有参数的 POST 上的 ModelBinding。Startup 类中的全局设置不是一个选项,因为对于大多数其他控制器,默认设置是正确的。只有一个控制器需要[FromBody] objectDefaultContractResolver
0赞 Nainesh Patel 1/21/2020
这样就解决了问题。但是对于每个请求,$id都会被附加。例如,对于第一个请求$id以 1 开头,但对于所有后续请求,$id以 27,55...stackoverflow.com/questions/59832635/......谁能帮我?
9赞 DavidG 5/14/2019 #2

您链接的答案效果很好,但您可以通过将其包装在可应用于任何操作或控制器的属性中来进一步扩展它。例如:

public class JsonConfigFilterAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is ObjectResult objectResult)
        {
            var serializerSettings = new JsonSerializerSettings
            {
                ContractResolver = new DefaultContractResolver()
            };

            var jsonFormatter = new JsonOutputFormatter(
                serializerSettings, 
                ArrayPool<char>.Shared);

            objectResult.Formatters.Add(jsonFormatter);
        }

        base.OnResultExecuting(context);
    }
}

只需将其添加到操作方法或控制器中:

[JsonConfigFilter]
public ActionResult<Foo> SomeAction()
{
    return new Foo
    {
        Bar = "hello"
    };
}

评论

1赞 ExternalUse 5/14/2019
谢谢@DavidG - 这不会处理输入格式化程序,或者会吗?我认为这也是原始问题中缺失的部分。[FromBody] object
0赞 DavidG 5/14/2019
嗯,你可能是对的。在这种情况下,使用自定义模型活页夹可能会更好。
1赞 Kirk Larkin 5/14/2019
@ExternalUse 你试过这个输入端吗?我不认为JSON输入格式化程序太关心请求内部的大小写,因此它应该在进行任何更改和不进行任何更改的情况下工作。它也适用于 - 如果您在 JSON 中提供多个变体,则最后一个变体获胜。SomePropertysomePropertySOMePRoperTY
0赞 ExternalUse 5/14/2019
提供的答案效果很好(谢谢!值得一提的是@KirkLarkin上面的评论。输入滤波器似乎确实忽略了大小写。
0赞 uygar donduran 12/4/2020
我希望在 mvc 配置中添加 mvc OutputFormatters,但它总是空的。 had 参数,该参数添加了所有 MVC outputformatters。这有点不同。objectResult.FormattersIControllerConfiguration.InitializeHttpControllerSettings settings
1赞 Alex from Jitbit 9/13/2021 #3

只需在控制器中覆盖即可Json()

public class MyController : Controller
{
    public override JsonResult Json(object data)
    {
        return base.Json(data, new JsonSerializerSettings {
            // set whataever options you want
        });
    }
}