该MSBuild的过程中模仿大会决议(Mimicking assembly resolution o

2019-07-29 08:14发布

我写一个验证工具,检查项目中的引用文件的版本。 我想使用的MSBuild使用相同的解决过程。

例如,Assembly.Load(..)需要一个完全合格的组件名称。 然而,在项目文件中,我们可能只有类似“的System.Xml”。 的MSBuild可能使用该项目的目标框架版本和其他一些试探法来决定要加载哪个的System.Xml的版本。

你会如何去模仿(或直接使用)的MSBuild的决议过程?

换句话说,在运行时,我想借此字符串“的System.Xml”,在一个.csproj的文件中找到的其他信息一起,发现的MSBuild会发现同一个文件。

Answer 1:

如果你的目标框架版本,你想与定位,而不是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;
    }
}


Answer 2:

我今天有这个问题,我发现怎么做这个老博客文章:

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


Answer 3:

这应该告诉你怎么做你真正想要的,但我认为你应该使用我公司提供的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();
    }


Answer 4:

为什么不只是调用的MSBuild对你的项目或解决方案文件,它传递/ V:d延伸,并解析你想要的信息的输出文件? 例如,你将看到类似的每个大会决议如下:

  Primary reference "System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".
      Resolved file path is "c:\WINNT\Microsoft.NET\Framework\v2.0.50727\System.Data.dll".
      Reference found at search path location "{TargetFrameworkDirectory}".
          For SearchPath "{TargetFrameworkDirectory}".
          Considered "C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.exe", but it didn't exist.
          Considered "C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.Data.dll", but it didn't exist.
          Considered "C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\System.Data.exe", but it didn't exist.
          Considered "C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\System.Data.dll", but it didn't exist.
          Considered "c:\WINNT\Microsoft.NET\Framework\v3.5\System.Data.exe", but it didn't exist.
          Considered "c:\WINNT\Microsoft.NET\Framework\v3.5\System.Data.dll", but it didn't exist.
          Considered "c:\WINNT\Microsoft.NET\Framework\v3.0\System.Data.exe", but it didn't exist.
          Considered "c:\WINNT\Microsoft.NET\Framework\v3.0\System.Data.dll", but it didn't exist.
          Considered "c:\WINNT\Microsoft.NET\Framework\v2.0.50727\System.Data.exe", but it didn't exist.
      This reference is not "CopyLocal" because it's a prerequisite file.

另外,代表们的MSBuild解决组件从组装Microsoft.Build.Tasks.v3.5的Microsoft.Build.Tasks.ResolveAssemblyReference类(在我的情况下,建立对3.5框架)的任务。 您可以分析项目文件并用适当的(元)数据提供ResolveAssemblyReference的实例,并让它执行该决议为你 - 似乎完美的,因为这是MSBuild的不正是。



Answer 5:

如果你让自己的免费副本反射 ,你可以检查MSBuild.exe的内部文件本身。 我注意到有一类

Microsoft.Build.Shared.TypeLoader

具有调用的方法

internal LoadedType Load(string typeName, AssemblyLoadInfo assembly);

这可以帮助?

总之,随着反射镜可以得到的代码,并希望直接重用系统。



Answer 6:

要直接模仿CLR分辨率过程中,你可以写一个自定义的MSBuild任务,虽然我看不出有什么会实现。

的MSBuild不能解决组件。 它们由CLR解决。 本文介绍了运行时如何解决组件: http://msdn.microsoft.com/en-us/library/yx7xezcf.aspx

当你在Visual Studio中的系统组件来自于文件系统,但是当它们在运行时加载它们来自GAC。 http://p3net.mvps.org/Topics/Basics/IntegratingGACWithVS.aspx

如果您还有疑问,请澄清。



Answer 7:

这可能帮助: 在MSBuild的解决二进制参考



文章来源: Mimicking assembly resolution of the msbuild process