在每个控制器的 WebAPI 上强制 SnakeCase 反序列化

Force SnakeCase Deserializing on WebAPI Per Controller

我只想为我的一个控制器更改传入请求的反序列化格式。所以我将其添加到我的 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);
}

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

您可以使用棘手的媒体类型格式化程序来完成所需的工作。通常自定义格式化程序会覆盖方法 CanReadType() / CanWriteType()ReadFromStreamAsync() / WriteToStreamAsync()CanWriteType() 在你的情况下应该总是 return 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