Windows Server 2008 R2, Windows 8で インストール済みプリンタ一覧を表示する


コンピュータのすべてのプリンタを一覧表示&名前変更: MSLabo: MCP取得や実務用に自宅でWindowsサーバを検証・自習してます&たまに日記
を参考にして実行しようとしたら、Windows Server 2008 R2, Windows8 にはなかったのでメモ。

> cscript /nologo %WINDIR%\System32\Printing_Admin_Scripts\ja-JP\prnmngr.vbs -l

Entity Framework の SQL ログ出力を行う【EFProviderWrappers編】

Entity Framework は残念な事に DBアクセス時のSQLを出力するオプションがありません。実際にどんなSQLが実行されているか把握できるようにしておかないと大抵困ります。ログ出力を行うためのラッパーが作成されているためのそれを利用します。

環境

手順

前提

既にEntity Framework を利用したASP.NET MVC アプリケーション(以下アプリケーション)が存在するとします。

EFProviderWrappers のダウンロードとビルド

  1. Tracing and Caching Provider Wrappers for Entity Framework in C# for Visual Studio 2010からソースをダウンロードします。
  2. ダウンロードした「Tracing and Caching Provider Wrappers for Entity Framework.zip」を解凍します。
  3. 「解凍先\C#\EFProviderWrappers.sln」をVisualStudio2010で開き、構成「Release」でビルドします。
  4. 「解答先\C#\EFProviderWrapperDemo\bin\Release」にある、EFProviderWrapperToolkit.dll, EFTracingProvider.dll をコピーします。

参照の追加

コピーしたDLLへの参照をアプリケーションに追加します。

拡張DbContextの作成

  1. ダウンロードしたソリューションに含まれている EFProviderWrapperDemo プロジェクトから ExtendedNorthwindEntities.cs をアプリケーションにコピーします。今回はファイル名、クラス名を NorthwindPhotoShare に置換してます。
  2. このクラスは DbContext を継承しているので*1継承元を NorthwindEFEntities からログ出力するDbContextObjectContextを継承しているクラス*2に変更します。このDbContext の名前が PhotoShareEntities の場合は、ExtendedPhotoShareEntities.cs は以下のようなソースになります。なお、DBへの接続文字列はPhotoShareEntitiesです。
public partial class ExtendedPhotoShareEntities : PhotoShareEntities
{
    private TextWriter logOutput;

    public ExtendedPhotoShareEntities()
        : this("name=PhotoShareEntities")
    {
    }

    public ExtendedPhotoShareEntities(string connectionString)
        : base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(
                connectionString,
                "EFTracingProvider"
        ))
    {
    }
}

Web.Configファイルへの登録

アプリケーションの Web.Config へ設定を追加します。

  <system.data>
    <DbProviderFactories>
      <add name="EF Tracing Data Provider" invariant="EFTracingProvider" description="Tracing Provider Wrapper" type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
    </DbProviderFactories>
  </system.data>

拡張DbContext生成メソッド、および、ログ出力メソッドの追加

ExtendedPhotoShareEntities に、CreateExtendedPhotoShareEntities というメソッドが存在します。
これを以下のように実装します。

public static ExtendPhotoShareEntities CreateExtendPhotoShareEntities()
{
    ExtendPhotoShareEntities context = new ExtendPhotoShareEntities();

    context.CommandFinished += SqlCommandFinished;

    return context;
}

private static void SqlCommandFinished(object sender, CommandExecutionEventArgs e)
{
    Logger _logger = LogManager.GetLogger("SQL");

    string sqlStr = e.Command.CommandText;

    // パラメータ名の長い順にソート
    var SortedParameters = (from p in e.Command.Parameters.Cast<DbParameter>() orderby p.ParameterName.Length descending select p );

    foreach (var parameter in SortedParameters)
    {
        sqlStr = sqlStr.Replace(parameter.ParameterName,
                    ToDbFormattedString(parameter.Value));
    }
    sqlStr = sqlStr.Replace("\r\n", " ");
    _logger.Info(sqlStr);
}

private static string ToDbFormattedString(object p)
{
    if (p is DateTime)
        return " TO_DATE('" + ((DateTime)p).ToString() + "','YYYY/MM/DD HH24:MI:SS')";
    if (p is String)
        return "'" + (p as string).Replace("'", "''") + "'";
    return p.ToString();
}

あとは DbContextのインスタンス作成を以下のように実装します。

void insert(Photo target) 
{
    using (ExtendedPhotoShareModel context = ExtendedPhotoShareEntities.CreateExtendedPhotoShareModel())
    {
        // ここにDBアクセスのを記述。
        context.Photos.Add(target);
        context.SaveChanges();
    }
}

備考

