2009-06-26 63 views
5

我正在编写一个验证工具来检查项目中引用的文件的版本。我想使用MSBuild使用的相同的解析过程。模仿msbuild进程的程序集解析

例如,Assembly.Load(..)需要一个完全合格的程序集名称。但是,在项目文件中,我们可能只有“System.Xml”之类的东西。 MSBuild可能使用项目的目标框架版本和其他一些启发式来决定要加载哪个版本的System.Xml。

你将如何去模仿(或直接使用)msbuild的程序集解析过程?

换句话说,在运行时,我想将字符串“System.Xml”和在.csproj文件中找到的其他信息一起找到msbuild将找到的相同文件。

回答

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 
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

如果您仍有问题,请澄清。

+0

我对汇编来自编译时的感兴趣。在运行时,我想查看XML的参考版本属性是“System.Xml”,并找到与msbuild找到的相同的程序集。 – 2009-06-26 19:34:53

+0

谢谢你试图回答。不幸的是,这些都不是运行时解决方案。 – 2009-06-30 22:49:12

1

如果你的目标,你想用的定位,而不是3.5兼容的Framework版本时,Visual Studio 2008 SP1和FxCop的1.36 RTM增加的规则CA 1903: Use only API from targeted framework,以确保您留在目标框架版本兼容。打开该规则并将其视为错误将会使构建失败并提供所需的行为。

下面是示例代码演示的时候,你的目标框架版本2的侵犯:

using System.Runtime; 

class Program 
{ 
    static void Main() 
    { 
     GCSettings.LatencyMode = GCLatencyMode.LowLatency; 
    } 
} 
1

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

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

Microsoft.Build.Shared.TypeLoader 

已方法称为

internal LoadedType Load(string typeName, AssemblyLoadInfo assembly); 

这可以帮助?

无论如何,有了反射器,你可以得到代码,并希望直接重用系统。

2

为什么不直接针对您的项目或解决方案文件调用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的Microsoft.Build.Tasks.ResolveAssemblyReference类的任务。 v3.5汇编(在我的情况下,构建3.5框架)。您可以解析项目文件,并提供ResolveAssemblyReference实例与适当的(元)数据,并让它为您执行解析 - 看起来很完美,因为这正是MSBuild所做的。