System.Text.Json で文字エンコードをカスタマイズする方法

既定では、シリアライザーでは ASCII 以外のすべての文字がエスケープされます。 つまり、\uxxxx に置き換えられます。xxxx は文字の Unicode コードです。 たとえば、次の JSON の Summary プロパティがキリル文字の жарко に設定されている場合、WeatherForecast オブジェクトは次の例に示すようにシリアル化されます。

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "\u0436\u0430\u0440\u043A\u043E"
}

言語文字セットのシリアル化

1 つ以上の言語の文字セットをエスケープせずにシリアル化するには、次の例に示すように、System.Text.Encodings.Web.JavaScriptEncoder のインスタンスを作成するときに Unicode 範囲を指定します。

using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
Imports System.Text.Encodings.Web
Imports System.Text.Json
Imports System.Text.Unicode
var options1 = new JsonSerializerOptions
{
    Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.Cyrillic),
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options1);
options = New JsonSerializerOptions With {
    .Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.Cyrillic),
    .WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast1, options)

このコードでは、キリル文字やギリシャ文字はエスケープされません。 Summary プロパティがキリル文字の жарко に設定されている場合、WeatherForecast オブジェクトは次の例に示すようにシリアル化されます。

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "жарко"
}

既定では、エンコーダーは BasicLatin 範囲を使用して初期化されます。

すべての言語セットをエスケープせずにシリアル化するには、UnicodeRanges.All を使用します。

特定の文字のシリアル化

別の方法として、エスケープせずに許可する個々の文字を指定することもできます。 次の例では、жарко の最初の 2 文字のみをシリアル化します。

using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
Imports System.Text.Encodings.Web
Imports System.Text.Json
Imports System.Text.Unicode
var encoderSettings = new TextEncoderSettings();
encoderSettings.AllowCharacters('\u0436', '\u0430');
encoderSettings.AllowRange(UnicodeRanges.BasicLatin);
var options2 = new JsonSerializerOptions
{
    Encoder = JavaScriptEncoder.Create(encoderSettings),
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options2);
Dim encoderSettings As TextEncoderSettings = New TextEncoderSettings
encoderSettings.AllowCharacters(ChrW(&H436), ChrW(&H430))
encoderSettings.AllowRange(UnicodeRanges.BasicLatin)
options = New JsonSerializerOptions With {
    .Encoder = JavaScriptEncoder.Create(encoderSettings),
    .WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast1, options)

上記のコードによって生成される JSON の例を次に示します。

{
  "Date": "2019-08-01T00:00:00-07:00",
  "TemperatureCelsius": 25,
  "Summary": "жа\u0440\u043A\u043E"
}

ブロッ クリスト

前のセクションは、エスケープしたくないコード ポイントまたは範囲の許可リストを指定する方法について説明しています。 ただし、許可リスト内の特定のコード ポイントをオーバーライドできるグローバルおよびエンコーダー固有のブロック リストがあります。 ブロック リスト内のコード ポイントは、許可リストに含まれていても、常にエスケープされます。

グローバル ブロック リスト

グローバル ブロック リストには、プライベート用途の文字、制御文字、未定義のコード ポイント、および Space_Separator カテゴリなどの特定の Unicode カテゴリ (U+0020 SPACE を除く) などが含まれます。 たとえば、許可リストとして Unicode 範囲の CJK 記号と句読点 (U+3000 から U+303F) を指定した場合でも、U+3000 IDEOGRAPHIC SPACE はエスケープされます。

グローバル ブロック リストは、.NET のすべてのリリースで変更された実装の詳細です。 グローバル ブロック リストのメンバーである (またはメンバーではない) 文字に依存しないようにしてください。

エンコーダー固有のブロック リスト

エンコーダー固有のブロックされたコード ポイントの例としては、HTML エンコーダー'<''&'JSON エンコーダー'\'URL エンコーダー'%' があります。 たとえば、アンパサンド ('&') が BasicLatin の範囲内にあり、すべてのエンコーダーが BasicLatin を使用して既定で初期化される場合でも、HTML エンコーダーではアンパサンドは常にエスケープされます。

すべての文字のシリアル化

エスケープ処理を最小限にするには、次の例に示すように、JavaScriptEncoder.UnsafeRelaxedJsonEscaping を使用できます。

using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Unicode;
Imports System.Text.Encodings.Web
Imports System.Text.Json
Imports System.Text.Unicode
var options3 = new JsonSerializerOptions
{
    Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
    WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecast, options3);
options = New JsonSerializerOptions With {
    .Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
    .WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast1, options)

注意事項

既定のエンコーダーと比較して、UnsafeRelaxedJsonEscaping エンコーダーは、文字をエスケープせずにそのまま渡すことについて、より寛容です。

  • <>&' など、HTML に影響する文字はエスケープされません。
  • クライアントとサーバーが "文字セット" について合意していない場合の結果など、XSS または情報漏えい攻撃に対する追加の多層防御は提供されません。

安全でないエンコーダーは、クライアントによって結果のペイロードが UTF-8 でエンコードされた JSON として解釈されることがわかっている場合にのみ使用してください。 たとえば、サーバーが応答ヘッダー Content-Type: application/json; charset=utf-8 を送信している場合は使用できます。 未加工の UnsafeRelaxedJsonEscaping 出力が HTML ページまたは <script> 要素に決して出力されないようにしてください。

関連項目