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

Posted

技术标签:

【中文标题】AspNet Core - 控制器级别的输入/输出 JSON 序列化设置【英文标题】:AspNet Core - input/output JSON serialization settings at Controller Level 【发布时间】:2019-10-01 07:25:09 【问题描述】:

我的应用程序需要(几乎是默认的)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: Configure JSON serializer settings on action or controller level 几乎相同,但我要求的是 AspNet Core 2.2+,其中 IControllerConfiguration 已不存在。

Core 2.1+ 等效问题在这里有一个回复:Configure input/output formatters on controllers with ASP.NET Core 2.1

那里的答案似乎有些零散或不完整 - 很难想象没有更简单的方法可以实现这一目标。 有人知道如何在单个控制器中对所有输入和输出使用 DefaultContractResolver 吗?

【问题讨论】:

【参考方案1】:

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

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"
    ;

【讨论】:

感谢@DavidG - 不过,它不会处理[FromBody] object 的输入格式化程序,还是会这样?我认为这也是原始问题中缺少的部分。 嗯,你可能是对的。在这种情况下,使用自定义模型绑定器可能会更好。 @ExternalUse 你试过这个的输入端吗?我认为 JSON 输入格式化程序不太关心请求中的大小写,因此它应该与 SomePropertysomeProperty 一起使用而无需任何更改。它也适用于 SOMePRoperTY - 如果您在 JSON 中提供多种变体,则最后一个获胜。 提供的答案很好用(谢谢!);值得注意的是上面@KirkLarkin 的评论。输入过滤器确实似乎忽略了大小写。 我希望objectResult.Formatters 包含在 mvc 配置中添加的 mvc OutputFormatters,但它始终为空。 IControllerConfiguration.InitializeHttpControllerSettings settings 参数,其中添加了所有 mvc 输出格式化程序。这有点不同。【参考方案2】:

对于 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() );
    

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

【讨论】:

感谢@Samuel,它解决了输出问题,但与带有[FromBody] object 参数的 POST 上的 ModelBinding 无关。 Startup 类中的全局设置不是一个选项,因为对于大多数其他控制器,默认设置是正确的。只有一个控制器需要DefaultContractResolver 这样就解决了问题。但是对于每个请求, $id 都会被附加。例如,对于第一个请求,$id 以 1 开头,但对于所有后续请求,$id 以 27,55 开头...***.com/questions/59832635/… 有人可以帮我吗?【参考方案3】:

只需覆盖控制器中的Json()

public class MyController : Controller

    public override JsonResult Json(object data)
    
        return base.Json(data, new JsonSerializerSettings 
            // set whataever options you want
        );
    

【讨论】:

以上是关于AspNet Core - 控制器级别的输入/输出 JSON 序列化设置的主要内容,如果未能解决你的问题,请参考以下文章

Swashbuckle.AspNet.Core:Swagger UI 显示空白页面 - 如何修复?

无法通过 CORS 将 JSON 发布到 ASPNET Core(415 - 不支持的媒体类型)

EF Core 入门

sqlmap

提升日志记录集输出级别

Microsoft.AspNet.WebApi.Core 和过时的库