首页 > 解决方案 > 带有 .netstandard 2.0 项目的 ProjectCracker

问题描述

我的团队最近从使用 .net 框架转为使用 .net 标准 2.0 来构建我们的 F# 库。我们有一些我们在项目上运行的内部脚本来自动生成 Markdown 文档,这些脚本使用 F# Compiler Services SDK 来分析代码并检索类型元数据、文档注释等。

我们正在使用该FSharp.Compiler.Service.ProjectCracker库来读取我们的.fsproj文件并生成FSharpProjectOptions运行该FSharpChecker.ParseAndCheckFileInProject方法时要使用的实例。但是,对于 .net 标准项目,调用时会出现以下错误ProjectCracker.GetProjectOptionsFromProjectFile

System.Exception: Could not load project Example.fsproj in ProjectCollection. 
Available tools: 
["C:\Program Files (x86)\MSBuild\12.0\bin\amd64";
 "C:\Program Files (x86)\MSBuild\14.0\bin\amd64";
 "C:\Windows\Microsoft.NET\Framework64\v2.0.50727";
 "C:\Windows\Microsoft.NET\Framework64\v3.5";
 "C:\Windows\Microsoft.NET\Framework64\v4.0.30319"]. 

Message: The default XML namespace of the project must be the MSBuild XML namespace. 
If the project is authored in the MSBuild 2003 format, please add xmlns="http://schemas.microsoft.com/developer/msbuild/2003" to the <Project> element. 
If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format.```

有什么方法可以使用 Project Cracker 库读取 .net 标准项目文件,还是我们需要手动解析文件并FSharpProjectOptions为我们的新库手动创建?

标签: f#.net-standardf#-compiler-services

解决方案


似乎标准的 ProjectCracker 包不能用于读取 .netstandard 项目文件。但是,已经有一个 NuGet 包可用于提供此功能,Dotnet.ProjInfo。此项目允许您读取 .NET 项目文件的所有变体,包括 .NET Framework 和 .NET Core,以及 project.json 和 .csproj/.fsproj 文件。

该项目没有作为 API 很好地记录(文档更适合命令行工具),但可以在FsAutoComplete 库中看到该工具的编程用法。

对于 .netstandard 项目,您可以使用该getProjectInfos函数,如下所示:

let getProjectInfo additionalMSBuildProps file =
    let projDir = Path.GetDirectoryName file
    let additionalInfo = 
            [ "OutputType"
              "IsTestProject"
              "Configuration"
              "IsPackable"
              MSBuildKnownProperties.TargetFramework
              "TargetFrameworkIdentifier"
              "TargetFrameworkVersion"
              "MSBuildAllProjects"
              "ProjectAssetsFile"
              "RestoreSuccess"
              "Configurations"
              "TargetFrameworks"
              "RunArguments"
              "RunCommand"
              "IsPublishable"
            ]

    let loggedMessages = System.Collections.Concurrent.ConcurrentQueue<string>()
    let msBuildExec = Dotnet.ProjInfo.Inspect.msbuild (Dotnet.ProjInfo.Inspect.MSBuildExePath.DotnetMsbuild "dotnet") (fun exePath args -> Utils.runProcess loggedMessages.Enqueue projDir exePath (args |> String.concat " "))
    let gp () = Dotnet.ProjInfo.Inspect.getProperties (["TargetPath"; "IsCrossTargetingBuild"; "TargetFrameworks"] @ additionalInfo)

    let additionalArgs = additionalMSBuildProps |> List.map (Dotnet.ProjInfo.Inspect.MSBuild.MSbuildCli.Property)

    let cliList = [Dotnet.ProjInfo.Inspect.getFscArgs; Dotnet.ProjInfo.Inspect.getResolvedP2PRefs; gp]

    file |> Dotnet.ProjInfo.Inspect.getProjectInfos loggedMessages.Enqueue msBuildExec cliList additionalArgs

推荐阅读