WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

MVC5 でエラーメッセージが英語

by WebSurfer 6. February 2019 12:48

Visual Studio Community 2015 のテンプレートで [MVC] を選択して生成した ASP.NET MVC5 アプリケーションでは、そのままではデフォルトで表示されるエラーメッセージが英語になってしまいます。その理由と日本語にする方法を書きます。

英語のエラーメッセージ

上の画像を表示したコードは先の記事「日付と通貨の書式設定」と同じものです(ただし、View から DisplayForFor は削除しています)。

一番上のテキストボックスに "1c" という数字としては無効な文字列を入力するとクライアント側の検証で NG となり、"The field ID must be a number." という英語のエラーメッセージが表示されます。(IE11 の場合です。動作はブラウザによって異なります)

Model のプロパティに付与したデータアノテーション属性には、先の記事に書いコードの通り、そのようなエラーメッセージは設定していませんが、html ソースには以下のように data-val-number="The field ID must be a number." という属性が設定されます。上の画像ではその設定値が表示されています。

<input class="form-control text-box single-line" 
    data-val="true" 
    data-val-number="The field ID must be a number." 
    data-val-regex="数字 1 ~ 5 文字" 
    data-val-regex-pattern="^\d{1,5}$" 
    data-val-required="ID は必須" 
    id="ID" name="ID" 
    type="number" 
    value="1" />

なぜ "The field ID must be a number." というような英語になってしまうかと言うと、日本語のサテライトアセンブリ System.Web.Mvc.resources.dll がインストールされてないからです。

(ちなみに、Visual Studio 2010 のテンプレートで作る MVC4 は自動的に日本語のサテライトアセンブリ System.Web.Mvc.resources.dll が bin/ja フォルダに配置されます。MVC3 も、仕組みは不明ですが、エラーメッセージは日本語になります)

解決するには、NuGet パッケージ管理で Microsoft.AspNer.Mvc.ja をインストールしてやるのが簡単かつ確実だと思います。以下の画像を見てください。

NuGet パッケージ追加

それにより、プロジェクトの bin フォルダに ja フォルダが追加され、その中に日本語のサテライトアセンブリが追加されます。

日本語のサテライトアセンブリ

上の画像の ja フォルダの中の EntityFramework 関係のアセンブリは NuGet パッケージ Microsoft.AspNer.Mvc.ja をインストールする際に System.Web.Mvc.resources.dll と同時にインストールされたものです。(依存関係は不明)

インストール済みの他のパッケージが Microsoft.AspNet.Mvc.ja に依存し、更新が必要な場合は同時に更新されます。ちなみに、自分の環境で v5.2.7 をインストールしたら、Microsoft.AspNet.Mvc.5.2.3 ⇒ 5.2.7、Microsoft.AspNet.Razor.3.2.3 ⇒ 3.2.7、Microsoft.AspNet.WebPages.3.2.3 ⇒ 3.2.7 というように更新されました。

【注意】

日本語のサテライトアセンブリをインストールしたら、web.config の system.web 要素内に globalization 要素を追加し、その Culture, UICulture 属性を "auto" に設定するのを忘れないようにしてください。

Culture, UICulture を "auto" に設定すると、ASP.NET は、ブラウザから送信されてくる要求ヘッダに含まれる Accept-Language の設定を調べて、その要求を処理するスレッドのカルチャを Accept-Language に設定されているカルチャに書き換えてくれます。

そして、実行時に、リソースマネージャが現在の要求を処理しているスレッドのカルチャ情報を参照してローカライズされたリソースを検索し、UI に表示されるテキストを取得するという仕組みになっています。

Culture, UICulture を "auto" に設定するのを忘れるとブラウザの言語設定は無視されます。デフォルトではシステムのロケールに該当するカルチャがスレッドに設定されます。

なので、ホスティングサービス(Azure も含む)などでサーバーの OS が英語版だったりすると ja フォルダにある日本語のサテライトアセンブリは使われず、元の英語に戻ってしまうはずです。

Tags: ,

Validation

Ajax でファイルダウンロード

by WebSurfer 5. February 2019 18:38

Ajax を使ってファイルをダウンロードするにはどうすれば良いかということを調べましたので備忘録として書いておきます。

