SnakeCaseNamingStrategy и JsonPatch в ядре ASP.NET - PullRequest
0 голосов
/ 19 сентября 2018

Есть ли способ зарегистрировать / использовать "глобальный" 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 Ответ

0 голосов
/ 19 сентября 2018

Похоже, что нет простого способа повлиять на ContractResolver, который используется при создании экземпляра JsonPatchDocument<T>.Экземпляры этого класса создаются с помощью TypedJsonPatchDocumentConverter, как показано в следующем фрагменте кода:

var container = Activator.CreateInstance(
    objectType,
    targetOperations,
    new DefaultContractResolver());

Здесь ясно, что DefaultContractResolver жестко задан в качестве второго аргумента при создании экземпляра.из JsonPatchDocument<T>.

Один из вариантов решения этой проблемы при использовании ASP.NET Core MVC - это использование Action Filter , который позволяет вносить изменения в любые аргументы, передаваемые вдействие.Вот базовый пример:

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());
});
...