by WebSurfer
2025年3月14日 13:57
.NET アプリにおいて Encoding.GetEncoding メソッドで Shift_JIS のエンコーディングを取得しようとすると、以下の画像のように ArgumentException 例外がスローされます。

これは、.NET では特定の OS に依存する機能はサポートされてないので、Shift_JIS に限らず Windows OS のコードページの中の特定の locale のエンコーディングはデフォルトでは使えないということのようです。(注: .NET Framework ではデフォルトで Windows コードページの大多数のエンコーディングが使えます)
サポートされているエンコーディングは Encoding.GetEncodings メソッドで取得できます。.NET 8.0 の場合、自分の環境で試すと以下の 7 種類になっていました。
-
ASCII (code page 20127)
-
UTF-8 (code page 65001)
-
UTF-16LE (code page 1200)
-
UTF-16BE (code page 1201)
-
UTF-32LE (code page 12000)
-
UTF-32BE (code page 12001)
-
ISO-8859-1 (code page 28591)
UTF-7 も含まれるというMicrosoft のドキュメントを目にしましたが "The UTF-7 encoding is insecure and should not be used." ということで除外されたようです。
では、.NET アプリで上の一覧にないエンコーディングを Encoding.GetEncoding メソッドで取得して使うにはどうするかですが、それについては Microsoft のドキュメント「EncodingProvider クラス」に説明があります。それを参考に以下に Shift_JIS を使う場合の例を書きます。
(1) プロバイダクラスを定義
抽象クラス EncodingProvider を継承したプロバイダクラスを定義します。この例では、プロバイダクラスの名前を ShiftJisEncodingProvider とします。
ShiftJisEncodingProvider クラスで、 継承した抽象クラス EncodingProvider の抽象メソッド GetEncoding(Int32) と GetEncoding(String) を override し、Shift_JIS エンコーディングを返すようにします。
Shift_JIS エンコーディングは CodePagesEncodingProvider クラスのインスタンスから取得します。
ShiftJisEncodingProvider クラスのコード例は以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | using System.Text;
public class ShiftJisEncodingProvider : EncodingProvider
{
public override Encoding? GetEncoding( int codepage)
{
var provider = CodePagesEncodingProvider.Instance;
if (codepage == 932)
{
return provider.GetEncoding(932);
}
return null ;
}
public override Encoding? GetEncoding( string name)
{
var provider = CodePagesEncodingProvider.Instance;
if (name.Equals( "shift_jis" , StringComparison.CurrentCultureIgnoreCase))
{
return provider.GetEncoding( "shift_jis" );
}
return null ;
}
}
|
(2) ShiftJisEncodingProvider の登録
ShiftJisEncodingProvider のインスタンスを Encoding.RegisterProvider メソッド に渡して、.NET アプリで Shift_JIS エンコーディングを取得できるようにします。
(3) Shift_JIS エンコーディングの取得
.NET アプリでは Encoding.GetEncoding メソッドを使って Shift_JIS エンコーディングを取得します。ステップ (2) と (3) のコード例は以下の通りです。コメントの結果に示すように期待通り Shift_JIS エンコーディングが取得できています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | using System.Text;
namespace ConsoleApp4
{
internal class Program
{
static void Main( string [] args)
{
var provider = new ShiftJisEncodingProvider();
Encoding.RegisterProvider(provider);
var sjis = Encoding.GetEncoding( "shift_jis" );
Console.WriteLine($ "{sjis.EncodingName}\t{sjis.CodePage}\t{sjis.WebName}" );
var str = "123abcあいう" ;
Console.Write($ "{str}: " );
byte [] bytes = sjis.GetBytes(str);
foreach ( byte b in bytes)
{
Console.Write($ "[{b:x2}]" );
}
}
}
}
|
上で述べたようなカスタムプロバイダクラスを定義しなくても Windows コードページのエンコーディングを簡単に全部使えるようにする方法もあります。
その方法は、Microsoft のドキュメント「CodePagesEncodingProvider クラス」に説明があります。
-
CodePagesEncodingProvider.Instance 静的プロパティから CodePagesEncodingProvider オブジェクトを取得します。
-
CodePagesEncodingProvider オブジェクトを Encoding.RegisterProvider メソッドに渡します。
コード例は以下の通りで一行で済みます。必要ないエンコーディングまで使えるようにすることで何か予期せぬ副作用が出るかもしれないという可能性は否定しきれませんが、こちらのが本筋かもしれません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | using System.Text;
namespace ConsoleApp4
{
internal class Program
{
static void Main( string [] args)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
var sjis2 = Encoding.GetEncoding( "shift_jis" );
Console.WriteLine($ "{sjis2.EncodingName}\t{sjis2.CodePage}\t{sjis2.WebName}" );
Console.Write($ "{str}: " );
byte [] bytes2 = sjis2.GetBytes(str);
foreach ( byte b in bytes2)
{
Console.Write($ "[{b:x2}]" );
}
Console.WriteLine( "\n\nサポートしているすべてのエンコーディングを取得する" );
EncodingInfo[] eis = Encoding.GetEncodings();
foreach (EncodingInfo ei in eis)
{
Console.WriteLine($ "{ei.DisplayName}\t{ei.CodePage}\t{ei.Name}" );
}
}
}
}
|
by WebSurfer
2025年2月4日 12:28
ASP.NET Core Web API で、ブラウザから fetch や axios を使って multipart/form-data 形式でアップロードされてきた Blob データをどのように取得できるかということを書きます。
axios のドキュメント Multipart Bodies のサンプルコード(抜粋下記)を見て、そこに書いてある Blob データを Web API でどのように取得できるかを考えたのがきっかけです。
1 2 3 4 | const form = new FormData();
form.append( 'my_field' , 'my value' );
form.append( 'my_buffer' , new Blob([1,2,3]));
form.append( 'my_file' , fileInput.files[0]);
|
上のコードの FormData を、ブラウザから JavaScript の fetch や axios を使って multipart/form-data 形式で送信すると、ボディ部分は下のようになります (Fiddler によるキャプチャ画像)。2 つ目の name が my_buffer となっているパートが Blob データです。

