概要

前回は6章(『プログラミング C#』 その6 継承)だったけれど、ちっと章をすっとばしていきなり20章に来てみた。というのも20章は C# のウェブ・アプリケーション・フレームワークであるところの、 ASP.NET の章なんだよ。熱心なみろりHP読者のみなさんには周知のことであるけれど、ぼくはウェブ・アプリケーションにはちょっと親しみをもっているんだ。何のことだかわからないって? このみろりHP作りがウェブ・アプリケーション開発なんだってば!

ちなみにみろりHPは、プログラミング語 Python、フレームワーク Django の組み合わせで作っているよ。

じゃあ流し読みノートを書こう。

 

流し読みノート

ASP.NET ってそもそも何の略

  • ASP.NET はなにかの略語ではない(マジか)。
  • Django みたいに単一のフレームワークのことではなくて、いくつかのフレームワークの総称らしい。下に書く、 ASP.NET Web Forms とか ASP.NET MVC が Django に相当するもの。
  • 2つのビューエンジン、 aspx と Razor がある。
    • aspx は古くて冗長。 ASP.NET Web Forms という機能用のファイル。拡張子はそのまんま aspx。
    • Razor のほうが単純な文法で、2010年生まれと新しい。ふつう cshtml っていう拡張子のファイルになる。

 

ビューエンジンの機能

ビューエンジンてのはアレだ HTML の中にプログラムの変数を埋め込んだり、タグを動的に生成するのを手伝ってくれる機能。 Django にももちろんあって、 HTML の中で for だか if だかを書くことを可能にしてくれた。このページ(みろりHPブログのページ)自体も、それで生成されているんだぜ。

<!-- 式を書きたいとき -->
<!-- Razor -->
<div>クエリ文字列: @Request.QueryString</div>
<!-- aspx -->
<div>クエリ文字列: <%: Request.QueryString %></div>

<!-- コードブロック(HTML の中に C# のエリアを作る) -->
<!-- Razor -->
@{
    System.Collections.Specialized.NameValueCollection qs = Request.Unvalidated().QueryString;
}
<!-- aspx -->
<%
    System.Collections.Specialized.NameValueCollection qs = Request.Unvalidated().QueryString;
%>

<!-- Razor の場合コードブロックの中に C# と HTML を混ぜて書ける。 -->
<!-- その判別は Razor がやってくれるけれど、明示的に書くこともできる。それは良いことだね。 -->
@foreach (string paramKey in qs)
{
    int i = paramKey.Length;
    <div>
        キー:@paramKey, 値:@qs[paramKey] (@i)
    </div>
    <!-- 明示的な書き方。 -->
    @: キー:@paramKey, 値:@qs[paramKey] (@i)
}

<!-- aspx は混ぜて書けない。何これヒド。 -->
<%
    foreach (string paramKey in qs)
    {
%>
        <div>
            キー:<%: paramKey %>, 値:<%: qs[paramKey] %>
        </div>
<%
    }
%>

<!-- C# の using も書ける。名前空間のインポート。 -->
<!-- Razor -->
@using System.Linq
<!-- aspx -->
<%@ Import Namespace="System.Collections.Specialized" %>

<!-- レイアウトページ。複数ページで共通して同じヘッダとか使いたいときに活躍。 aspx のほうはちょっと意味がわからない。 -->
<!-- Razor -->
@{
    Layout = "_CustomLayout.cshtml"
}
<!-- aspx -->
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="My.master.cs" Inherites="WebFormsApp.My" %>

<!-- section を使うと head タグの中に追加できる。 -->
<!-- Razor -->
@section head
{
    <link href="~/Content/Special.css" rel="stylesheet" type="text/css" />
}

もちろん全部 Django でもできる。コラ。張り合うんじゃありません。

Razor のうんちく

  • ↑こうした機能は Razor ビューエンジンが HTML をクラスとしてコンパイルして動作する。
  • ページ内のすべてのコードブロックと式が Execute というメソッドとして定義されている。
    • ああ、まあそのへんはよくわからんけど、 HTML + ちょっとの C# を書いているつもりでも、実際はクラスの中身を書いていることになってるんだね。
  • Razor の中では Html などのヘルパーオブジェクトが使える。それは上述したクラスの親クラスで定義されているためだ。ヘルパーオブジェクトってのが以下のようなものがある。
    • Context リクエストとレスポンスの情報が入ってる。
    • Html 一般的な HTML 要素を生成するヘルパーメソッド。
    • Output ページに書き込む TextWriter。
    • Profile ユーザ単位の情報が入ってる。使うにはプロファイル機能の有効化が要る。
    • Request リクエストの情報。
    • Response レスポンスを完全に制御できる。
    • Server ASP.NET のユーティリティメソッド。
    • Session まあこれはセッションやろ。
  • _PageStart.cshtml を置いとくと、そのディレクトリの View を読む前に Razor がその中のコードを実行してくれる。

まあなんか、 Django のビューエンジンと似たような感じなのかなと思う。

string photoUrl;
<p>@photoUrl</p>  ←これ、ダメ。 Use of unassigned local variable

string photoUrl = string.Empty;
<p>@photoUrl</p>  ←これ、 OK。なんでやねんデフォルト値があるんだからええやろ……。

 

Razor Request.QueryString のセキュリティがどんどん下がっていくサマ

上述した @Request.QueryString は Get クエリを表示するものなので、クロスサイトスクリプティング攻撃のセキュリティホールとなる。それを勝手に防ぐ機能が Razor にある。

<!-- セキュリティ爆高。クエリに Javascript が含まれているとエラーが表示されて自動的に保護される。 -->
@Request.QueryString

<!-- エラーは出さないけれど、 < とか > とか :// をエスケープする。 -->
@Request.Unvalidated().QueryString

<!-- < とか > だけエスケープする。 -->
@HttpUtility.UrlDecode(Request.Unvalidated().QueryString.ToString())

<!-- エスケープもしない。 XSS 攻撃を許容する。 -->
@Html.Raw(HttpUtility.UrlDecode(Request.Unvalidated().QueryString.ToString()))

Razor センセーの過保護っぷりがスゴイ。

 

aspx と Web Forms のうんちく

  • aspx は単体で語られるより ASP.NET Web Forms という機能とセットで語られる。
  • サーバサイドコントロールというモデルを使用している。(?)
  • コードビハインドというモデルを使用している。(?)
    • えー。よくわからんけど、 aspx という HTML のファイルと C# のファイルが1ページごとにセットになっていると思ってよさげ。「コードビハインド」と言われたら、 aspx と紐付いている C# のファイルのことを指している感じだ。
  • これらモデルのおかげで、デスクトップアプリケーションと同じような感覚でプログラミングができる。
    • あー。 Python でデスクトップアプリを作ったことあるから、なんかわかるかも。たとえば画面にボタンを出したいときは HTML みたいなのを書くんじゃなくて、 Python ファイルの中でボタンオブジェクトを生成して配置していくんだよ。そういうモデルだってことだろう? だから aspx と C# がセットなんでしょ。
  • HTML(aspx)側に <asp:TextBox> みたいにコントロール(C# から操作できる要素のことをコントロールと呼ぶっぽい)を書いて、それが input タグに置き換わる。
  • POST すると、コントロールの情報が POST に含まれる。
    • これはビューステートといって、暗号化とメッセージ認証コード(MAC)によって保護されている。でもこれは過剰なセキュリティで、現に昔は MAC だけだったとのことだ。
    • POST リクエストがあると、まず aspx ファイルをもとにコントロールが新作成されたあと、ビューステートに従ってコントロールが変更されるという流れ。
    • その流れのおかげで、実際はまったく新しいオブジェクトが生成されてるんだけど、直前と同じ状態であるかのようにコントロールを扱えるというわけだ。泥男(スワンプマン)みたいな話やな。
  • <asp:TextBox> みたいに定義したコントロールでないと C# から操作できないわけではない。 <span runat="server"> みたいに書けばこれも操作できる。

いや、ナニコレ。クライアントサイドとサーバサイドが癒着しすぎだろう。めちゃくちゃややこしそう。これは Razor 一択だろう。現にこの著者だって「Razor はマークアップを大幅に書き換えたり、情報を追加したりしない」とちょっと aspx をディスっているぞ。勝手に HTML タグが書き換わるなんて、 CSS とかでデザインすることを考えたら地獄じゃね?

 

ASP.NET MVC

  • ASP.NET の上にさらに MVC というパターンを上乗せしたもの。
  • MVC ってのは、機能を全部ひとつのファイルに書くんじゃなく、次のように分けて書いて管理するパターンだ。
    • 表示したい情報 -> モデル
    • 表示方法 -> ビュー
    • リクエストに応じてどのビューを使うのか管理 -> コントローラ
  • MVC 1970年に Xerox のパロアルト研究所で考案されたもの。
  • だから MVC ってのはフレームワークの名前でありながら、そのパターン自体の名前でもあるわけね。
  • ASP.NET MVC はそのパターンに加えてルーティング機能によって URL をサーバ上のファイルシステムの構造に対応させるだけでなく、より高度な情報を洗練された形で URL に組み込める。
  • ところで _PageStart.cshtml という Razor の機能があったけれど、 MVC では _ViewStart という名前でも使える。

全然意識してなかったけど Django も MVC パターンだね。初心者ってひとつのファイルにずらずらーーっと書いちゃうからヤベー長さになってタイヘンなんだけど、アレは「このファイルには計算を書く」「このファイルには画面表示に関することを書く」と切り分けられてラクだったよ。

 

小休憩

とくにおもしろいものはなかったけれど、 C# でウェブ・アプリケーションを作ろうとするとき使うものはわかった。 ASP.NET MVC だね。 Django に近い感覚で使えそうだ。