.NET 5.0中如何为单个控制器配置Newtonsoft Json枚举字符串序列化
你原来两次调用services.AddMvc().AddNewtonsoftJson()的方式行不通,第二次调用会直接覆盖第一次的全局配置,没法实现“两组配置并存”的效果。下面给你几个实用的解决方案:
方案一:自定义JsonResult(最直接省心)
先创建一个专属的JsonResult类型,内置带StringEnumConverter的序列化配置:
using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Newtonsoft.Json.Converters; public class StringEnumJsonResult : JsonResult { // 提前定义好固定配置,避免重复创建 private static readonly JsonSerializerSettings _customSettings = new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Utc, DateFormatHandling = DateFormatHandling.IsoDateFormat, DateFormatString = "yyyy-MM-ddTHH:mm:ssK", Converters = { new StringEnumConverter() } }; public StringEnumJsonResult(object value) : base(value) { SerializerSettings = _customSettings; } }
然后在需要特殊处理的控制器Action里,返回这个自定义结果就行:
public class SpecialController : ControllerBase { [HttpGet] public IActionResult GetData() { var data = new { Status = MyEnum.Active, CreateTime = DateTime.Now }; return new StringEnumJsonResult(data); } }
其他控制器正常用默认的Json()方法,全局配置保持你最初的默认设置:
services.AddMvc().AddNewtonsoftJson(options => { options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; options.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat; options.SerializerSettings.DateFormatString = "yyyy-MM-ddTHH:mm:ssK"; });
方案二:用Action过滤器(不用改Action返回类型)
如果不想改Action的返回写法,可以写个过滤器自动替换序列化配置:
using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Newtonsoft.Json.Converters; public class UseStringEnumSerializationAttribute : ActionFilterAttribute { private static readonly JsonSerializerSettings _customSettings = new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Utc, DateFormatHandling = DateFormatHandling.IsoDateFormat, DateFormatString = "yyyy-MM-ddTHH:mm:ssK", Converters = { new StringEnumConverter() } }; public override void OnResultExecuting(ResultExecutingContext context) { if (context.Result is JsonResult jsonResult) { // 直接替换默认的序列化配置 jsonResult.SerializerSettings = _customSettings; } base.OnResultExecuting(context); } }
接着在目标控制器或者单个Action上标记这个特性:
// 给整个控制器加,里面所有Action都会用字符串枚举序列化 [UseStringEnumSerialization] public class SpecialController : ControllerBase { [HttpGet] public IActionResult GetData() { var data = new { Status = MyEnum.Active, CreateTime = DateTime.Now }; return Json(data); // 还是写默认的Json方法,过滤器会自动处理 } }
全局配置同样保持默认即可。
方案三:注入不同配置的序列化器(灵活度最高)
如果需要更灵活的控制,可以把两组配置都注册到DI容器,然后在控制器里按需取用:
先在Startup.cs里注册两个配置:
// 默认配置 services.AddSingleton<JsonSerializerSettings>(sp => new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Utc, DateFormatHandling = DateFormatHandling.IsoDateFormat, DateFormatString = "yyyy-MM-ddTHH:mm:ssK" }); // 带字符串枚举的配置,给个名字区分 services.AddSingleton<JsonSerializerSettings>("StringEnum", sp => new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Utc, DateFormatHandling = DateFormatHandling.IsoDateFormat, DateFormatString = "yyyy-MM-ddTHH:mm:ssK", Converters = { new StringEnumConverter() } });
然后在目标控制器里注入命名的配置,手动序列化后返回:
public class SpecialController : ControllerBase { private readonly JsonSerializerSettings _stringEnumSettings; // 通过构造函数注入指定名称的配置 public SpecialController([FromKeyedServices("StringEnum")] JsonSerializerSettings stringEnumSettings) { _stringEnumSettings = stringEnumSettings; } [HttpGet] public IActionResult GetData() { var data = new { Status = MyEnum.Active, CreateTime = DateTime.Now }; var json = JsonConvert.SerializeObject(data, _stringEnumSettings); return Content(json, "application/json"); } }
如果.NET 5里[FromKeyedServices]用不了,就封装个工厂类来获取配置:
public class JsonSettingsFactory { private readonly IServiceProvider _serviceProvider; public JsonSettingsFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public JsonSerializerSettings GetDefaultSettings() { return _serviceProvider.GetRequiredService<JsonSerializerSettings>(); } public JsonSerializerSettings GetStringEnumSettings() { return _serviceProvider.GetRequiredService<JsonSerializerSettings>("StringEnum"); } } // 别忘了在Startup.cs注册工厂 services.AddSingleton<JsonSettingsFactory>();
之后控制器注入工厂就行:
public class SpecialController : ControllerBase { private readonly JsonSerializerSettings _stringEnumSettings; public SpecialController(JsonSettingsFactory settingsFactory) { _stringEnumSettings = settingsFactory.GetStringEnumSettings(); } // 后续代码和上面一样 }
内容的提问来源于stack exchange,提问作者ophelia
相关产品推荐
相关产品推荐