上記の置換ロジックを見るとわかりますが Oracle用のSQL、パラメータを置換してます。
つまり、ODP.NET でも出力できました。SQLServerのサンプルを見たい場合は こちらのサイト(Logging all SQL statements done by Entity Framework)やDemoプロジェクトを参考にしてください。とパラメータの形式が異なるのでログ出力メソッドを変更する必要があります。

注意

ExecuteStoreQuery について

Q and A - Tracing and Caching Provider Wrappers for Entity Framework in C# for Visual Studio 2010でも議論されていることですが、
Entity Framework で素のSQL、を発行する時はExecuteStoreQueryを使うと思います。このWrapperを利用してExecuteStoreQueryを実行すると、NoSupportedExceptionが発生します。ソース見ればわかりますが、
「DbConnectionWrapper.cs」の以下の箇所が原因です。

protected override DbCommand CreateDbCommand() 
{ 
    throw new NotSupportedException(); 
} 

ここを以下のように直せば呼び出す事はできますが、ログ出力のために発生させるイベント CommandFinished が発生しませんので注意。

protected override DbCommand CreateDbCommand() 
{ 
    return this.wrappedConnection.CreateCommand();
} 

最後に

ここまで書いておいてなんですが、VisualStudio2012形式のソリューションになっていないことや、自分で拡張したいという思いから、次回は自分でWrapperを作る予定です。なのでタイトルは【EFProviderWrappers編】となっています。サンプルが出来たらエントリを書きます。

*1:2012/11/19変更 NorthwindEFEntities はObjectContext を継承していたためDbContext を継承していると記載した箇所を削除

*2:2012/11/20変更 ObjectContextを継承したクラスを利用する必要があります。

TFS2012 自動ビルドで NUnit テストのカバレッジ結果を OpenCover で計測する #tfsug

TFS2012 自動ビルドでのNUnit テストの結果が OpenCover カバレッジを計測できない(回避策発見) - kaji_3's blog で実現できず困っていましたが、解決したので対応方法をまとめます。

環境

  • Windows8
  • VisualStudio2012
  • TFS2012
  • ReportGenerator.1.6(NuGet)
  • OpenCover.4.0.804(NuGet)
  • NUnit 2.6.1
  • TFS2012ビルドサービスのユーザは「TFSBuildUser」を使っている
  • TFSBuildUser は Administrators に所属
  • Windows8にVisualStudio2012とTFS2012をインストールしている
  • 以下のコマンドでレジストリへの登録済み
regsvr32 x86\OpenCover.Profiler.dll
regsvr32 x64\OpenCover.Profiler.dll

目的

NUnitのカバレッジを計測したかったのですが Premium を買ってもらうことができないため、OpenCoverを利用します。

前提

自動ビルド終了後に OpenCover を実行するとなぜか以下のようなメッセージが出力されます。

No results - no assemblies that matched the supplied filter were instrumented
    this could be due to missing PDBs for the assemblies that match the filter
    please review the output file and refer to the Usage guide (Usage.rtf)

原因は、ビルド後に行うテストによって pdb ファイルが OpenCover で参照できない状態になると推測していますが、ビルドプロセスの「何か」は特定ができていません。

そのため、ビルド直後に OpenCover を実行する処理をビルドプロセスに追加します。

手順

ビルドバッチの作成

