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