上のように送信されてきた my_buffer の Blob データは、ASP.NET Core Web API のアクションメソッドの引数の型を IFormFile 型とすれば取得できました。
具体的には、Web API プロジェクトで以下のクラスを定義し、
1 2 3 4 5 6 | public class Blob
{
public string ? My_field { get ; set ; }
public IFormFile? My_buffer { get ; set ; }
public IFormFile? My_file { get ; set ; }
}
|
それをアクションメソッドの引数に設定して、JavaScript の fetch や axios を使って FormData をアクションメソッドに POST 送信すれば、下の画像の通り My_buffer プロパティに Blob を取得できます。

MDN のドキュメント Blob に、
"File インターフェイスは Blob をベースにしており、 Blob の機能を継承してユーザーのシステム上のファイルをサポートするように拡張しています"
・・・と書いてあるとおり、input type="file" を使ってのファイルと同様の扱いになるということのようです。
最初、バイト配列として取得できるのではと思って、上の Blob クラスの My_buffer プロパティの型を byte[]? として試してみたのですが、バインドできないようで null になってしまいます。
![My_buffer プロパティが byte[]? 型の場合 My_buffer プロパティが byte[]? 型の場合](/BlogEngine/image.axd?picture=2025%2f2%2f0203Debugger1.jpg)
以下に検証に使ったコードを載せておきます。Visual Studio 2022 のテンプレートを使ってターゲットフレームワーク .NET 9.0 で作成した ASP.NET Core Web API アプリです。
Controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | using Microsoft.AspNetCore.Mvc;
using WebApi.Models;
namespace WebApi.Controllers
{
[Route( "api/[controller]" )]
[ApiController]
public class UploadController : ControllerBase
{
[HttpPost( "blob" )]
public async Task<IActionResult> ReceiveBlob([FromForm] Blob model)
{
string result = $ "My_field: {model.My_field}" ;
if (model.My_file != null && model.My_file.Length > 0)
{
string filename = Path.GetFileName(model.My_file.FileName);
result += $ ", My_file: {filename}" ;
}
if (model.My_buffer != null && model.My_buffer.Length > 0)
{
string array = string .Empty;
using (var stream = new MemoryStream())
{
await model.My_buffer.CopyToAsync(stream);
byte [] bytes = stream.ToArray();
foreach ( byte b in bytes)
{
array += $ "[{b:x2}]" ;
}
}
result += $ ", My_buffer: {array}" ;
}
return Content(result);
}
}
}
|
View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | @{
ViewData[ "Title" ] = "SendBlob" ;
}
<!DOCTYPE html>
<html>
<head>
<meta name= "viewport" content= "width=device-width" />
<title>@ViewData[ "Title" ] - WebApi</title>
<script type= "text/javascript" >
const url = "/api/upload/blob" ;
const upload = async () => {
const fileInput = document.getElementById( "fileupload" );
const resultDiv = document.getElementById( "result" );
const form = new FormData();
form.append( 'my_field' , 'my value' );
form.append( 'my_buffer' , new Blob([1, 2, 3]));
form.append( 'my_file' , fileInput.files[0]);
const param = {
method: "POST" ,
body: form
}
const response = await fetch(url, param);
if (response.ok) {
const message = await response.text();
resultDiv.innerText = message;
} else {
resultDiv.innerText = "アップロード失敗" ;
}
};
window.addEventListener( 'DOMContentLoaded' , () => {
const btn = document.getElementById( "button1" );
btn.addEventListener( "click" , upload);
});
</script>
</head>
<body>
<input type= "file" name= "fileupload" id= "fileupload" multiple= "multiple" />
<br />
<button type= "button" id= "button1" >Upload</button>
<br />
<div id= "result" ></div>
</body>
</html>
|
上の View のコードの実行結果は以下のようになります。

