WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

ASP.NET Core MVC の JSON シリアライズ

by WebSurfer 11. March 2020 14:40

ASP.NET Core 3.1 MVC の Controller.Json メソッドを使って .NET オブジェクトを JSON 文字列にシリアライズすると日本語の文字は Unicode Escape Sequence (以下 UES と書きます) という形にエスケープされます。

JSON 文字列

UES というのは \uxxxx という形で表される Unicode 文字で、xxxx はその文字の Unicode コードになります。以下に、UES になる理由と、UES ではなく UTF-8 で(即ち、エスケープしないで)JSON 文字列に出力する方法を書きます。

UES となる理由はシリアライザでエスケープ処理が行われているからのようで、日本語の文字に限らず非 ASCII 文字は全てデフォルトで UES になるそうです。そのことは Microsoft のドキュメント Customize character encoding に書いてありました。

ちなみに ASP.NET Core 3.1 Web API では UES にはならず、日本語の文字も UTF-8 で出力されます。何故 MVC と Web API で違う結果になるのかは不明です。(たぶん、MVC では HtmlEncode、JavaScriptEncode、UrlEncode の 3 つのエンコーダーすべてでエスケープされるようになっている、Web API では以下のサンプルコードのように BMP の文字はエスケープ対象から外す設定になっているからではなかろうかと想像しています)

日本語の文字も UES ではなく UTF-8 で出力する、即ちエスケープされないように設定するにはどうするかを以下に書きます。

Controller.Json メソッドには第 2 引数に JsonSerializerOptions クラスを設定するオーバーロードがありますが、その JsonSerializerOptions.Encoder プロパティでエスケープ対象から外す文字の設定が可能なようです。

アクションメソッド単位で JsonSerializerOptions を設定する方法は Microsoft のドキュメント Configure System.Text.Json-based formatters を参照してください。具体的には以下のサンプルコードのように設定します。

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using WebAPI.Data;
using Microsoft.EntityFrameworkCore;

// エスケープ回避を設定するため追加
using System.Text.Json;
using System.Text.Encodings.Web;
using System.Text.Unicode;

namespace WebAPI.Controllers
{
  public class HomeController : Controller
  {
    private readonly BloggingContext _context;

    public HomeController(BloggingContext context)
    {
      _context = context;
    }

    public async Task<IActionResult> Json()
    {
      // Core は遅延ローディングが働かないので注意
      var list = await _context.Blogs.
                       Include(b => b.Posts).ToListAsync();

      // BMP 全てをエスケープしないよう設定
      // (WriteIndented はオマケ)
      return Json(list, new JsonSerializerOptions
      {
        Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
        WriteIndented = true,
      });
    }
  }
}

上のコードでは、JavaScriptEncoder.Create(UnicodeRange[]) メソッドの引数に UnicodeRanges クラスの All プロパティを渡して BMP(Basic Multilingual Plane・・・U+0000 から U+FFFF の範囲)の文字をエスケープ対象から外すように設定しています。

結果は以下のようになります。

JSON 文字列

なお、UnicodeRanges クラスの説明では、"現時点では、UnicodeRange クラスでサポートされているのは、基本多言語面 (BMP) の名前付き範囲のみです" とのことですので注意してください。

上のサンプルコードのように BMP 全てをエスケープしないよう設定しても、例えば 𠀋 という文字 (u2000b) は BMP にありませんが、それを JSON にシリアライズすると、 \uD840\uDC0B (サロゲートペアの形) になります。Web API でも同じです。

Tags: , , , ,

CORE

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  July 2020  >>
MoTuWeThFrSaSu
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

View posts in large calendar