web-dev-qa-db-ja.com

単一のASP.NET CoreコントローラーのJSONシリアル化設定を変更する

2つのコントローラーコントローラーがあります:ControllerAControllerB。各コントローラーの基本クラスはControllerです。

ControllerAは、デフォルトの形式(camelCase)でJSONを返す必要があります。 ControllerBは、snake_caseという別のJSON形式でデータを返す必要があります。

これをASP.NET Core 3.xおよび2.1に実装するにはどうすればよいですか?

私はstartupを試してみました:

services
    .AddMvc()
    .AddJsonOptions(options =>
    {
        options.SerializerSettings.Converters.Add(new StringEnumConverter());
        options.SerializerSettings.ContractResolver = new DefaultContractResolver()
        {
            NamingStrategy = new SnakeCaseNamingStrategy()
        };
    })
    .AddControllersAsServices();

ただし、これにより、ControllerBだけでなく、allコントローラのシリアル化が変更されます。 1つのコントローラーに対してこの機能を構成または注釈を付けるにはどうすればよいですか?

18
Kees C. Bakker

Action FilterOutput Formatter の組み合わせでこれを実現できます。アクションフィルターの例を次に示します。

public class SnakeCaseAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext ctx)
    {
        if (ctx.Result is ObjectResult objectResult)
        {
            objectResult.Formatters.Add(new JsonOutputFormatter(
                new JsonSerializerSettings
                {
                    ContractResolver = new DefaultContractResolver
                    {
                        NamingStrategy = new SnakeCaseNamingStrategy()
                    }
                },
                ctx.HttpContext.RequestServices.GetRequiredService<ArrayPool<char>>()));
        }
    }
}

OnActionExecutedを使用すると、コードは対応するアクションの後に実行され、最初に結果がObjectResult(継承によりOkObjectResultにも適用される)かどうかを確認します。 ObjectResultの場合、フィルターはJsonOutputFormatterを使用してプロパティをシリアル化する SnakeCaseNamingStrategy のカスタマイズバージョンを追加するだけです。 JsonOutputFormatterコンストラクターの2番目のパラメーターは、DIコンテナーから取得されます。

このフィルターを使用するには、関連するコントローラーに適用するだけです。

[SnakeCase]
public class ControllerB : Controller { }

ASP.NET Core 3.0以降の更新

3.0以降の場合、外観は少し異なります。3.0以降のデフォルトのJSONフォーマッターは、System.Text.Jsonに基づいています。これを書いている時点では、これらは ヘビの場合の命名戦略に対する組み込みサポートはありません です。

ただし、Json.NETを3.0以降で使用している場合(詳細は docs にあります)、上記のSnakeCaseAttributeはまだ実行可能ですが、いくつかの変更点があります。

  1. JsonOutputFormatterNewtonsoftJsonOutputFormatterになりました。
  2. NewtonsoftJsonOutputFormatterコンストラクターには、MvcOptionsの引数が必要です。

これがコードです:

public class SnakeCaseAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext ctx)
    {
        if (ctx.Result is ObjectResult objectResult)
        {
            objectResult.Formatters.Add(new NewtonsoftJsonOutputFormatter(
                new JsonSerializerSettings
                {
                    ContractResolver = new DefaultContractResolver
                    {
                        NamingStrategy = new SnakeCaseNamingStrategy()
                    }
                },
                ctx.HttpContext.RequestServices.GetRequiredService<ArrayPool<char>>(),
                ctx.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>().Value));
        }
    }
}

注:たとえば、JsonOutputFormatter/NewtonsoftJsonOutputFormatterをどこかで事前に作成することをお勧めします。これは、手元の質問の副次的なものなので、例ではそれほど進んでいません。

16
Kirk Larkin

エンドポイントで使用するこのメソッドを作成することになりました:

{           
    // needed to get the same date and property formatting 
    // as the Search Service:
    var settings = new JsonSerializerSettings
    {
        ContractResolver = new DefaultContractResolver()
        {
            NamingStrategy = new SnakeCaseNamingStrategy()
        },
        DateFormatString = "yyyy-MM-ddTHH:mm:ss.fffZ"
    };

    return Json(result, settings);
}
0
Kees C. Bakker