(メモ: プロジェクトは VS2022 AspNet9 WebApi)
by WebSurfer
2025年1月27日 14:26
下の図の構成で、ASP.NET MVC5 において Dependency Injection (DI) により IHttpClientFactory を取得し、それから HttpClient を生成して Web API からデータを取得し、そのデータをブラウザに表示する方法を書きます。

ASP.NET Core MVC の例は先の記事「ASP.NET と HttpClient (CORE)」に書きました。
ASP.NET Core の場合は、Visual Studio のテンプレートを使ってプロジェクトを作成すればデフォルトで DI 機能が実装されるので、Program.cs で AddHttpClient メソッドを使って IHttpClientFactory を IServiceCollection (DI コンテナ) に登録するだけで、Controller はコンストラクタの引数経由で IHttpClientFactory を取得できます。
一方、ターゲットフレームワークが .NET Framework 場合、Visual Studio のテンプレートで作成した MVC5 アプリには DI 機能は実装されません。なので、最初の課題はそれにどのように DI 機能を追加するかになります。
ちなみに DI を利用して IHttpClientFactory を取得するのは必須です。何故かと言うと、Microsoft のドキュメント「IHttpClientFactory の代替手段」に書いてありますように、以下のことを回避できるというメリットがあるからです。
-
HttpMessageHandler インスタンスをプールすることによるリソース枯渇の問題
-
一定の間隔で HttpMessageHandler インスタンスを循環させることによって発生する古くなった DNS の問題
ターゲットフレームワークが .NET Framework のアプリでも、バージョンが 4.6.2 以降であれば ASP.NET Core で DI に使われている Microsoft.Extensions.DependencyInjection 名前空間にあるクラス類を利用して DI 機能を実装できます。
.NET Framework 4.8 の MVC5 アプリに DI 機能を実装する詳しい方法は、先の記事「MVC5 での Dependency Injection」に書きました。この記事では、その記事のアプリの IServiceCollection (DI コンテナ) に IHttpClientFactory を登録し、それを Controller でどのように使って Web API に要求を出し、データを取得するかを書きます。
(1) Microsoft.Extensions.Http
NuGet パッケージ Microsoft.Extensions.Http をインストールします。これは AddHttpClient メソッドを使用して IHttpClientFactory を IServiceCollection(DI コンテナ)に登録できるようにするため必要です。

(2) AddHttpClient メソッドの追加
先の記事「MVC5 での Dependency Injection」に書いた Global.asax.cs のコード内の ConfigureServices メソッドに、以下のように AddHttpClient メソッドを追加します。この一行で Controller はコンストラクタの引数経由で IHttpClientFactory を受け取れるようになります。
1 2 3 4 5 6 7 8 9 | private void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ScopedThing>();
services.AddTransient<HomeController>();
services.AddHttpClient();
}
|
(3) Controller
Controller の例です。ブラウザが Hero アクションメソッドを呼び出すと、DI 機能により IHttpClientFactory が Controller のコンストラクタの引数経由で渡されます。
IHttpClientFactory から生成した HttpClient を使って Web API に要求を出して JSON 形式のデータを取得し、それを .NET の List<Hero> 型のオブジェクトにデシリアライズして View に渡しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | using Mvc5DependencyInjection.Models;
using System.Collections.Generic;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Mvc;
using System.Text.Json;
namespace Mvc5DependencyInjection.Controllers
{
public class HomeController : Controller
{
private readonly ScopedThing _scopedThing;
private readonly IHttpClientFactory _clientFactory;
public HomeController(ScopedThing scopedThing,
IHttpClientFactory clientFactory)
{
this ._scopedThing = scopedThing;
this ._clientFactory = clientFactory;
}
public async Task<ActionResult> Hero()
{
HttpClient client = _clientFactory.CreateClient();
var url = "Web API の url" ;
var request = new HttpRequestMessage(HttpMethod.Get, url);
HttpResponseMessage response = await client.SendAsync(request);
List<Hero> list = null ;
if (response.IsSuccessStatusCode)
{
using (Stream responseStream =
await response.Content.ReadAsStreamAsync())
{
list = await JsonSerializer.
DeserializeAsync<List<Hero>>(responseStream);
}
}
return View(list);
}
}
}
|
(4) Model
1 2 3 4 5 6 7 8 | namespace Mvc5DependencyInjection.Models
{
public class Hero
{
public int id { get ; set ; }
public string name { get ; set ; }
}
}
|
(5) View
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | @model IEnumerable<Mvc5DependencyInjection.Models.Hero>
@{
ViewBag.Title = "Hero" ;
}
<h2>Hero</h2>
<table class = "table" >
<tr>
<th>
@Html.DisplayNameFor(model => model.id)
</th>
<th>
@Html.DisplayNameFor(model => model.name)
</th>
</tr>
@ foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.id)
</td>
<td>
@Html.DisplayFor(modelItem => item.name)
</td>
</tr>
}
</table>
|
(6) 実行結果
上のコードを実行するとブラウザには以下のように表示されます。
