WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

識別子名に日本語

by WebSurfer 2015年3月17日 17:23

変数、メソッド、プロパティなどの識別子名に、見易さや保守性を考えて日本語を使うという話を時々聞きますが、言語仕様上許されているからと言って安易に使うと思わぬ副作用がありそうという話を書きます。

自分が気がついた例に限っての話ですが、それは ASP.NET MVC のモデルのプロパティ名、コントローラーのアクションメソッドの引数名です。

モデルのプロパティ名は html ソースでは name 属性に設定され、クライアント側でのユーザー入力の検証やサーバー側でのモデルバインディングに使われます。

具体的には次の通りです。

先の記事 コレクションのデータアノテーション検証 で紹介したモデル / ビュー / コントローラーのコードを見てください。そのモデルには CountryList と Name というプロパティ名が使われています。それを元に以下のようなビューを書くと、

@Html.LabelFor(m => m.CountryList[i].Name)
@Html.EditorFor(m => m.CountryList[i].Name)
@Html.ValidationMessageFor(m => m.CountryList[i].Name)

生成される html ソースは以下のようになります。

<label for="CountryList_0__Name">国名</label>
<input class="text-box single-line" 
  data-val="true" 
  data-val-length="国名 は 15 文字以内" 
  data-val-length-max="15"
  data-val-required="国名 は必須" 
  id="CountryList_0__Name"
  name="CountryList[0].Name" 
  type="text"
  value="Italy" />
<span class="field-validation-valid" 
  data-valmsg-for="CountryList[0].Name" 
  data-valmsg-replace="true">
</span>

上記の CountryList と Name が日本語になった場合、jQuery ライブラリを使ったクライアント側での検証がうまく動くのか、ブラウザで form が submit されると き name 属性がどうなるか、サーバー側できちんとモデルバインディングされるかが気がかりです。

モデルのプロパティ以外で思いつくものとしてはアクションメソッドの引数名があります。これもサーバー側でのモデルバインディングに関係します。

他にも予期できない副作用があるかもしれません。十二分に検証すれば済むかもしれませんが、そもそも余計な気苦労と不要な手間です。そこまでして日本語を使う理由はなさそうです。

クライアント側に影響がありそうな ASP.NET MVC アプリの識別子名で、日本語を使っても問題なさそうなのはコントローラーのアクションメソッド名ぐらいでしょうか?

例えば、以下のようにアクションメソッド名は日本語でも、ActionNameAttribute で英語名 Countries を付与すればブラウザからは Countries で呼べます。

[ActionName("Countries")]
public ActionResult 国リスト取得()
{
  return View();
}

でも、やっぱり日本語を使うのは個人的にはお勧めではないです。例えば、Countries でなら呼べますが Countries では 404 エラーです。違いが分かりますか?

答は、名前の最後の s が半角 / 全角の違いということです。

そんなエラーはすぐ気がつくと思われるかもしれませんが、たとえ 1 分で気がついたとしても時間と労力の無駄には変わりないということで、やはり日本語は使用しない方がよいと自分は思います。

Tags: ,

.NET Framework

FileUpload と CustomValidator

by WebSurfer 2015年3月10日 14:02

ASP.NET サーバーコントロールの FileUpload を使用してファイルをアップロードする際に、検証コントロールの CustomValidator を利用してファイルのサイズとタイプを検証し、検証結果 NG の場合はファイルをセーブしない方法について書きます。

アップロードされるファイルの検証

注:この記事は単一ファイルのアップロードの場合に限った話です。(ASP.NET 4.5 以降では FileUpload コントロールに AllowMultiple, HasFiles, PostedFiles プロパティなどが追加されています。なので、Web サーバーが ASP.NET 4.5 以降、ブラウザが HTML5 をサポートしていれば FileUpload を使っての複数ファイルの同時アップロードが可能です・・・が、それは今回は考えていません)

ファイルのアップロード後に、サーバー側だけでファイルのサイズやタイプを検証するのであれば、CustomValidator を使うメリットはあまりなさそうです。

しかし、RequiredFieldValidator, RegularExpressionValidator 等と同様に、ユーザー入力を submit する前にクライアント側で検証し、検証結果 NG の場合は submit を中止してエラーメッセージを表示するという機能を実装する場合は CustomValidator を利用するのがお勧めです。

理由は、(1) 他の ASP.NET 検証コントロールとの統一性が保てること、(2) 検証結果 NG の場合の submit の中止とエラーメッセージの表示のため検証コントロールの既存の機能が使えるということです。(特に (2) は ASP.NET の仕組みをよく理解していないと自力で実装するのは難しいと思われます)

CustomValidator を利用する場合、サーバー側での検証に使うメソッド、クライアント側での検証に使う JavaScript 関数のコードは自力で書かなければなりません。

