5

プロジェクトで参照されているファイルのバージョンをチェックする検証ツールを作成しています。MSBuild が使用するのと同じ解決プロセスを使用したいと考えています。

たとえば、Assembly.Load(..) には完全修飾アセンブリ名が必要です。ただし、プロジェクト ファイルには、「System.Xml」のようなものしかない場合があります。MSBuild はおそらく、プロジェクトのターゲット フレームワーク バージョンとその他のヒューリスティックを使用して、読み込む System.Xml のバージョンを決定します。

msbuild のアセンブリ解決プロセスをどのように模倣 (または直接使用) しますか?

つまり、実行時に、文字列 "System.Xml" を .csproj ファイルにある他の情報と共に取得し、msbuild が検索するのと同じファイルを検索します。

4

7 に答える 7

3

今日、この問題が発生しました。その方法については、次の古いブログ記事を見つけました。

http://blogs.msdn.com/b/jomo_fisher/archive/2008/05/22/programmatically-resolve-assembly-name-to-full-path-the-same-way-msbuild-does.aspx

私はそれを試してみました、うまくいきます!可能な場合はアセンブリの 4.5.1 バージョンを見つけるようにコードを変更しました。これが現在の状態です。

#if INTERACTIVE
#r "Microsoft.Build.Engine" 
#r "Microsoft.Build.Framework"
#r "Microsoft.Build.Tasks.v4.0"
#r "Microsoft.Build.Utilities.v4.0"
#endif

open System
open System.Reflection
open Microsoft.Build.Tasks
open Microsoft.Build.Utilities
open Microsoft.Build.Framework
open Microsoft.Build.BuildEngine

/// Reference resolution results. All paths are fully qualified.
type ResolutionResults = {
    referencePaths:string array
    referenceDependencyPaths:string array
    relatedPaths:string array
    referenceSatellitePaths:string array
    referenceScatterPaths:string array
    referenceCopyLocalPaths:string array
    suggestedBindingRedirects:string array
    }


let resolve (references:string array, outputDirectory:string) =
    let x = { new IBuildEngine with
                member be.BuildProjectFile(projectFileName, targetNames, globalProperties, targetOutputs) = true
                member be.LogCustomEvent(e) = ()
                member be.LogErrorEvent(e) = ()
                member be.LogMessageEvent(e) = ()
                member be.LogWarningEvent(e) = ()
                member be.ColumnNumberOfTaskNode with get() = 1
                member be.ContinueOnError with get() = true
                member be.LineNumberOfTaskNode with get() = 1
                member be.ProjectFileOfTaskNode with get() = "" }

    let rar = new ResolveAssemblyReference()
    rar.BuildEngine <- x
    rar.IgnoreVersionForFrameworkReferences <- true
    rar.TargetFrameworkVersion <- "v4.5.1"
    rar.TargetedRuntimeVersion <- "v4.5.1"
    rar.TargetFrameworkDirectories <- [||] //[|@"C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\"|]
    rar.Assemblies <- [|for r in references -> new Microsoft.Build.Utilities.TaskItem(r) :> ITaskItem|]
    rar.AutoUnify <- true
    rar.SearchPaths <- [| "{CandidateAssemblyFiles}"
                          "{HintPathFromItem}"
                          "{TargetFrameworkDirectory}"
                         // "{Registry:Software\Microsoft\.NetFramework,v3.5,AssemblyFoldersEx}"
                          "{AssemblyFolders}"
                          "{GAC}"
                          "{RawFileName}"
                          outputDirectory |]

    rar.AllowedAssemblyExtensions <- [| ".exe"; ".dll" |]
    rar.TargetProcessorArchitecture <- "x86"
    if not (rar.Execute()) then
        failwith "Could not resolve"
    {
        referencePaths = [| for p in rar.ResolvedFiles -> p.ItemSpec |]
        referenceDependencyPaths = [| for p in rar.ResolvedDependencyFiles -> p.ItemSpec |]
        relatedPaths = [| for p in rar.RelatedFiles -> p.ItemSpec |]
        referenceSatellitePaths = [| for p in rar.SatelliteFiles -> p.ItemSpec |]
        referenceScatterPaths = [| for p in rar.ScatterFiles -> p.ItemSpec |]
        referenceCopyLocalPaths = [| for p in rar.CopyLocalFiles -> p.ItemSpec |]
        suggestedBindingRedirects = [| for p in rar.SuggestedRedirects -> p.ItemSpec |]
    }



[<EntryPoint>]
let main argv = 
    try
      let s = resolve([| "System"
                         "System.Data"
                         "System.Core, Version=4.0.0.0"
                         "Microsoft.SqlServer.Replication" |], "")
      printfn "%A" s.referencePaths
    finally
      ignore (System.Console.ReadKey())

    0
于 2014-06-03T11:32:10.347 に答える
2

これはあなたが本当にやりたいことをする方法をあなたに示すはずです、しかし私はあなたが私が提供したFXCopの答えを使うべきだと思います。

