【问题标题】:Can't find xsd.exe in the path during MSBuild Community Tasks BeforeBuild step in Visual Studio在 Visual Studio 中的 MSBuild 社区任务 BeforeBuild 步骤期间无法在路径中找到 xsd.exe
【发布时间】:2017-09-24 05:26:19
【问题描述】:

我正在使用 MSBuild 社区任务来运行 Xsd.exe 作为我在 Visual Studio 中构建的一部分,如下所示:

<Import Project="$(SolutionDir)Common.targets" />
<PropertyGroup>
  <MSBuildCommunityTasksPath>$(SolutionDir)TeamBuildTypes</MSBuildCommunityTasksPath>
</PropertyGroup>
<Import Project="$(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.Targets" />
<UsingTask TaskName="XSD" AssemblyFile="$(VCTargetsPath)$(CPPTasks)" />
<Target Name="BeforeBuild">
  <!--Exec Command="'$(DevEnvDir)..\Tools\vsvars32.bat'" /-->
  <XSD Sources="MySchema.xsd" GenerateFromSchema="classes" Language="CS" />
</Target>

Common.targetshere 一致。

但是,我在构建过程中收到以下错误:

“XSD”任务意外失败。

Microsoft.Build.Shared.InternalErrorException:MSB0001:内部 MSBuild 错误:xsd.exe 意外不是根路径

MSDN论坛here已经给出了解决方案,就是在path环境变量中添加xsd.exe的路径。但是,正如 Pico Ohms 的回答所表明的那样,这是不可维护的,因为它依赖于版本,并且需要每个开发人员执行额外的步骤才能构建,只是因为 Xsd.exe。

我找到了另一个解决方案here,即事先调用 vsvars32.bat。这是上面代码中被注释掉的行。这没有用,所以我找到了一个解决方案 here,我希望它可以工作,即使用 /useenv 参数调用 DEVENV

然后我找到了另一个解决方案here,即将&lt;xs:include schemaLocation="MSBuild\MSBuild.Community.Tasks.xsd"/&gt; 添加到Microsoft.Build.xsd。也没用。

所以,现在我没有想法了。如何在不要求开发人员更新其 path 变量的情况下使用/useenv 解决方案或其他解决方案来使 MSBuild 社区任务 XSD 任务正常工作?我知道我可以将 xsd.exe 放入 Visual Studio 解决方案中,但这对我来说似乎是一种廉价的解决方法。

【问题讨论】:

    标签: xml visual-studio msbuild xsd.exe msbuildcommunitytasks


    【解决方案1】:

    我不得不做一些研究来记住我在另一个线程上发布的comment,但是您可以通过从 XSD 任务派生并覆盖 GenerateFullPathToTool() 方法来为您的任务实现自定义搜索路径。

    当您在 DotPeek 中查看 XSD 任务时,您会发现它派生自 Microsoft.Build.Utilities.ToolTask​​。 ToolTask​​ 包含一个名为“GenerateFullPathToTool()”的方法。顾名思义,调用此方法以返回工具的完整路径。

    Microsoft.Build.Utilities 类中的 ToolLocationHelper 可用于为已安装的 xsd.exe 找到合适的位置。

    它包含一个名为 GetPathToDotNetFrameworkSdkFile 的方法,它将为您提供 dot net sdk 的文件名的位置。将“xsd.exe”作为参数,你应该很高兴。

    如果该方法没有返回您需要的路径,还有其他方法可以返回各种路径及其基于注册表的路径,因此它比设置显式路径更具可移植性。

    【讨论】:

    • 谢谢,帕特里克。我会接受您的回答,因为如果这是唯一可行的解​​决方案,那么它确认它对我的需求来说太过分了。相反,我将创建一个新的构建配置,专门用于需要运行 xsd.exe 以重新生成 C# 类,并将条件 Condition="'$(Configuration)'=='DebugEnv'" 添加到 Target 参数。这样,它不会干扰不需要重新生成 C# 类的开发人员(因为它们是源代码控制的),并且只有在确实需要重新生成时,开发人员才能相应地添加路径。
    【解决方案2】:

    我多年来一直使用的解决方案是使用inline task 在项目文件中设置路径。

     <ItemGroup>   
        <!-- Configure XSD files by using the XsdClasses custom item type.  All files of this type are converted by the GenerateXsdClasses target. --> 
        <XsdClasses Include="Data\XsdFile1.xsd">
          <SubType>Designer</SubType>
        </XsdClasses>
         <XsdClasses Include="Data\XsdFile2.xsd">
          <SubType>Designer</SubType>
        </XsdClasses>
      </ItemGroup>
    
    
      <!-- In-line task to add a folder to the current path if not already in it. -->
      <UsingTask TaskName="AddToPath" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
        <ParameterGroup>
          <FolderPath ParameterType="System.String" Required="true" />
        </ParameterGroup>
    
        <Task>
          <Code Type="Fragment" Language="c#"><![CDATA[
                const string PathEnvironmentVariableName = "PATH";
                string currentPath = Environment.GetEnvironmentVariable(PathEnvironmentVariableName);
                if(!currentPath.ToLower().Contains(FolderPath.ToLower()))
                {
                    currentPath = currentPath.TrimEnd(';');
                    string newPath = string.Format("{0};{1}", currentPath, FolderPath);
                    Environment.SetEnvironmentVariable(PathEnvironmentVariableName, newPath);
                }
    ]]></Code>
        </Task>   
      </UsingTask>
    
      <!-- Reference the Xsd task. -->
      <UsingTask TaskName="XSD" AssemblyFile="$(VCTargetsPath)Microsoft.Build.CppTasks.Common.dll" />
    
      <!-- Set the default path to Xsd.exe - this will be added to the current path using the above inline task.  Can be overridden per client by setting a user or machine environment variable with the same name. -->
      <PropertyGroup>
        <NetFxToolsPath Condition="'$(NetFxToolsPath)' == ''">C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.7 Tools\</NetFxToolsPath>
      </PropertyGroup>
    
    
      <!-- Generate classes from xsd files configured with 'XsdClasses' item type. -->
      <Target Name="GenerateXsdClasses" Inputs="@(XsdClasses)" Outputs="@(XsdClasses->'%(RelativeDir)%(Filename).cs')">
        <Message Importance="high" Text="Building %(XsdClasses.Filename)" />
        <AddToPath FolderPath="$(NetFxToolsPath)" />
        <!-- Note the trailing . in the outputdir because the folder ends with a / -->
        <XSD MinimalRebuildFromTracking="true" Sources="%(XsdClasses.Identity)" GenerateFromSchema="classes" Namespace="XsdClassesNamespace" SuppressStartupBanner="true" AdditionalOptions="/outputdir:&quot;%(XsdClasses.RelativeDir).&quot;" />
      </Target>
    
      <!-- Configure class generation from xsd to occur before build. -->
      <Target Name="BeforeBuild" DependsOnTargets="GenerateXsdClasses"/>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-02
      • 2017-02-01
      • 2012-01-09
      相关资源
      最近更新 更多