SnakeCaseNamingStrategy и JsonPatch в ядре ASP.NET
Есть ли способ зарегистрировать / использовать "глобальный" ContractResolver при использовании пакета ApsNetCore.JsonPatch (2.1.1)?
Я столкнулся с проблемой, когда путь не был решен, потому что свойства в моих моделях находятся в PascalCase, а путь в JsonPatch - в SnakeCase.
В этом случае мне нужно установить ContractResolver для JsonPatchDocument в значение Default/Globally зарегистрированного ContractResolver в файле Startup.cs.
Это работает, но мне придется делать это для каждого патч-маршрута, который я собираюсь реализовать.
Начальная конфигурация:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services
.AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
})
}
контроллер:
[HttpPatch("{id}"]
[Consumes(MediaTypeNames.Application.Json)]
public async Task<IActionResult> Patch(string id,
[FromBody] JsonPatchDocument<Entity> patchEntity)
{
...
patchEntity.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
};
patchEntity.ApplyTo(entity);
...
1 ответ
Похоже, что не существует простого способа повлиять на ContractResolver
который используется при создании экземпляра JsonPatchDocument<T>
, Экземпляры этого класса создаются TypedJsonPatchDocumentConverter
, как этот фрагмент кода показывает:
var container = Activator.CreateInstance(
objectType,
targetOperations,
new DefaultContractResolver());
Здесь ясно, что DefaultContractResolver
жестко закодирован как второй аргумент при создании экземпляра JsonPatchDocument<T>
,
Одним из вариантов решения этой проблемы при использовании ASP.NET Core MVC является использование фильтра действий, который позволяет вносить изменения в любые аргументы, передаваемые в действие. Вот основной пример:
public class ExampleActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext ctx)
{
// Find a single argument we can treat as IJsonPatchDocument.
var jsonPatchDocumentActionArgument = ctx.ActionArguments.SingleOrDefault(
x => typeof(IJsonPatchDocument).IsAssignableFrom(x.Value.GetType()));
// Here, jsonPatchDocumentActionArgument.Value will be null if none was found.
var jsonPatchDocument = jsonPatchDocumentActionArgument.Value as IJsonPatchDocument;
if (jsonPatchDocument != null)
{
jsonPatchDocument.ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
};
}
}
}
ActionExecutingContext
класс, переданный здесь, включает в себя ActionArguments
свойство, которое используется в этом примере, чтобы попытаться найти аргумент типа IJsonPatchDocument
, Если один найден, мы перезаписываем ContractResolver
соответственно.
Чтобы использовать этот новый фильтр действий, вы можете добавить его в контроллер, действие или зарегистрировать его глобально. Вот как зарегистрировать это глобально (есть много ответов для других вариантов, поэтому я не буду углубляться в это здесь):
services.AddMvc(options =>
{
options.Filters.Add(new ExampleActionFilterAttribute());
});