前回(NUnit の OpenCover レポートを作成する - kaji_3's blog)作成したものから、ビルドサービス実行ユーザにインストールした OpenCover、ReportGeneratorのインストール先に変更しました。
また、TFSのビルドでバイナリが出力される先でテストを実行するようにしています。
(参考TFSのビルドプロセスにOpenCoverのカバレッジ計測を組み込む(前半) - Yasuo's Notebook

rem NUnitのインストール先
set nunit_home=C:\Program Files (x86)\NUnit 2.6.1

rem OpenCoverのインストール先
set opencover_home=C:\Users\TFSBuildUser\Documents\Visual Studio 2012\Projects\PhotoShare\packages\OpenCover.4.0.804

rem ReportGeneratorのインストール先
set reportgen_dir=C:\Users\TFSBuildUser\Documents\Visual Studio 2012\Projects\PhotoShare\packages\ReportGenerator.1.6.0.0

rem パスの設定
set path=%path%;%opencover_home%;%reportgen_dir%\

rem 実行するテストのアセンブリ
set target_test=PhotoShare.Domain.Tests.dll

rem 実行するテストのアセンブリの格納先
set target_dir=C:\Builds\1\KiritoFramework\PhotoShare_MainBuild\Binaries\PhotoShare

rem カバレッジ計測対象の指定
set filters=+[PhotoShare*]*

rem カレントディレクトリをアセンブリの場所に移動
cd %target_dir%

rem OpenCoverの実行
OpenCover.Console -register:user -target:"%nunit_home%\bin\nunit-console.exe" -targetargs:"/nologo %target_test%"  -output:result.xml -mergebyhash  -filter:"%filters%"

rem レポートの生成
ReportGenerator "result.xml" html
ビルドプロセスの編集

ビルドプロセスの編集方法の詳細が乗っているのでそちらを。。
TFSのビルドプロセスにOpenCoverのカバレッジ計測を組み込む(後半) - Yasuo's Notebook

OpenCover実行プロセスの追加

前提に記述した事が原因で、ビルド、テストの最後にOpenCoverを実行するとエラーになります。そのため追加する場所をビルド直後にします。
具体的には、

  • コンパイルとテスト
    • プロジェクトのコンパイルを試す
      • プロジェクトのコンパイル
        • プロジェクトに MSBuild を実行する

の直下にしてください。こんな感じで。
f:id:kaji_3:20121004011123j:plain

ビルドサービスで実行

「実行するテストのアセンブリの格納先」のフォルダにレポートが作成されます。

TFS2012 自動ビルドでのNUnit テストの結果が OpenCover カバレッジを計測できない(回避策発見)

※対応方法をまとめました→TFS2012 自動ビルドで NUnit テストのカバレッジ結果を OpenCover で計測する #tfsug - kaji_3's blog

Premium からなら、コードカバレッジが取得できますが買う事ができないため OpenCover でカバレッジを計測しようとしてます。以前のエントリ(NUnit の OpenCover レポートを作成する - kaji_3's blog)で Visual Studio でビルドした結果に対し OpenCover を利用した場合、正常にレポート出力できましたが、TFSでの自動ビルド結果ではうまくいきませんでした。

環境

  • Windows8
  • VisualStudio2012
  • TFS2012
  • ReportGenerator.1.6(NuGet)
  • OpenCover.4.0.804(NuGet)
  • NUnit 2.6.1
  • TFS2012ビルドサービスのユーザは、「TFSBuildUser」を使っている
  • TFSBuildUser は Administrators に所属
  • Windows8にVisualStudio2012とTFS2012をインストールしている
  • 以下のコマンドでレジストリへの登録済み
regsvr32 x86\OpenCover.Profiler.dll
regsvr32 x64\OpenCover.Profiler.dll

現象

VisualStudio2012でビルドした結果に対し、OpenCoverを実行するとレポートが作成されるが、
TFS2012ビルドサービスでビルドした結果に対し、OpenCoverを実行すると以下のエラーが出力される。

TFSの自動ビルドで出力されたライブラリに対し NUnit でテストを行い OpenCoverでレポートを作成しようとすると以下のエラーがでます。

Execution Runtime: net-3.5
.....
Tests run: 5, Errors: 0, Failures: 0, Inconclusive: 0, Time: 0.2241488 seconds
  Not run: 0, Invalid: 0, Ignored: 0, Skipped: 0
Committing...
No results - no assemblies that matched the supplied filter were instrumented
    this could be due to missing PDBs for the assemblies that match the filter
    please review the output file and refer to the Usage guide (Usage.rtf)

調査

TestResultsフォルダをテスト対象にする方法(参考:TFSのビルドプロセスにOpenCoverのカバレッジ計測を組み込む(前半) - Yasuo's Notebook)と回避できるもよう。

しかし、TFS2010,MSTestの場合は、TestResultsフォルダが作成され、Outフォルダ内のアセンブリが出力されるようだが、出力されない。
(出力されない原因がTFS2012なのか、NUnitなのかは未検証)

成功条件と失敗条件

  • ビルドは成功したが、以下のメッセージが出て格納フォルダへのコピー時エラーになった場合、既にビルドされているアセンブリに対しては、カバレッジが計測できる。
変更セットと作業項目を関連付ける
例外メッセージ: TF270016: ログ ファイルを 'C:\Builds\1\kaji\PhotoShare_MainBuild\Sources\PhotoShare\PhotoShare.log' から '\\altavista3\TFSworkdddd\PhotoShare_MainBuild\PhotoShare_MainBuild_20121004.1\logs' に発行するときにエラーが発生しました。詳細: ネットワーク名が見つかりません。
 (種類 PublishLogFileException)
例外スタック トレース:    場所 System.Activities.Statements.Throw.Execute(CodeActivityContext context)
   場所 System.Activities.CodeActivity.InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager)
   場所 System.Activities.Runtime.ActivityExecutor.ExecuteActivityWorkItem.ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)

推測として、この後の処理「変更セットと作業項目を関連付ける」以降で pdb ファイルに「何か」が変更が加えられて OpenCover で実行ができなくなってしまうのではないか。

対応案

ビルドプロセスでの「変更セットと作業項目を関連付ける」の前の「プロジェクトに MSBuild を実行する」完了直後に OpenCover を実行するプロセスを追加、することで解決しようと思います。対応策が実現できたら、別エントリ作成の上、ここに反映します。

NUnit の OpenCover レポートを作成する

無償のカバレッジ計測ツールがないぞーと思ったら OpenCover というのが存在したので NUnit の実行結果のレポートを生成するバッチをこちらのエントリ(.NETでのカバレッジ計測ツールOpenCover - Yasuo's Notebook)を参考にして作成しようと思います。

環境

手順

NuGetでReportGenerator、OpenCoverをインストール

両方ともNuGetで取得可能なのでインストールします。

NUnitをインストール

OpenCoverでカバレッジを計測するにはNUnitのコンソール実行版が必要なのでインストールします。
NUnit - Home

バッチファイルの作成

んで、レポート生成用バッチファイルを作成します。

rem NUnitのインストール先
set nunit_home=C:\Program Files (x86)\NUnit 2.6.1

rem OpenCoverのインストール先
set opencover_home=C:\Users\ユーザ名\Documents\Visual Studio 2012\Projects\PhotoShare\packages\OpenCover.4.0.804

rem ReportGeneratorのインストール先
set reportgen_dir=C:\Users\ユーザ名\Documents\Visual Studio 2012\Projects\PhotoShare\packages\ReportGenerator.1.6.0.0

rem パスの設定
set path=%path%;%opencover_home%;%reportgen_dir%\

rem 実行するテストのアセンブリ
set target_test=PhotoShare.Domain.Tests.dll

rem 実行するテストのアセンブリの格納先
set target_dir=C:\Users\ユーザ名\Documents\Visual Studio 2012\Projects\PhotoShare\PhotoShare.Domain.Tests\bin\Debug

rem カバレッジ計測対象の指定
set filters=+[PhotoShare*]*


rem OpenCoverの実行
OpenCover.Console -register:user -target:"%nunit_home%\bin\nunit-console.exe" -targetargs:"/nologo %target_test%"  -targetdir:"%target_dir%" -output:result.xml -mergebyhash  -filter:"%filters%"

rem レポートの生成
ReportGenerator "result.xml" html
pause

実行

実行すると、実行フォルダに html フォルダが作成されレポートが保存されます。

補足

MSTestの場合は参考エントリを見ればバッチのサンプルがありますよ!

TFS2012 自動ビルドで NUnit テストを実行する #tfsug

Visual Studio 2012 でアダプターがあれば MSTest 以外のテストフレームワークVisual Studio のテスト結果等が利用できるようになりました。となるとTFSの自動ビルドでゲートチェックインしたくなったのでその手順をまとめました。

環境

手順

拡張機能NUnit Test Adapter (Beta2) 」インストール

「ツール」→「拡張機能と更新プログラム」で「NUnit Test Adapter (Beta2)」をインストール。

拡張機能のライブラリをソース管理にチェックイン

拡張機能のライブラリをソース管理に追加します。
拡張機能のライブラリは以下の場所にあります。
最後のフォルダ名のみランダムだと思われます。(未検証)
「C:\Users\ユーザ名\AppData\Local\Microsoft\VisualStudio\11.0\Extensions\nrqj5pzy.q5q」

フォルダ内にある以下のライブラリをソース管理します。

BuildProcessTemplateと一緒の階層がいいような気がします。
ここでは以下の場所に追加します。
f:id:kaji_3:20120929231037p:plain

ビルドコントローラーにカスタムアッセンブリを設定する

Team Foundation Server 管理コンソール」を起動します。
ビルドコントローラーのプロパティを起動します。
f:id:kaji_3:20120929231100p:plain

プロパティのカスタムアッセンブリへのバージョンコントロールパスに先ほどチェックインしたライブラリのパスを入力してOKをクリックします。
f:id:kaji_3:20120929231202p:plain

ビルドの実行

ビルドを実行します。
するとNUnitで記述したテストもビルド結果に表示されます。
f:id:kaji_3:20120929231825p:plain

これでゲートチェックインも NUnit で書いたテストが対象になります。

Entity Framework Code First で VARBINARY型の列に対応するプロパティをつくる

環境


対象のプロパティの型を byte[] にします。下のサンプルだとImageプロパティが該当します。

public class Photo
{
    public int PhotoId { get; set; }
    public string Title { get; set; }
    public byte[] Image { get; set; }
}

このクラスを Code First でDBにテーブルを作成すると以下のようになります。

CREATE TABLE [dbo].[Photos] (
    [PhotoId] INT             IDENTITY (1, 1) NOT NULL,
    [Title]   NVARCHAR (MAX)  NULL,
    [Image]   VARBINARY (MAX) NULL,
    CONSTRAINT [PK_dbo.Photos] PRIMARY KEY CLUSTERED ([PhotoId] ASC)
);