サーバー側は特に難しくはないと思いますが、問題はクライアント側です。もともと JavaScript にはローカルファイルにアクセスする機能はありません。なので、JavaScript ではファイルのサイズやタイプなどの情報は取得できず、クライアント側での検証は諦めざるを得ませんでした。

ところが HTML5 によって話が変わってきました。今は、ブラウザが HTML5 File API 仕様をサポートしていれば、その API を利用して JavaScript でファイルのサイズやタイプなどの情報を取得でき、クライアント側での検証が可能が可能です。

以下に CustomValidator を使用して、クライアント側とサーバー側の両方でファイルのサイズとタイプを検証し、サイズが 500,000 bytes を超える場合、タイプが image/jpeg 以外の場合は検証 NG としてファイルのアップロードを中断するサンプルコードをアップしておきます。

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
  // サイズ制限 500,000 bytes, タイプ制限 image/jpeg とした。
  // ハードコーディングしないで web.config で appSettings に
  // 設定する方が良いかも。
  int maxFileSize = 500000;
  string allowedContentType = "image/jpeg";
    
  protected void Page_Load(object sender, EventArgs e)
  {
    Label1.Text = "";
  }
    
  protected void Button1_Click(object sender, EventArgs e)
  {
    if (Page.IsValid)
    {
      // FileUploadTest はアプリケーションルート直下に作った
      // ファイル格納用フォルダ。その物理パスを取得
      string savePath = MapPath("~/FileUploadTest/");

      savePath += Server.HtmlEncode(FileUpload1.FileName);

      FileUpload1.SaveAs(savePath);

      // アップロード完了時のメッセージ表示
      Label1.Text = FileUpload1.FileName +
        " (" + FileUpload1.PostedFile.ContentType + ") - " +
        FileUpload1.PostedFile.ContentLength.ToString() + 
        " bytes アップロード完了";
    }
  }

  // サーバー側の検証に使うメソッド。
  // ServerValidate イベントのハンドラに設定する 
  protected void ServerValidate(object source, 
      ServerValidateEventArgs args)
  {
    // FileUpload にファイルが格納されていることを確認
    if (FileUpload1.HasFile)
    {
      // MIME コンテンツタイプの取得 / 制限
      string contentType = FileUpload1.PostedFile.ContentType;
      if (contentType != allowedContentType)
      {
        ((CustomValidator)source).ErrorMessage =
              "タイプが " + allowedContentType + 
              "ではありません。";
        args.IsValid = false;
        return;
      }
        
      // ファイルサイズの取得 / 制限
      int fileSize = FileUpload1.PostedFile.ContentLength;
      if (fileSize > maxFileSize)
      {
        ((CustomValidator)source).ErrorMessage =
            "サイズが " + maxFileSize.ToString() +
            " bytes を超えています。";
        args.IsValid = false;
        return;
      }

      args.IsValid = true;
    }
    else
    {
      ((CustomValidator)source).ErrorMessage = 
          "ファイルが選択されていません";
      args.IsValid = false;
    }
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>FileUpload</title>
  <script type="text/javascript">
  //<![CDATA[
    // クライアント側での検証用 JavaScript 関数。
    // ClientValidationFunction プロパティに設定する
    function ClientValidate(val, args)
    {
      // HTML5 File API の File, FileList がサポートされている
      // 場合のみ検証する。サポートされてないとスクリプトエラ
      // ーになるので下の if 文は必要
      if (window.File && window.FileList) 
      {
        var fileUpload = 
          document.getElementById("<%=FileUpload1.ClientID%>");

        // if (fileUpload.files[0] == null) でも引っかかるがファイルが
        // 選択されてないと fileUpload.files[0] は undefined になるので
        // 以下のようにするのが正解かも
        if (fileUpload.files[0] == undefined ||
            fileUpload.files[0] == null) {
        {
          // ここでサーバー側と同様に ErrorMessage プロパティ
          // に設定されたエラーメッセージを書き換えようとした
          // が不可。ウラワザ的方法があるかもしれないが諦めた。
          // 下の alert はデバッグ時の検証用
          alert("ファイル未選択");
          args.IsValid = false;
          return;
        }

        if (fileUpload.files[0].type != '<%=allowedContentType%>') 
        {
          // alert はデバッグ時の検証用
          alert("タイプ相違");
          args.IsValid = false;
          return;
        }

        // 2021/1/26 訂正
        // Number() を使わないと Chrome, Edge で Synrax error になる。
        // ブログの記事を書いた 2015/3/10 時点では問題なかったが
        // JavaScript の仕様が変わった?
        if (fileUpload.files[0].size > Number(<%=maxFileSize%>)) {
        {
          // alert はデバッグ時の検証用
          alert("サイズオーバー");
          args.IsValid = false;
          return;
        }
      }
      args.IsValid = true;
    }
  //]]>
  </script>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <h4>Select a file to upload:</h4>

    <asp:FileUpload id="FileUpload1"                 
      runat="server">
    </asp:FileUpload>
           
   <%-- CustomValidator だけは、ControlToValidate プロ
    パティを設定しなくても使用可。ValidateEmptyText プ
    ロパティはデフォルトの false のままで検証できる。
    ControlToValidate="FileUpload1" としておくと、
    ファイルを選択した時点でクライアント側の検証がかかる。
    ただし、そうすると未選択時にはクライアント側での検証
    はかからなくなるので注意--%>
    <asp:CustomValidator 
      ID="CustomValidator1" 
      runat="server" 
      ForeColor="Red"
      OnServerValidate="ServerValidate" 
      ClientValidationFunction="ClientValidate"            
      ErrorMessage="CustomValidator">
    </asp:CustomValidator>
    <br/>
    <br/>

    <asp:Button id="Button1" Text="Upload file"
      OnClick="Button1_Click" runat="server">
    </asp:Button>

    <hr />

    <asp:Label id="Label1" runat="server" />
  </div>
  </form>
</body>
</html>

自分が持っているブラウザで試した限りですが、File API がサポートされていてクライアント側での検証が可能だったのは、Firefox 36.0.1, Chrome 41.0.2272.76, Safari 5.1.7, Opera 12.17 でした。

IE10 以上も File API をサポートしているそうですが、自分は持ってないので検証できていません。IE9 で検証してみましたが、やはり File API は未サポートのようで、クライアント側での検証はかかりません。ただし、サーバー側での検証はかかるので、そこでは制限できます。

この記事の上にある画像は、上のサンプルコードを Chrome で表示した時のもので、MIME タイプが image/jpeg ではないのでクライアント側での検証結果が NG となり、ErrorMessage プロパティに設定されたエラーメッセージ "CustomValidator" が赤文字で表示されたところです。

注: CustomValidator の ControlToValidate プロパティを "FileUpload1" に設定しておくと、ファイルを選択した時点でクライアント側の検証がかかります。ただし、そうすると未選択時にはクライアント側での検証はかからなくなるので注意してください。上のサンプルコードでは ControlToValidate を設定 していませんので、submit(すなわち[Upload file]ボタンクリック)時点でクライアント側の検証がかかっています。

エラーメッセージ "CustomValidator" は、CustomeValidator をドラッグ&ドロップしたときのデフォルト ErrorMessage="CustomValidator" で、もちろんこれは初期設定で変更できます。ただし、クライアント側でエラーの内容に応じてこれを動的に書き換えることはできないようです(サーバー側では上のコードのようにして書換可能でしたが)。

最後に、HTML5 File API に関して参考になると思われる(と言うか自分が参考にした)記事へのリンクを張っておきます。

Tags: , ,

Validation

IE の互換表示設定と meta タグ

by WebSurfer 2015年2月24日 14:19

先の記事 ブラウザーモードとドキュメントモード で、meta タグ (X-UA-Compatible) に content="IE=edge" を指定すると IE6 ~ IE11 では "the highest standards mode supported by Internet Explorer" になるという話を書きました。

これと IE の互換表示設定(以下の画像参照)のどちらが優先されるでしょうか?

IE の互換表示設定

実際に検証した結果、meta タグの指定の方でした。(検証に使ったのは IE9 です。【2021/7/31 追記】 IE11 バージョン 11.789.19041.0 でも検証しました。他のバージョンは未検証)

上の画像のようにデフォルトでは[イントラネットのサイトを互換表示で表示する(I)]にチェックが入っていますので、あるサイトをローカルイントラネットに登録すると(登録しなくても、ホスト名によっては IE が勝手にイントラネットと判定するケースもありますが)、そのサイトは互換モードで表示されます。

または、上の画像で[追加(A)]ボタンをクリックして[互換表示に追加した Web サイト(W):]に加えても、そのサイトは互換モードで表示されます。

上記の設定のまま、あるページだけは標準モードで表示したい場合、そのページに以下の meta タグを追加すれば "the highest standards mode supported by Internet Explorer" 即ち標準モードで表示されるようになります。

<meta http-equiv="x-ua-compatible" content="IE=edge" />

標準モードでは表示が崩れるなどの理由で互換モードで表示したい場合のみに meta タグを使用してドキュメントモードを指定するのだと思い込んでいましたが、その逆(互換モード ⇒ 標準モード)も可能だったようです。

実は、つい先日 MSDN Forum で教えてもらうまで知らなかったです。(汗)

Tags:

その他

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年3月  >>
252627282912
3456789
10111213141516
17181920212223
24252627282930
31123456

View posts in large calendar