コードビハインドができてから、すっかり忘れてた。これでも動くのね。なんか大分新鮮。(はてな表記のコードシンタックスハイライトがaspxに対応してないので、ちょっと色がおかしいけど↓)

Sample.aspxのみ

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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>サンプル</title>
    <script language="c#" runat="server">
        
        /// <summary>
        /// ページロード時
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Page_Load(object sender, EventArgs e)
        {
            lbl1.Text = "初期表示";        
        }

        /// <summary>
        /// ボタンクリック時
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void btn1_Click(object sender, EventArgs e)
        {
            lbl1.Text = txt1.Text;
        }
        
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <asp:Label runat="server" ID="lbl1"/><asp:TextBox runat="server" ID="txt1"/>
        <asp:Button runat="server" ID="btn1" onclick="btn1_Click" Text="ボタン" />
    </form>
</body>
</html>

ふりかえりワークショップやりました

前のプロジェクトの面々にワークショップやりました。何度かふりかえりをやっているので、ここら辺りでPFのこととかちゃんと伝えたいっていうのと、次のプロジェクトでも実践してほしいという思いがあって2時間コースで行いました。

流れとしては、パワポ80ページくらいの資料作ってPFの話をして、ふりかえりの定義とかルールとかKPTのやりかたのおさらいとか、コツとかその辺りを話しして、ワークショップをやってもらう。その後、今回のワークショップでをふりかえって、「自分が次のプロジェクトでファシリテータとしてふりかえりをやったら」というテーマでみんなでふりかえり。なかなかの出来でした(自画自賛

ちょっと前に富士通カイゼンフェスタで受けたワークショップでは、ゴムを使ってボールを運ぶという作業だったのですが、用意するのが大変そうだったので、カイゼンフェスタの後の懇親会でのアドバイスを元に下記の感じで行いました。永和の天野勝さん、富士通カイゼンフェスタのスタッフの方々、ありがとうございました!

■■ワークショップ
■準備するもの

  • はさみ、のり、テープ、ホチキス、ホチキスの芯、小さい付箋、A3用紙3枚(チーム数分)
  • ペン、太いペン(各自)
  • 模造紙、大きめの付箋(最後にみんなでやるふりかえり用)
  • A4の裏紙をありったけ、タイマー、メジャー(全体で使用)
  • 計測結果を記載用の用紙をチーム数分(チーム名を入れるところと、3回分の計測結果を書く枠を印刷したもの)

■流れ

  1. チームを作ってもらう(3人1組くらい)
    • 自己紹介をする
    • チーム名を決めて、計測用紙に書く
  2. 1回目の実践(3分)とふりかえり(10分)
  3. 2回目の実践(3分)とふりかえり(5分)
  4. 3回目の実践(3分)とふりかえり(5分)
  5. 各チームからの発表(各チーム3分)
  6. 最後にみんなでふりかえり(15分程度)

■ルール

  • A4裏紙を使って塔を作ります
    • どんな方法でも構いません(貼る、積む、切る)
    • 3分経過後高さを計測して記録します

■■ワークショップ結果
■チームAは2回目塔が崩れたながらも、1回目と3回目の差が1番あったので見事優勝で駄菓子セットをゲットしました。独自の路線でふりかえりもわきあいあいとしてました。



■チームBは圧倒的な高さを誇りました。他チームを意識せず自分たちの作業に集中し、分業もきっちり。みごとなチームワークでした。Tryを次のKeepやTryにまわしてつかっていて、きっちりふりかえりができてたのが印象的でした。



■チームCはやり方を工夫しながらも、高さに伸び悩みました。周りを意識しすぎたと発表のときいっていましたが、もう1回やれば大分いけたと本人たちも端でみていた私もそう思いました。結果が出なくでも意欲的なふりかえりがよかったです。あとは普段は物静かな面子が集まったのに、かなりみんな大きな声で、たくさん話しながら作業していたのがとても印象的でした。



■■みんなでおこなったふりかえり

  • Keep/Good
    • 仕事のときよりさらにコミュニケーションがとれた
    • 意識の一致が図れた
    • カイゼンがとてもうまくいった
    • スパンを短くふりかえりをすると、カイゼン幅がのびやすい
    • スパンを短くすると、テーマが決めやすそうだ
    • 互いの裏の顔がみえた
    • ふりかえりのときに、何を気をつけたり考えたりしたらいいのかわかった
    • ふりかえりの時間が短く決められていると集中する
  • Problem
    • 時間の使い方がうまくなかった
    • ProblemとTryがごちゃごちゃになりがち
    • 明確なテーマを決めないとふりかえりがぶれる
    • 原因追求に走りがち
    • これを言ったら笑われるかもと思っていえなかったことがある
    • 整理整頓ができなかった
  • Try
    • もちまわりでファシリテータをやってみる
    • 短いスパンで開催する
    • テーマをちゃんと決める(ためにも短いスパンで)
    • ささいなことでも言ってみる
    • 朝会で、Tryの確認時間を設ける


終了後、メンバーで飲み会をしたときも、気づきを報告しあったりとか、今度はこうしたいねとか、楽しかったとか、頭使ったとか、勉強になったとか、ずっとワークショップが話題になってたのが嬉しかったです。次は自分のチームじゃないところにワークショップやる予定!

最後に、一番高かった塔の写真

VisualStudio2010 Express + NUnit でDebug実行ができない場合

VisualStudio2010 Express + NUnit (最新版2.5.8Released)を使ってテストコードを書いてみる の補足。VisualStudio2010でできないというか、.NET Framework 4.0 だとDebug実行ができないという問題です。

動作的には、NUnitはVer2.5.3から4.0に対応してくれているようですが、Debug実行ができません。対応方法としては簡単で、nunit.exe.config のconfigurationセクション内に、startupの3行を追加するだけ。これでDebug実行可能になります。ロードマップには載ってなかったけど(あたしの英語力の問題だけかもしれない)まあそのうち通常対応してくれるでしょう。

nunit.exe.config

<startup>
    <requiredRuntime version="4.0.30319" />
</startup>

2011/12/12さらに追記しました
VisualStudio2010 Express + NUnit でDebug実行ができない場合 の追記。

VisualStudio2010 Express + NUnit (最新版2.5.8Released)を使ってテストコードを書いてみる

Visual Studio にはテストフレームワークがついているのですが、残念ながらExpressでは使えません。さらにExpressではAdd-inも使えないので何かと不便。有償版を買いたいものの、お財布事情とか勉強用とかの方はどうしてもExpress。ということで、最近、新人向けにテストの講義をしたので、その時使った資料をUPしておきます。備忘録としても。

まずはテストフレームワークのインストールを行います。

  1. NUnit.orgより、最新版をダウンロードする。今回は最新版2.5.8
  2. NUnit-2.5.8.10295.msi を落としてきたので、これをたたく
  3. 今回はCompleteで全部入れます。インストーラの指示に従ってどんどん次へ進んでいく
  4. [スタートボタン] - [プログラム] - [NUnit 2.5.8] - [NUnit] を選択してGUIが起動すればとりあえず成功







次に、テスト用プロジェクトを作って動作させるところを設定します

  1. VisualStudioを起動し、[CSharpExam]と[CSharpExamTest]というクラスライブラリのプロジェクトを2つ作る。今回は [D:\Work\CSharpExam] に作成しました。
  2. インストールしたNUnitを使えるようにします。CShrapExamTestプロジェクトに参照追加より、[.NET]タブの[nunit.framework]のバージョン[2.5.8.10295]コンポーネントを選択


テストコードを早速書いてみます。ありがちな計算クラスを作ります。

  1. CSharpExamにCalcクラスを作成します
  2. CSharpExamTestに、CalcTestクラスを作成します
  3. CSharpExamを使えるようにCSharpExamTestから [参照の追加] - [プロジェクト] - [CSharpExam] を追加します
  4. NUnitとCharpExamをusingに追加します
  5. CalcTestのクラス定義の上に、[TestFixture] Attributeを記述して、テストをするためのクラスであることを宣言します
  6. インストール時に確認した要領で、NUnitGUIを起動し、[File] - [OpenProject] で、[D:\Work\CSharpExam\CShrapExamTest\bin\Debug\CShrapExamTest.dll] を選択します
  • Runすると、紫色の?がつきますが、動作することは確認できます



でもこれでは使いにくい。デバッグ実行[F5」で動いた方が嬉しいなー。ということでプロジェクトファイルの設定をちょこっと変えます

  1. CShrapExamTest.csprojを、テキストエディタ等で開いて編集し、ファイルを保存して閉じます
Debug|AnyCPUのプロパティグループ内に、下記の2行を追加する (※パスはNUitのインストールパス)
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> 
    <StartAction>Program</StartAction>							
    <StartProgram>C:\Program Files\NUnit 2.5.8\bin\net-2.0\nunit.exe</StartProgram>
   ・・・
</PropertyGroup>

ここまで来たらもう1息。今度は、NUnitの起動時に、該当のテストを読み込むように設定します

  1. [CSharpExamTest] プロジェクトを選択し、右クリックで ”プロパティ”を選択
  2. [デバッグ] タグの [コマンドライン引数]に、TestのAssemblyのパスを設定する。(この手順では、D:\Work\CSharpExam\CShrapExamTest\bin\Debug\CShrapExamTest.dll)
  3. [デバッグ開始]で実行した場合、NUnitGUIが起動し、該当のAssemblyが読み込まれていれば成功。Runを押して、NUnitが走ることを確認します。

ようやく、それっぽく動作するようになりましたので、テストコードを書いてみましょう。まずはAddTestから。

  1. CalcTestクラスに、[Test]Attributeをつけて、AddTestメソッドを作成します。
  2. Calcクラスにあるであろう、Addメソッドに、1と2を渡した結果を、3という予想値と比べます
  3. Addメソッドのところに赤い波線が出て、'CSharpExam.Calcに、'Add'の定義がありません'と出るので、Addの左端の青いラインをクリックして、メソッドスタブを生成します。
  4. 実行して「レッド」(NG)になることを確認します。これでテストクラスが正しく対象のクラスを呼べていることが確認できるはずです。

CalcTest.cs

[Test]
public void AddTest()
{
    int result = Calc.Add(1, 2);
    Assert.AreEqual(3, result);
}


Calc.cs

public class Calc
{
    public int Add(int p, int p_2)
    {
        throw new NotImplementedException();
    }
}


忘れてましたが、テストファーストの原則は、レッド → グリーン →リファクタリングのサイクルで行います。今は最初の「レッド」のところです。「レッド」を確認したところで次に「グリーン」を目指します。

Calc.cs

public int Add(int p, int p_2)
{
    return 3;
}

これで、テストコードが正しくかけていることが分かります。その確認がとれたところで実装します。

Calc.cs

public int Add(int p, int p_2)
{
    return p + p_2;
}

これでAddメソッドが正しく作成されました。最初はまどろっこしく感じるかも知れませんが、急がば回れ。テストはこんな感じで行います。

※2010/11/30 上記の設定だけだとDebug実行ができない件について、記載しました。
VisualStudio2010 Express + NUnit でDebug実行ができない場合

ファイルアップロードでのサイズ制限を考える

世の中のサイトはどのように実現しているのだろうか?最適なのは、リクエストのヘッダのサイズだけでジャッジだけど、それをASP.NETでどうやるのかあちこち調べて(ファイルのアップロードなんてずっとやってたはずなのに、自分が担当で書いたことなかったんだろうなー、きっと)、大体下記の感じで落ち着いた。

今回はファイルのサイズ指定は、個別に設定したいということでWeb.configは使えないのでXMLファイルに定義してあります。Web.configの設定値をA、個別の設定値をB、ファイルサイズをCとした場合はこういう感じになります。

  1. C < B < A :正常にアップロード
  2. B < C < A :Application_BeginRequest内で処理
  3. B < A < C :Application_Error内で処理

そこで問題なのがIIS5.1で、IIS5.1だとApplication_Error時にうまいこと処理できません。そもそもは、WindowsXPで開発中に、この問題に引っかかったのがはじまりでした。
IIS 5.1 に fileupload コントロールを使用すると、 ASP.NET Web ページでファイルをアップロードしようとすると、エラー メッセージを表示します。

結局、下記の通りにやってもIIS 5.1である以上、Redirectはうまくできませんでした。そもそもHttpContextがうまくとれない。さらにRequestが大きいサイズのままを保持していて上書きもできないし。今回は、結合環境以降はIISが7.5なのでこのまま行くことに決定。そもそも5.1でいまだに開発していることが間違いなのかなー?どなたかいい解決方法あったら教えてください。

Global.asax.cs

/// <summary>
/// Application_BeginRequest時
/// </summary>
void Application_BeginRequest(object sender, EventArgs e)
{
    RedirectFileSizeOver(null);
}

/// <summary>
/// Application_Error時
/// </summary>
void Application_Error(object sender, EventArgs e)
{
    Exception exc = Server.GetLastError();

    if (exc.GetType() == typeof(HttpException))
    {
        HttpException httpEx = (HttpException)exc;

        if (httpEx.GetHttpCode() == 500 && httpEx.ErrorCode == -2147467259)
        {
            Server.ClearError();
            RedirectFileSizeOver(httpEx);
            return;
        }
    }
}

/// <summary>
/// サイズオーバー時の処理
/// </summary>
private void RedirectFileSizeOver(HttpException ex)
{
	//設定のXMLを取得
	Dictionary<string, int> pathList = GetSettingFiles();

	//設定されているページで、その設定値よりRequestが大きい場合
    if(pathList.ContainsKey(thisPath))
    {
        if (Request.Files.Count > 0 && Request.Files[0].ContentLength > pathList[thisPath] * 1000)
        {
            OperationLogger operationLogger = new OperationLogger("");

            if (ex != null)
            {
                operationLogger.PutError("Web.ConfigのhttpRuntime maxRequestLengthより大きいサイズのファイルをUploadしました", ex);
            }
            else
            {
                operationLogger.PutError("FileSizeSetting.xmlのmaxSizeより大きいサイズのファイルをUploadしました");
            }
            PathManager.Redirect(thisPath + "?size");
        }
    }	

}

Web.config

<system.web>
    <!-- Requestが受け付けるMaxLengthとタイムアウト値 -->
    <httpRuntime maxRequestLength="30000" executionTimeout="120"/>
</system.web>

IIS7.0/IIS7.5 アプリケーションプールのマネージ パイプライン モードの構成

Windows 2008 Server(R2)にASP.NETのアプリケーションをのせたら、ローカル(Windows XP SP3)では動くのに。トップページも開きませんでした。調べたら、アプリケーションプールのマネージパイプラインが「統合モード」なことが原因なもよう。


そもそもIIS7.0以降は6.0以前と大分違うので勉強が必要でした。MSDNの中では、TechNetのこのページが1番分かりやすかったです。IIS5.0、IIS6.0 技術者向け IIS7.0 概要とアーキテクチャ それから、こちらも参考にしました。IIS 7.0 アーキテクチャの概要

            • -

IIS7.0以降は、アプリケーションプールのマネージパイプラインモードに、クラッシックと統合の2つのモードができました。MSDNからの抜粋だとこんな感じです。下記の内容は、上記TechNetのPPTファイル P.18の「IIS7.0におけるASP.NET統合」を見るとスッキリと分かる気がします。

■統合アプリケーション プール モード
アプリケーション プールが統合モードである場合、IISASP.NET の統合要求処理アーキテクチャを利用できます。 アプリケーション プール内のワーカー プロセスが要求を受け取ると、要求は順序付けされたイベントのリストを通じて受け渡しされます。 各イベントでは、必要なネイティブ モジュールおよびマネージ モジュールが呼び出され、要求の一部が処理され、応答が生成されます。

アプリケーション プールを統合モードで実行することには、いくつかのメリットがあります。 まず、IISASP.NET の要求処理モデルが統一されたプロセス モデルとして統合されることです。 このモデルでは、認証など、以前は IISASP.NET で重複していた手順が解消されます。 また、統合モードではあらゆる種類のコンテンツでマネージ機能を利用できるようになります。

■クラシック アプリケーション プール モード
アプリケーション プールがクラシック モードである場合、要求は IIS 6.0 のワーカー プロセス分離モードと同じように処理されます。 ASP.NET の要求は、まず、IIS でネイティブ処理の手順を経た後、マネージ ランタイムでマネージ コードを処理するために Aspnet_isapi.dll にルーティングされます。 最後に、要求は、応答を送信する IIS に再びルーティングされます。

IISASP.NET の要求処理モデルがこのように分離されているために、認証や承認などの一部の処理手順が重複します。 さらに、フォーム認証などのマネージ コード機能は、ASP.NET アプリケーションや、すべての要求が aspnet_isapi.dll によって処理されるようにマッピングするスクリプトがあるアプリケーションでのみ使用できます。

運用環境を IIS 7.0 にアップグレードし、アプリケーションを統合モードのアプリケーション プールに割り当てる前に、統合モードにおける既存のアプリケーションの互換性をテストしてください。 また、アプリケーションをクラシック モードのアプリケーション プールに追加するのは、アプリケーションが統合モードで動作しない場合に限定してください。 たとえば、アプリケーションが IIS からマネージ ランタイムに渡される認証トークンを利用している場合、IIS 7.0 の新しいアーキテクチャにより、このプロセスではアプリケーションに障害が発生します。

ふむふむ、そしてこちらを見てみる。Web アプリケーションの統合モードへの移行

  1. Web.configの設定は、VS2010で作っているので最初からIIS7以降対応になっているのでOK
  2. 統合モードを操作するためのクラスとプロパティも、クラッシックで使えないという該当のプロパティは使ってない

ログを見ると、Global.asaxのApplication_Startあたりで出ているのでさらに検索した結果、MSのIIS作ってる方のサイトの対応でうまくいきました。IIS7 Integrated mode: Request is not available in this context exception in Application_Start

Global.aspx内のApplication_StartメソッドでRequestのHttpContextにアクセスするとExceptionが発生するようです。対応方法としては、該当の処理を別クラスの別メソッドに移植し、Application_BeginRequestメソッド内から呼ぶようにします。移植した別メソッドの内で、staticなprivateなフラグを作っておき、1度処理したら次回のRequest時には処理をしない仕組みを作っておきます。

Global.asax.cs

public class Global : System.Web.HttpApplication
{
    void Application_BeginRequest(object sender, EventArgs e)
    {
        HttpApplication app = (HttpApplication)sender;
        FirstRequestInitialization.Initialize(app.Context);
    }
}

class FirstRequestInitialization
{
    private static bool s_InitializedAlready = false;
    private static Object s_lock = new Object();

    public static void Initialize(HttpContext context)
    {
        if (s_InitializedAlready)
        {
            return;
        }
        lock (s_lock)
        {
            if (s_InitializedAlready)
            {
                return;
            }

            SetAppRoot(context);
            s_InitializedAlready = true;
        }
    }
    
    private static void SetAppRoot(HttpContext context)
    {
        if (context.Application["AppRootName"] == null)
        {
            context.Application["AppRootName"] = context.Request.ApplicationPath;
        }
    }    
}

ほとんど参考にさせて頂いたサイトと一緒ですが、一応UPしておきます。修正前は、SetAppRootはApplication_Startから呼ばれていました。修正後、IIS7.5の環境に発行して無事動作することを確認できました。

Web.configの切り替え2

Visual Studio 2010 でのWeb.configの切り替えの続き

Transform 属性と Locator 属性の個別の要素での使用っていうところの日本語がいまひとつ分かりにくくて、アプリケーションの発行時に何度かエラーが出たけど、ようやく分かった。理解するの遅っ。

たとえば、Web.configに2つほどKeyのあるappSettingsがあるとして、

<appSettings>
    <!-- 設定1(パス) -->
    <add key="Settings1" value="C:\Work\"/>
    <!-- 設定2 (サイズ)-->
    <add key="Settings2" value="1"/>
</appSettings>

Web.Release.configにはこのように書いておくと、うまく変換してくれる。なるほどねー、LogatorとTransformってそういうことだったのですな。

<appSettings>
    <!-- 設定1(パス) -->
    <add key="Settings1" value="D:\Work\" xdt:Locator="Match(key)" xdt:Transform="SetAttributes(value)"/>
    <!-- 設定2 (サイズ)-->
    <add key="Settings2" value="2" xdt:Locator="Match(key)" xdt:Transform="SetAttributes(value)"/>
</appSettings>

ちなみに確認の仕方もメモしておく(最初、配置してから確認してて面倒だなーと思ったので)

  • Releaseビルドにしておいて、配置パッケージの作成を行う
  • 出力結果に、パッケージ "SFA.App.WebUI.zip" が次の場所に 1 つのファイルとして正常に作成されています:file:///C:/Work/AppWebUI/obj/Release/Package と出るので
  • \obj\Release\TransformWebConfig\transformed 内のWeb.configを確認します