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

6

我的应用程序需要(几乎是默认的)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处理所有输入和输出?
3个回答

9

你链接的答案已经足够好了,但是你可以进一步将它包装在一个属性中,以便你可以应用到任何操作或控制器上。例如:

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
感谢@DavidG-那不会处理[FromBody] object的输入格式化程序,对吗?我认为这也是原始问题中缺少的部分。 - ExternalUse
1
@ExternalUse 你尝试过输入端吗?我认为JSON输入格式化程序不太关心请求内部的大小写,因此SomePropertysomeProperty应该可以在不进行任何更改的情况下工作。它还可以使用SOMePRoperTY - 如果您在JSON中提供多个变体,则最后一个获胜。 - Kirk Larkin
.NET Core版本的操作过滤器:https://stackoverflow.com/a/73866496/379279 - xhafan
@xhafan 这已经是一个.NET Core版本了。你的代码只是实现了较低级别的接口。 - DavidG
@DavidG 好的,我现在记得了 - 我需要为所有控制器添加一些东西,感谢您的澄清。 - xhafan
显示剩余3条评论

1

只需在您的控制器中重写 Json() 方法

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

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
谢谢@Samuel,这解决了输出问题,但没有解决使用[FromBody] object参数进行POST的ModelBinding问题。在Startup类中的全局设置不是一个选项,因为对于大多数其他控制器,缺省设置是正确的。只有一个控制器需要DefaultContractResolver - ExternalUse
这种方法解决了问题。 但是对于每个请求,$id都会被附加。例如, 对于第一个请求,$id从1开始,但对于所有后续请求,$id从27、55等开始。https://dev59.com/DLjoa4cB1Zd3GeqPD8P4有人能帮我吗? - Nainesh Patel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接