首页 > 解决方案 > ASP.NET Core 中的 SnakeCaseNamingStrategy 和 JsonPatch

问题描述

使用 ApsNetCore.JsonPatch (2.1.1) 包时,有没有办法注册/使用“全局”ContractResolver?

我遇到了路径未解析的问题,因为我的模型中的属性在 PascalCase 中,但 JsonPatch 中的路径在 SnakeCase 中。

在这种情况下,我必须将 JsonPatchDocument 上的 ContractResolver 设置为 Startup.cs 文件中的默认/全局注册的 ContractResolver。

它有效,但我必须为我要实施的每个补丁路由都这样做。

启动配置:

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

标签: c#asp.net-corejson-patch

解决方案


似乎没有简单的方法来影响ContractResolver创建JsonPatchDocument<T>. 此类的实例由 a 创建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());
});

推荐阅读