redwarrior’s diary

C#, ASP.NET, WEB, G*などの雑多な情報

(小ネタ)Chaining AssertionのParameterized TestでどのTest Caseで失敗したかを記録する

Chaining Assertionでは、Parameterized Testがサポートされているが、テストが失敗した時のメッセージにはどのケースで失敗したかの情報は含まれていないため、多くのテストケースを試す場合は以下のように工夫すると良い感じです。

//公式サンプルコードを一部修正
[TestClass]
public class UnitTest
{
    public TestContext TestContext { get; set; }

    [TestMethod]
    [TestCase(1, 1, 2, 3)]       //第1引数を追加
    [TestCase(2, 10, 20, 30)]    //第1引数を追加
    [TestCase(3, 100, 200, 300)] //第1引数を追加
    public void TestMethod2()
    {
        TestContext.Run((int i, int x, int y, int z) =>
        {
            Console.WriteLine($"ケースNo.{i:D2} x={x}, y={y}, z={z}") //第1引数をケースNo.としてコンソール出力
            (x + y).Is(z);
            (x + y + z).Is(i => i < 1000);
        });
    }
}

テスト結果の出力画面を表示すると、テストが失敗したところでコンソール出力が終了しているので、どこで失敗したかがわかるようになります。

実行環境

C#でExcelファイルを扱うライブラリごとのファイルクローズ方法(EPPlus、NPOI)

C#ASP.NET MVC)でExcelファイルを扱う方法を調べていて、EPPlusが良さそうだったので簡単なプログラムを作成して動作を確認した。しばらく経って実際に使用する時になって、ファイル形式が .xls であることが判明。

EPPlusでは .xls のファイルは読み込めないため、NPOIについての調べ始めたところ、NPOIのサンプルがコンソールアプリケーションばかりでファイルストリームのクローズについてあまり書かれていなかったので、EPPlusと並べて記録しておきます。

EPPlus

EPPlusでは以下のように実装していました。dataは、コントローラのアクションメソッドで受け取ったHttpPostedFileBaseクラスのインスタンスです。ExcelPackageがIDisposableインターフェイスを実装しているのでスマートに書けます。

using (ExcelPackage inputFile = new ExcelPackage(data.InputStream))
{
    ExcelWorksheet sheet = inputFile.Workbook.Worksheets["Sheet1"];
    // ...以下何らかの処理
}

NPOI

NPOIも、WorkbookFactoryクラスのCreateメソッドや、HSSFWorkbookクラスのコンストラクタ等でストリームを受け取ることが出来るのですが、メソッドの戻り値であるIWorkbookがIDisposableインターフェイスを実装していないので、usingを使用することが出来ません。
さらに調べていくと、NPOIのGitHubリポジトリのexamplesフォルダに似たようなサンプルがあったので、その方法を使用します。

IWorkbook book;
using (Stream fs = data.InputStream)
{
    book = WorkbookFactory.Create(fs);
}
ISheet sheet = book.GetSheet("Sheet1");
// ...以下何らかの処理

以上です。

(小ネタ)bootstrap-datepicker (Bootstrap 3 に対応した Date Picker) で選択した日付がハイライトされない

使用しているライブラリ(NuGetから取得可能)

github.com

参照するcssが間違っていた。 bootstrap.datepicker.cssではなく、bootstrap.datepicker3.cssを参照する。

TFS 2015のXAMLビルドでNuGetの復元を行わない設定をしたらビルドが超速く終わるようになった

メモ:TFS 2017は、NuGetサーバーをローカルで建てることが出来るらしいので、そちらを使った方がディスク容量の節約になると思いますし、そちらを使いましょう。

TFS 2015から新しいビルド方式が用意されて、TFS 2017もリリースされ、今後あまり使われなくなっていくと思われるXAMLビルドですが、自動ビルド&デプロイの方法を確立した事もあり、しばらく使い続けることになりそうです。

TFS 2015上のXAMLビルドで、形として残していなかったノウハウがあったので、備忘録として残しておきます。

環境

困っていた事

作成したプロジェクトをTFS上でビルドする時に、NuGetによる復元が毎回発生してしまいビルドが上手くいきません。