Ajax でファイルダウンロード

例えば、先の記事「MVC でファイルのダウンロード」で書いたようなアクションメソッドがあるとして、Ajax を使ってその URL に非同期要求をかけたとします。

そうすると、同期要求した場合と全く同様に、応答ヘッダには Content-Type と Content-Disposition が適切に設定され、コンテンツ(ファイルのバイナリデータ)も正しく返ってきます。

しかしながら、上の画像のような通知バーは表示されませんし、ファイルは PC のディスクには保存されません。

では、ファイルを PC のディスクに保存するにはどうすればいいかと言うと、応答コンテンツを Blob(生データ)として取得し、それを保存するためのスクリプトを書くことになります。

jQuery ajax を使う場合、バージョン 3.0 以降であれば Blob を取得できるそうですが(未検証・未確認です)、バージョン 2.x 以前では Blob を取得できないので、ネイティブの XMLHttpRequest を使うことになるそうです。

詳しくは stackoverflow の記事 Using jQuery's ajax method to retrieve images as a blob にある回答を読んでください。

取得した Blob をファイルとして PC に保存するには、IE, Edge の場合は msSaveBlob method を使います。

Chrome, Firefox, Opera の場合は URL.createObjectURL を使って Blob の URL を取得し、それを html の a 要素の href 属性に設定し、download 属性にファイル名を設定してスクリプトでクリックするようにします。

具体的には、ネイティブの XMLHttpRequest を使った例ですが、以下のコードの通りです。

function download() {
  var url = "/Home/FileDownload";
  var filename = "testfile";

  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'blob';
  xhr.onreadystatechange = function (e) {
    if (this.readyState == 4 && this.status == 200) {
      var blob = this.response;

      //IE, Edge とその他で処理の切り分け
      if (window.navigator.msSaveBlob) {
        window.navigator.msSaveBlob(blob, filename + ".pdf");
      } else {
        var a = document.createElement("a");
        // IE11 は URL API をサポートしてない
        var url = window.URL;
        a.href = url.createObjectURL(new Blob([blob],
                                     { type: blob.type }));
        document.body.appendChild(a);
        a.style = "display: none";
        a.download = filename + ".pdf";
        a.click();
      }
    }
  };
  xhr.send();
}

2, 3 注意点を書いておきます。

IE11 は window.URL をサポートしてないのでファイルとして保存するには msSaveBlob メソッドを使う以外に手はなさそうです。

msSaveBlob の第 2 引数を設定しないと、ファイル名は IE の場合 1A31A31A-1F57-4D8D-8C70-150839D02536.pdf のように、Edge の場合は (1) となってしまいます。

MDN のドキュメントには、Content-Disposition ヘッダーで download 属性の指定と異なるファイル名が与えられた場合は、この属性より HTTP ヘッダーが優先するということが書いてありますが、実際試すと download 属性の指定通りとなります。"" を設定したりすると aae9adeb-1005-407f-a3a6-046fa79c4351.pdf のようになります。

Tags: ,

Upload Download

日付と通貨の書式設定

by WebSurfer 4. February 2019 18:10

ASP.NET MVC5 アプリで日付(DateTime 型)と通貨(Decimal 型)を表示し、編集してデータベースを更新する場合、どのように書式設定を行うのが良いかということについて書きます。

日付と通貨の書式設定

上の画像は DisplayFor と TextBoxFor を上下に並べて表示していますが、その「契約日」と「価格」に示したように、

  1. DisplayFor 等を使った表示の場合のみ書式設定を行い、
  2. テキストボックスに値を表示する場合は書式設定しない。または、"{0:F0}" のような書式設定に留めパースできない文字は含めないようにする。

・・・のがよさそうです。

スキャフォールディング機能を使って CRUD 可能なアプリを作ると Index (レコード一覧), Create, Delete, Edit, Details というアクションメソッドとそれに対応するビューが生成されますが、Index, Delete, Details を上記 (1) で、Create, Edit を上記 (2) で表示するということです。

