ASP.NET Webアプリケーションで text/plain レスポンスで日本語(マルチバイト)の文字列を返すと表示が文字化けする現象について紹介します。
概要
ASP.NET WebアプリケーションでHTMLではなく text/plain のテキスト形式のレスポンスを返すWebアプリケーションを作成し、
レスポンスに日本語の文字列(マルチバイト文字列)が含まれると、日本語の表示が文字化けして表示されることがあります。
動作の確認
ASP.NET Webアプリケーション(.NET 5)を作成し、下記のコードを記述します。
処理はシンプルでASP.NET Webアプリケーションのアプリケーションルートにアクセスすると、 "Hello World!\r\n" と "こんにちは、ASP.NETの世界へ!\r\n"
の文字列を返すアプリケーションです。
文字列を返すだけのため、レスポンスはHTMLではなく、無指定、あるいは
text/plain
となります。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TextPlainResponse
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!\r\n");
await context.Response.WriteAsync("こんにちは、ASP.NETの世界へ!\r\n");
});
});
}
}
}
上記のプロジェクトを実行します。Webブラウザを起動しアプリケーションルートのURLにアクセスします。
下図の画面が表示されます。日本語の文字列「こんにちは、ASP.NETの世界へ!」が文字化けして表示されることが確認できます。
原因
ASP.NET WebアプリケーションのWriteAsyncの出力はデフォルトでは、UTF-8 で出力されます。
一方、Google ChromeやMicrosoft Edge などのWebブラウザでは、レスポンスの指定がない場合、コンテンツをShift-JISとして扱うため、
UTF-8のレスポンスをShift-JISとして画面に表示する動作になり、文字化けが発生します。
上記のプロジェクトのレスポンスヘッダを確認すると、content-typeヘッダはなく、何も指定が無いことが確認できます。
対処法
以下の対処法があります。
- content-type ヘッダを設定しレスポンスを UTF-8 エンコーディングされているコンテンツとして処理する
- ASP.NET Webアプリケーションの日本語(マルチバイト文字列)の出力をShift-JISにする
対策後のプログラム : Content-Type ヘッダを設定
レスポンスヘッダに content-type フィールドを追加し、MIME Type, charset を指定してUTF-8のコンテンツであることを
明示して文字化けしないようにする対処方法です。
コード
以下のコードを記述します。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TextPlainResponse
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
context.Response.ContentType = "text/plain; charset=utf-8";
await context.Response.WriteAsync("Hello World!\r\n");
await context.Response.WriteAsync("こんにちは、ASP.NETの世界へ!\r\n");
});
});
}
}
}
解説
以下のコードにより、レスポンスヘッダの content-type ヘッダにMIME Typeとcharset(エンコーディング)を設定しています。
このコードにより、レスポンスコンテンツをUTF-8でエンコーディングされた文字列として処理します。
context.Response.ContentType = "text/plain; charset=utf-8";
実行結果
上記のプロジェクト実行し、Webブラウザでアプリケーションルートにアクセスします。
下図の画面が表示されます。文字化けせずにレスポンスの文字列が表示できています。
レスポンスヘッダの値を確認します。レスポンスヘッダに
content-type
ヘッダがあります。
ContentType の値は
text/plain; charset=utf-8
が設定されており、レスポンスのエンコーディングはUTF-8であることが明示されています。
この設定により、文字化けせずに日本語の文字列(マルチバイト文字列)が表示されます。
対策後のプログラム : Shift-JIS のレスポンスを返す
ASP.NET アプリケーションのレスポンスの日本語(マルチバイト)文字列をShift-JISとしてレスポンスする方法です。
コード
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TextPlainResponse
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
System.Text.Encoding sjisEncoding = System.Text.Encoding.GetEncoding("SHift-JIS");
await context.Response.WriteAsync("Hello World!\r\n");
await context.Response.WriteAsync("こんにちは、ASP.NETの世界へ!\r\n", sjisEncoding);
});
});
}
}
}
解説
Shift-JISのEncoding オブジェクトを取得します。.NET Framework の場合は、GetEncoding のみでEncodingオブジェクトを取得できましたが、
.NET 5 (.NET Core)の場合は、エンコーディングプロバイダを追加しておく必要があります。詳しくは
こちらの記事を参照してください。
RegisterProvider()
メソッドを呼び出し、CodePagesEncodingProvider を追加した後に、
GetEncoding("Shift-JIS")
メソッドを呼び出すと
Shift-JISのEncoding オブジェクトを取得できます。
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
System.Text.Encoding sjisEncoding = System.Text.Encoding.GetEncoding("SHift-JIS");
レスポンスの出力は先のプログラムと同様です。マルチバイト文字列の出力の
WriteAsync()
メソッドには第二引数にエンコードするEncodingオブジェクトを与えています。
Shift-JISのEncodingオブ絵ジェクトを与えているため、日本語の文字列はShift-JISエンコーディングされてクライアントに送信されます。
await context.Response.WriteAsync("Hello World!\r\n");
await context.Response.WriteAsync("こんにちは、ASP.NETの世界へ!\r\n", sjisEncoding);
表示結果
上記のプロジェクトを実行し、WebアプリケーションルートのURLにアクセスします。
下図の画面が表示されます。文字化けせずにレスポンスの文字列が表示できています。
レスポンスヘッダの値を確認します。レスポンスヘッダに
content-type
ヘッダはありません。
レスポンスコンテンツのエンコーディングがShift-JISのため、文字化けせずに画面に表示されます。
著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2021-07-16
作成日: 2021-07-15