Cannot find xsd.exe in the path during MSBuild community tasks. BeforeBuild step in Visual Studio

I use MSBuild community tasks to run Xsd.exe as part of my build in Visual Studio, for example:

<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.targets matches here .

However, during build I get the following error:

Failed to complete the "XSD" task.

Microsoft.Build.Shared.InternalErrorException: MSB0001: Internal error MSBuild: xsd.exe unexpectedly not rooted path

The MSDN forum is here which should be called vsvars32.bat in advance. This is a commented line in the code above. This did not work, so I found a solution here that I was hoping would make it work, namely: DEVENV with the /useenv .

Then I found another solution here that should add <xs:include schemaLocation="MSBuild\MSBuild.Community.Tasks.xsd"/> to Microsoft.Build.xsd . Does not work.

So now I have no ideas. How to get an XSD task for MSBuild community tasks without requiring developers to update the path variable, either using the /useenv solution or some other solution? I know that I can install xsd.exe in a Visual Studio solution, but this seems like a cheap workaround for me.

-1
source share
2 answers

I had to do some research to remember the comment I posted in another thread about this, but you can implement your own search path for your task based on the XSD task and overriding the GenerateFullPathToTool () method.

xsd generation tree

When you look at the XSD task in DotPeek, you can see that it comes from Microsoft.Build.Utilities.ToolTask. ToolTask ​​contains the "GenerateFullPathToTool ()" method. This method is called to return the full path to the tool, as its name implies.

The ToolLocationHelper class in the Microsoft.Build.Utilities class can be used to find the right place for your installed xsd.exe.

tool position assistant

It contains the GetPathToDotNetFrameworkSdkFile method, which will give you the fileName location for dot net sdk. Put "xsd.exe" as the parameter, and you should be good to go.

If this method does not return the path you need, there are other methods for returning various paths and their bases from the registry so that it is more portable than setting the explicit path.

+1
source

The solution for this that I have used over the years is to use the built-in task to set the path in the project file.

  <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"/> 
0
source

Source: https://habr.com/ru/post/1303230/


All Articles