テキストボックスに表示する文字列も 2019年2月4日 とか ¥1,000 のように表示することはできますが、クライアント側での検証を無効にしてサーバーに POST したとしても、DateTime 型や Decimal 型にパースできないので結局モデルバインディングの際の検証が通りません。

どうしてもテキストボックスに表示する文字列も 2019年2月4日 とか ¥1,000 のようにしたいということであれば、モデルのプロパティも含めて全て String 型として扱い、検証は正規表現のみを使って行うということも考えられますが、データベースの型が datetime とか money でしょうから、サーバー側での取り扱いを考えると現実的ではなさそうです。

それに、ユーザーとしても、編集する際にいちいち ¥ とか , を入力するのは煩わしいはずで、喜んではくれないのでは?

上の画像のように表示するための方法ですが、DisplayFor での表示の書式はモデルのプロパティに DisplayFormatAttribute を付与して設定し、テキストボックスには TextBoxFor を使ってその第 2 引数に "{0:yyyy/MM/dd}"、"{0:F0}" などの書式を設定するのがよさそうです。

EditorFor を使うと書式が自由に設定できないし(DisplayFormatAttribute の設定と同じでよければ可能ですが)、レンダリングされる html ソースの input 要素の type 属性が問題になることがありますので使う場合は要注意です。

具体的には以下のようにします。

Model

public class PurchaseRecord
{
  [Display(Name = "ID")]
  [Required(ErrorMessage = "{0} は必須")]
  [RegularExpression(@"^\d{1,5}$", 
      ErrorMessage = "数字 1 ~ 5 文字")]
  public int ID { get; set; }

  [Display(Name = "契約日")]
  [Required(ErrorMessage = "{0} は必須")]
  [RegularExpression(
      @"^\d{4}/\d{2}/\d{2}( \d{1,2}:\d{2}:\d{2})?$", 
      ErrorMessage = "yyyy/MM/dd 形式")]
  [DisplayFormat(DataFormatString = "{0:yyyy年M月d日}")]
  public DateTime ContractDate { get; set; }

  [Display(Name = "価格")]
  [Required(ErrorMessage = "{0} は必須")]
  [RegularExpression(@"^\d{1,5}$", 
      ErrorMessage = "数字 1 ~ 5 文字")]
  [DisplayFormat(DataFormatString = "{0:C0}")]
  public decimal Price { get; set; }
}

View(一部の抜粋)

<div class="form-group">
  @Html.LabelFor(model => model.ID, 
    htmlAttributes: new { @class = "control-label col-md-2" })
  <div class="col-md-10">
    @Html.DisplayFor(model => model.ID)
    @Html.EditorFor(model => model.ID, 
      new { htmlAttributes = new { @class = "form-control" } })
    @Html.ValidationMessageFor(model => model.ID, 
      "", new { @class = "text-danger" })
  </div>
</div>

<div class="form-group">
  @Html.LabelFor(model => model.ContractDate, 
    htmlAttributes: new { @class = "control-label col-md-2" })
  <div class="col-md-10">
    @Html.DisplayFor(model => model.ContractDate)
    @Html.TextBoxFor(model => model.ContractDate, 
      "{0:yyyy/MM/dd}", new { @class = "form-control" })
    @Html.ValidationMessageFor(model => model.ContractDate, 
      "", new { @class = "text-danger" })
  </div>
</div>

<div class="form-group">
  @Html.LabelFor(model => model.Price, 
    htmlAttributes: new { @class = "control-label col-md-2" })
  <div class="col-md-10">
    @Html.DisplayFor(model => model.Price)
    @Html.TextBoxFor(model => model.Price, 
      "{0:F0}",new { @class = "form-control" })
    @Html.ValidationMessageFor(model => model.Price, 
      "", new { @class = "text-danger" })
  </div>
</div>

あと、オマケの話ですが、ASP.NET Web Forms アプリで使う GridView などで書式設定する際も同様なことはできます。以下の画像を見てください。

GridView で日付と通貨の書式設定

赤枠で囲った部分は[編集]ボタンをクリックして編集モードにしたテキストボックスですが、他の行との違いを見てください。

Tags: , ,

MVC

About this blog

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

Calendar

<<  November 2019  >>
MoTuWeThFrSaSu
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

View posts in large calendar