【问题标题】:Force SnakeCase Deserializing on WebAPI Per Controller在每个控制器的 WebAPI 上强制 SnakeCase 反序列化
【发布时间】:2018-05-09 03:26:13
【问题描述】:

我想仅为我的一个控制器更改传入请求的反序列化格式。所以我把它添加到我的Global.asax 中,它工作得很好:

HttpConfiguration config = GlobalConfiguration.Configuration;
config.Formatters.JsonFormatter.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings
{
    ContractResolver = new DefaultContractResolver
    {
        NamingStrategy = new SnakeCaseNamingStrategy()
    }
};

但它将更改应用于所有控制器。我只想将它应用于我的一个控制器。我还找到了this 的答案,我根据那个写了这段代码:

public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
{
    var formatter = controllerSettings.Formatters.OfType<JsonMediaTypeFormatter>().Single();
    controllerSettings.Formatters.Remove(formatter);

    formatter = new JsonMediaTypeFormatter
    {
        SerializerSettings = { ContractResolver = new DefaultContractResolver { NamingStrategy = new SnakeCaseNamingStrategy() } }
    };

    controllerSettings.Formatters.Add(formatter);
}

但不幸的是,它仅适用于序列化输出。有没有办法定义它来反序列化输入?

【问题讨论】:

    标签: c# asp.net-web-api serialization json.net asp.net-web-api2


    【解决方案1】:

    您可以使用复杂的媒体类型格式化程序来做您需要的事情。通常自定义格式化程序会覆盖方法CanReadType()/CanWriteType() 和ReadFromStreamAsync()/WriteToStreamAsync()。 CanWriteType() 在您的情况下应始终返回 false,因为您对自定义序列化不感兴趣。至于反序列化,您可以使用标准JsonMediaTypeFormatter(通过继承或聚合)并将其SerializerSettings 设置为使用SnakeCaseNamingStrategy:

    public class SnakeCaseJsonFormatter : JsonMediaTypeFormatter
    {
        public SnakeCaseJsonFormatter()
        {
            SerializerSettings = new JsonSerializerSettings
            {
                ContractResolver = new DefaultContractResolver
                {
                    NamingStrategy = new SnakeCaseNamingStrategy()
                }
            };
        }
    
        public override bool CanWriteType(Type type)
        {
            return false;
        }
    
        public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext)
        {
            throw new NotImplementedException();
        }
    }
    

    剩下的部分是在控制器级别应用这种自定义格式化程序。您可以使用实现IControllerConfiguration 接口的自定义属性来做到这一点。在Initialize() 方法中,将您的自定义格式化程序设置在第一个位置,以便它优先于标准JsonMediaTypeFormatter。你不应该删除标准的JsonMediaTypeFormatter,因为它会处理数据序列化:

    public sealed class SnakeCaseNamingAttribute : Attribute, IControllerConfiguration
    {
        public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
        {
            controllerSettings.Formatters.Insert(0, new SnakeCaseJsonFormatter());
        }
    }
    

    现在只需将此属性应用到您想要的控制器上,瞧:

    [SnakeCaseNaming]
    public class ValuesController : ApiController
    

    【讨论】:

    • 非常感谢亲爱的@CodeFuller。我完全按照您发布的内容做了,但是没有用!!你测试过代码吗?我想我们错过了什么。
    • 是的,我已经检查过了,它对我有用。现在到底什么不起作用?您是否在您尝试过的其他地方删除了对 SerializerSettings 的自定义?
    • SnakeCaseNamingStrategy 不适用于我的输入。我没有删除蚂蚁的东西。我刚刚创建了两个类(SnakeCaseJsonFormatter 和 SnakeCaseNamingAttribute)并将该属性应用到我的控制器上。我可以发布我的代码,但我想它很明显。
    • 当我在全局类中添加 SnakeCaseNamingStrategy 时,它会将属性名称更改为蛇形大小写。例如 FirstName 成为名字。但是当我在控制器上添加你的属性时。它没有改变任何东西。
    • 尝试在SnakeCaseNamingAttribute.Initialize() 和SnakeCaseJsonFormatter 构造函数中设置断点。他们叫吗?
    猜你喜欢
    • 2013-11-26
    • 2016-08-31
    • 2022-06-30
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 2017-05-13
    • 1970-01-01
    相关资源
    最近更新 更多