无法在 Web api 配置中设置自定义合同解析器
Posted
技术标签:
【中文标题】无法在 Web api 配置中设置自定义合同解析器【英文标题】:Cannot set a custom contract resolver in web api configuration 【发布时间】:2021-06-27 17:44:32 【问题描述】:如何在 web api 配置中设置自定义合同解析器?我的代码相对较新,到目前为止还没有自定义合约解析器。
除了路由,我没有添加其他自定义。
我尝试了三种不同的方法,但都没有奏效:
public static void Register(HttpConfiguration config)
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/controller/action/id",
defaults: new id = RouteParameter.Optional
);
//attempt 1
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CustomContractResolver();
//attempt 2
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CustomContractResolver();
//attempt 3
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
ContractResolver = new CustomContractResolver()
;
自定义合约解析器代码,调试时断点永远不会到达这里:
public class CustomContractResolver : CamelCasePropertyNamesContractResolver
protected override string ResolvePropertyName(string propertyName)
var regex = new Regex(@"([_])(\w)");
if (regex.IsMatch(propertyName))
var result = regex.Replace(propertyName.ToLower(), (match) => return match.Groups[2].Value.ToUpper(); );
return result;
else
return base.ResolvePropertyName(propertyName);
有什么遗漏吗?
编辑 1:
我正在使用 ASP.NET WebApi 5.2.1 和 MVC 5.2.7、JSON.NET (Newtonsoft.Json) v13.0.1(并且已经尝试过旧的 v12)
我的 Global Asax 也很简单:
public class MvcApplication : System.Web.HttpApplication
protected void Application_Start()
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register); //<- web api configuration
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes); //<- mvc configuration
BundleConfig.RegisterBundles(BundleTable.Bundles);
MVC RouteConfig 类:
public class RouteConfig
public static void RegisterRoutes(RouteCollection routes)
routes.IgnoreRoute("resource.axd/*pathInfo");
routes.IgnoreRoute("resource.ashx/*pathInfo");
routes.MapRoute(
name: "Default",
url: "controller/action/id",
defaults: new controller = "Home", action = "Index", id = UrlParameter.Optional
);
编辑 2
这里是一些测试 web api 控制器:
using System.Web.Http;
namespace Kronos.Web.Geolocalizacao.Controllers.Api
public class TestController : ApiController
[HttpGet]
public TestModel Obtain()
return new TestModel CODE_IDENTIFICATION = 1, DEFAULT_DESCRIPTION = "TEST DAT THING" ;
public class TestModel
public decimal CODE_IDENTIFICATION get; set;
public string DEFAULT_DESCRIPTION get; set;
使用 Tabbed Postman chrome 插件进行测试
Postman tests
【问题讨论】:
您的问题是asp.net-web-api 还是asp.net-mvc-5?他们使用不同的序列化程序,并且使用的序列化程序随版本而变化,所以请edit您的问题具体说明您使用的是哪个版本和设置? 如果是 MVC,请注意 asp.net-mvc-5 已经很老了,第一个版本是在 2013 年发布的。它默认不使用 Json.NET。如果您想在 MVC5 中使用 Json.NET 进行序列化,请参阅Setting the default JSON serializer in ASP.NET MVC。如果你想将它用于模型绑定,请查看How to use Json.NET for JSON modelbinding in an MVC5 project?。 我同时使用 asp net mvc 5 和 asp net web api,.net framework 4.8 【参考方案1】:您的问题与您注册全局设置的方式无关——根据this question,设置config.Formatters.JsonFormatter.SerializerSettings.ContractResolver
是正确的。您的问题是 Json.NET 在合同解析器也有 NamingStrategy
时不会调用 ResolvePropertyName()
- 而您的基类 CamelCasePropertyNamesContractResolver
确实有命名策略。
这可以通过检查当前Json.NET reference source for DefaultContractResolver.SetPropertySettingsFromAttributes()
来验证:
if (namingStrategy != null) property.PropertyName = namingStrategy.GetPropertyName(mappedName, hasSpecifiedName); else property.PropertyName = ResolvePropertyName(mappedName);
损坏的演示小提琴 #1 here。
如果我只是将您的CustomContractResolver
修改为从DefaultContractResolver
继承(默认情况下为空NamingStrategy
),那么它可以工作:
public class CustomContractResolver : DefaultContractResolver
readonly NamingStrategy baseNamingStrategy = new CamelCaseNamingStrategy();
protected override string ResolvePropertyName(string propertyName)
var regex = new Regex(@"([_])(\w)");
if (regex.IsMatch(propertyName))
var result = regex.Replace(propertyName.ToLower(), (match) => return match.Groups[2].Value.ToUpper(); );
return result;
else
return baseNamingStrategy.GetPropertyName(propertyName, false);
修复了演示小提琴 #2 here。
但是,更简洁的解决方案是将自定义合同解析器替换为自定义命名策略:
public class CustomNamingStrategy : CamelCaseNamingStrategy
public CustomNamingStrategy() : base()
public CustomNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames) : base(processDictionaryKeys, overrideSpecifiedNames)
public CustomNamingStrategy(bool processDictionaryKeys, bool overrideSpecifiedNames, bool processExtensionDataNames) : base(processDictionaryKeys, overrideSpecifiedNames, processExtensionDataNames)
readonly Regex regex = new Regex(@"([_])(\w)");
protected override string ResolvePropertyName(string name)
if (regex.IsMatch(name))
var result = regex.Replace(name.ToLower(), (match) => return match.Groups[2].Value.ToUpper(); );
return result;
return base.ResolvePropertyName(name);
然后像这样在设置中进行配置:
settings.ContractResolver = new DefaultContractResolver
// Set the constructor parameters as per your preference. These values are consistent with CamelCasePropertyNamesContractResolver
NamingStrategy = new CustomNamingStrategy(processDictionaryKeys: true, overrideSpecifiedNames: true),
;
演示小提琴#3 here.
【讨论】:
以上是关于无法在 Web api 配置中设置自定义合同解析器的主要内容,如果未能解决你的问题,请参考以下文章
如何从 java api 在 keycloak 中设置自定义用户属性
在 Google Maps api v2 中设置自定义 InfoWindow 的宽度
在 AFNetworking 2.x 中设置自定义标头后,RESTful API 未接收到参数