Windows Server自体は外部と通信できるが、NuGetクライアントが外部通信するためには設定が必要でした。

NuGetサーバーを内部に建てるという方法もあったと思うが、空いているサーバーもなくやり方がわかりませんでした。

対応した内容(概要)

まず、リポジトリの容量が増えても良いので、プロジェクトに全てのパッケージを含めました。

しかし、NuGetによる復元で外部接続が発生し、タイムアウトするまでプロジェクトの内のパッケージを参照しないため、ビルドに約1時間近くかかってしまっていました。

そこでビルド プロセス テンプレートをカスタマイズして、NuGetによる復元をオフにしたところ、1時間かかっていたビルドを1分に短縮することが出来ました。

ビルド プロセス テンプレートのカスタマイズ方法

ビルド プロセスのカスタマイズ

上記の「ビルド プロセス テンプレートのカスタマイズ」リンク先ページに手順がのっていますが、その通りにはやらずに以下の手順でやりました。

  1. ビルド定義のプロセスメニューから、ビルドプロセステンプレート(GitTemplate.12.xaml)をダウンロード
  2. ダウンロードしたファイルの名前を「GitTemplate.NotRestore.xaml」に変更
  3. プロジェクトの直下に保存して、ソリューションエクスプローラからファイルを追加
  4. 追加したファイルを開くと専用のエディタが開き編集可能になる
  5. エディタ上から「MSBuildの実行」を探す、無い場合は右上の「すべて展開」をクリックすると、表示されるはず。
  6. MSBuildの実行」を選択すると、プロパティウィンドウにプロパティが表示されるのでその中から「RestoreNuGetPackages」を探し、Falseに変更する
  7. 保存してエディタを閉じる

カスタマイズしたテンプレートをビルドに使用する

これで手元での修正が完了しました。次は修正したビルド プロセス テンプレートをTFS上のビルドに使用します。以下の手順でやりました。

  1. 修正したファイルをコミット&プッシュする
  2. ビルド定義のプロセスメニューから、ビルド プロセス ファイルのプルダウンからプッシュしたファイルを選択する(リポジトリサーバー上に無いと表示されない)
  3. 保存する

ビルド完了後に、TFS上からログを参照するとNuGetによる復元が行われていないことが確認できます。

以上です。

IIS上で動くASP.NET (MVC)アプリケーションの権限について

ASP.NET MVC アプリケーションを別サーバーにデプロイして動作確認しようとしたが、DBやフォルダへのアクセス権限でエラーが発生しました。以前に設定したのが少し前で、やり方を忘れていたのと、IIS上でASP.NET MVC アプリケーションの権限について理解があやふやな部分があったので調べました。

ASP.NET MVCでしか確認していないけれど、MVC固有の設定はしていないので ASP.NET上のアプリケーション全般に通じる話かもしれない。

Webアプリケーション、アプリケーションプールについて

そもそもIIS上でのWebアプリケーションやアプリケーションプールとは何なのか?については、以下のサイトに書いてありました。

aspnet.keicode.com

aspnet.keicode.com

メモ

  • IIS上のアプリケーションは、Application Pool単位で実行される。Application Poolは自作も可能(.NET Framework Versionを指定する)
  • IIS上のアプリケーションは、ワーカープロセス(w3wp.exe)で起動し、その設定がApplication Poolとしてまとめられている
  • ワーカープロセスは、Webサイトへのアクセスとは別の権限で動作する

アプリケーションの権限について

では、Application Poolの権限は、どうやって調べるのか?こちらは以下のサイトに書いてありました。

blog.shibayan.jp

IIS のアクセス許可 - クリエイティブWeb

メモ

IIS 7.0(Windows Server 2008)とIIS 7.5(Windows Server 2008 R2)の違い

メモ

IIS 7.0(Windows 2008)
  • Application PoolのIDは、NETWORK SERVICEが既定値
  • 実在のユーザーアカウントではないが、IIS AppPool\(Application Pool名)というIDでアクセス制御をすることが可能
    • アクセス制御は可能だが、ワーカープロセスはNETWORK SERVICEで動作する
    • IIS7.5と同じ動きにしたい場合は、Application PoolのIDをApplicationPoolIdentityにする
