アセンブリをロードせずに完全名を取得する

ここ最近 FxCop Integrator のコード分析と同じ動作をする MSBuild タスクを作り、ビルド実行時にカスタムタスクを呼び出してコード分析を走らせられるようにしていました。

そこで悩まされたのが、一度ビルドするとプロジェクト参照しているアセンブリをロックしてしまい、次回以降参照先プロジェクトがビルドできなくなるという現象。調べてみるとどうやら Assembly.LoadFrom() でアセンブリをロードしているのが問題のようでした。

 

バージョン 1.4.0 の頃、アセンブリ参照エラーでコード分析が実行できないという障害報告をいくつかもらっていたので、FxCop Integrator 2.0.0 にはアセンブリ参照エラーが発生したら、アセンブリ参照の解決を行ってコード分析をリトライする機能をつけました。

これが実際どう動いているかというと、

  1. コード分析実行のタイミングでプロジェクトの参照設定のリストから、参照している全てのアセンブリのパスを取得する
  2. 参照先の各アセンブリの完全名を取得し、完全名をキー、パスを値としたハッシュテーブルに格納しておく。
  3. アセンブリ参照エラーが発生したら、エラーメッセージから参照できなかったアセンブリの完全名を取得して、上記のハッシュテーブルからアセンブリのパスを探し出し、そのアセンブリも参照するようにしてコード分析をもう一度やり直す。

ということをやっています。

 

上記の 2 のところでアセンブリの完全名が必要なので、Assembly.LoadFrom() でアセンブリをロードして完全名を取得しているのですが、どうもこれがよくない模様。Visual Studio から起動された MSBuild で動いているカスタムタスクがアセンブリをロードすると、それがずっとメモリ上に常駐してしまう (結果的にアセンブリファイルがロック状態になる) らしいのです。

 

アセンブリ参照エラーの自動リカバリは捨てたくないので、別 AppDomain にロードして完全名だけ返してもらって AppDomain をアンロードするとか、アセンブリのバイナリデータを自力で解析して完全名を取得するとか色々考えたのですが、実は簡単に解決する方法がありました。

それが AssemblyName.GetAssemblyName() という static メソッド。

引数にアセンブリのパスを渡すと、AssemblyName オブジェクトを返してくるのですが、どうやらアセンブリをロードせずに完全名を取得する実装になっているらしく (バイナリを解析してる?)、このメソッドを使ってアセンブリの完全名を取得したらアセンブリファイルがロック状態になる現象は発生しなくなりました。

 

これでせっかく作った自動リカバリを捨てなくて済む。

よかった。

Comments

Popular posts from this blog

TFS: 別PCでのチェックアウトを取り消す

WPF の RichTextBox に文字列を設定する&取り出す

WPFアプリにアニメーションGIFを表示させる