static void Main()
    {
        string targetFile = @"test.csproj";
        XDocument xmlDoc = XDocument.Load(targetFile);
        XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";

        var references = from reference in xmlDoc.Descendants(ns + "ItemGroup").Descendants(ns + "Reference")
                         select reference.Attribute("Include").Value;

        foreach (var reference in references)
        {
            Assembly.LoadWithPartialName(reference);
        }

        foreach (var item in AppDomain.CurrentDomain.GetAssemblies())
        {
            var assemblyVersion = ((AssemblyFileVersionAttribute)item.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), true)[0]).Version.ToString();
            Console.WriteLine("\r\nFullname:\t{0}\r\nFileVersion:\t{1}", item.FullName, assemblyVersion);

        }
        Console.WriteLine("\r\nPress any key to continue");
        Console.ReadKey();
    }
于 2009-07-02T19:11:25.650 に答える
2

3.5 をターゲットにするのではなく、互換性を持たせたいフレームワーク バージョンをターゲットにする場合、Visual Studio 2008 SP1 および FxCop 1.36 RTM は、ルールCA 1903: ターゲット フレームワークの API のみを使用して、ターゲット フレームワーク バージョンとの互換性を維持できるようにします。そのルールをオンにしてエラーとして扱うと、ビルドが失敗し、必要な動作が提供されます。

フレームワーク バージョン 2 をターゲットにしている場合の違反を示すサンプル コードを次に示します。

using System.Runtime;

class Program
{
    static void Main()
    {
        GCSettings.LatencyMode = GCLatencyMode.LowLatency;
    }
}
于 2009-07-02T16:40:47.567 に答える
2

プロジェクトまたはソリューション ファイルに対して msbuild を呼び出し、/v:d 拡張子を渡して、出力ファイルから必要な情報を解析してみませんか? たとえば、アセンブリの解像度ごとに次のようなものが表示されます。

  プライマリ リファレンス「System.Data、Version=2.0.0.0、Culture=neutral、PublicKeyToken=b77a5c561934e089」。
      解決されたファイル パスは「c:\WINNT\Microsoft.NET\Framework\v2.0.50727\System.Data.dll」です。
      検索パスの場所「{TargetFrameworkDirectory}」で参照が見つかりました。
          SearchPath "{TargetFrameworkDirectory}" の場合。
          「C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.exe」と考えましたが、存在しませんでした。
          「C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.dll」と考えましたが、存在しませんでした。
          「C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\System.Data.exe」と考えましたが、存在しませんでした。
          「C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\System.Data.dll」と考えましたが、存在しませんでした。
          「c:\WINNT\Microsoft.NET\Framework\v3.5\System.Data.exe」と見なされましたが、存在しませんでした。
          「c:\WINNT\Microsoft.NET\Framework\v3.5\System.Data.dll」と考えましたが、存在しませんでした。
          「c:\WINNT\Microsoft.NET\Framework\v3.0\System.Data.exe」と見なされましたが、存在しませんでした。
          「c:\WINNT\Microsoft.NET\Framework\v3.0\System.Data.dll」と考えましたが、存在しませんでした。
          「c:\WINNT\Microsoft.NET\Framework\v2.0.50727\System.Data.exe」と考えましたが、存在しませんでした。
      この参照は前提条件ファイルであるため、「CopyLocal」ではありません。

または、MSBuild は、アセンブリを解決するタスクを Microsoft.Build.Tasks.v3.5 アセンブリから Microsoft.Build.Tasks.ResolveAssemblyReference クラスに委任します (私の場合は、3.5 フレームワークに対してビルドします)。プロジェクト ファイルを解析し、適切な (メタ) データを使用して ResolveAssemblyReference のインスタンスを提供し、解決を実行させることができます。これはまさに MSBuild が行うことなので、完璧に思えます。

于 2009-11-20T18:40:13.470 に答える
1

Reflectorの無料コピーを入手した場合は、MSBuild.exe ファイル自体の内部を調べることができます。クラスがあることに気がついた

Microsoft.Build.Shared.TypeLoader

と呼ばれるメソッドを持っています

internal LoadedType Load(string typeName, AssemblyLoadInfo assembly);

どれが役立つでしょうか?

とにかく、リフレクターを使用するとコードを取得でき、できればシステムを直接再利用できます。

于 2009-07-03T20:10:12.490 に答える
0

CLR解決プロセスを直接模倣するために、カスタムMSBuildタスクを作成できますが、それが何を達成するかはわかりません。

MSBuildはアセンブリを解決しません。それらはCLRによって解決されます。この記事では、ランタイムがアセンブリを解決する方法について説明します:http: //msdn.microsoft.com/en-us/library/yx7xezcf.aspx

Visual Studioを使用している場合、システムアセンブリはファイルシステムから取得されますが、実行時に読み込まれる場合はGACから取得されます。 http://p3net.mvps.org/Topics/Basics/IntegratingGACWithVS.aspx

それでも質問がある場合は、明確にしてください。

于 2009-06-26T19:12:25.990 に答える
0

これは役立つかもしれません: MSBuild でのバイナリ参照の解決

于 2009-07-03T20:04:00.957 に答える