IIS 7.5(Windows 2008 R2)
  • Application PoolのIDは、ApplicationPoolIdentityが既定値
  • ApplicationPoolIdentityでは、ワーカープロセスはApplication Poolごとに IIS AppPool\(Application Pool名)という仮想アカウントで動作する
  • 全てのApplication Poolのアカウントは、IIS_IUSRS グループに含まれる

DBやフォルダへの権限設定方法

作成したアプリケーションのDBやフォルダへのアクセス許可等の権限を設定するには、以下のどちらかを設定すれば良いようです。

  1. IIS_IUSRS グループを追加して権限を設定すると、Application Poolを使用するアプリケーションつまり、IIS上の全てのアプリケーションが設定した権限を持つ。
  2. IIS AppPool\(Application Pool名)アカウントを追加して権限を設定すると、対象のApplication Poolを使用するアプリケーションが設定した権限を持つ。

以上です。

補足

アプリケーションからDBへのログインは、Windows認証を使用しています。(Web.configの接続文字列にユーザー名・パスワードを指定しない)

(小ネタ).NET Frameworkの本体と、targeting packは別物

タイトルからして、何当たり前のことを言っているんだ感が全開ですが、今後同じ間違いをしないように書いておきます。

開発環境とネットワークでつながっていない環境に、ASP.NET MVC 5 アプリケーションをデプロイする必要がありました。

デプロイの「発行先を選択」でフォルダを選択して、ローカルPCのパスを指定します。

指定したパスにアプリケーション一式が格納されたフォルダが作成されるので、それを何らかの手段で対象の環境に持っていき、IISのサイトの下にフォルダごと配置します。以下のサイトの内容と大体同じ手順です。

[VisualStudio] 作成したWebプロジェクトをIISに乗せる – .NETちょこっとリファレンス

その後、ページを表示したら、Web.config の以下の部分でエラーが発生。

    <compilation debug="true" targetFramework="4.6" />

これは、.NET 4.6が入っていなさそうだなと思い、確認するとやはり .NET 4.5.2 しか入っていませんでした。

そこで .NET Framework 4.6 Targeting Pack をインストールして確認すると、エラーの内容が以下のように変化しました。

メソッドが見つかりません:'!!0[] System.Array.Empty()'
例外の詳細:System.MissingMethodException:メソッドが見つかりません:'!!0[] System.Array.Empty()'

上記メッセージの後にスタックトレースが続くのですが、それによると発生個所はUnityConfig.cs でした。

さて、勘のいい方ならば、すでにわかったと思いますが、上記のエラーメッセージを元に調べると、.NET 4.6 でビルドしたプログラムを .NET 4.5.2 上で実行しようとした時に発生するエラーでした。

つまり、.NET Framework 4.6 Targeting Pack を入れたのに、.NET Framework 4.6本体を入れていなかったのです。

過去の自分の記事を参考にしたのですが、そちらはそもそもビルドサーバーの話でした。

教訓:公式ドキュメントをちゃんと確認する。

.NET Framework のインストール

.NET Framework システム要件

ちなみに(1):実行環境には、.NET Framework 4.6 Targeting Pack は不要みたいです。

ちなみに(2):.NET 4.6.1以降の Developer Pack には、.NET Framework本体も同梱されています。

デプロイできたけど実行できない場合の対処方法(とTFS上のデプロイ)

ASP.NET MVC5でWebアプリケーションを作成し、IISへの公開も成功して、さて確認するぞ!という事でアクセスしたらエラーが発生して表示できなかったので、原因を調べました。

動作環境

設定内容

IIS 7では以下の設定が必要です。修正プログラムをインストールすれば不要なようです。また、IIS7.5は最初から不要です。

Web.configの修正

<system.webServer>
  <modules runAllManagedModulesForAllRequests="true"> //ここを追加

参考URL: https://support.microsoft.com/ja-jp/help/980368/a-update-is-available-that-enables-certain-iis-7.0-or-iis-7.5-handlers-to-handle-requests-whose-urls-do-not-end-with-a-period

TFS上のデプロイ

TFS上でWeb Deployをする場合は、以下も必要でした。

pubxmlファイルの修正

<AllowUntrustedCertificate>True</AllowUntrustedCertificate> //ここを追加

以上です。