I currently create my first MSBuild-script.
I've a tag "Folders" that findes all Directories in a given root path:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Target Name="Build">
<PropertyGroup>
<RootFolder>tmp</RootFolder>
</PropertyGroup>
<ItemGroup>
<Folders Include="$([System.IO.Directory]::GetDirectories("$(RootFolder)"))"/>
</ItemGroup>
<Message Text="#(Folders -> '%(FullPath)\Bin\Debug\%(Filename)%(Extension).dll', ';')"/>
</Target>
</Project>
That works perfect.
My problem is that I only need directories where the specified file exists.
I tried a condition like that
Condition="$([System.IO.File]::Exists("%(FullPath)\\Bin\\Debug\\%(Filename)%(Extension).dll"))"
for the folder tag.
This script runs without any error but my list is empty.
Why?
Are there any other solutions to check for a file?
I used this solution because it uses C# and I'm a C#-developer.
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<Target Name="Build">
<PropertyGroup>
<RootFolders>tmp</RootFolders>
</PropertyGroup>
<GetFiles rootFolders="$(RootFolders)">
<Output PropertyName="Files" TaskParameter="Files" />
</GetFiles>
<Message Text="$(Files)" />
</Target>
<UsingTask
TaskName="GetFiles"
TaskFactory="CodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
<ParameterGroup>
<rootFolders ParameterType="System.String" Required="true" />
<files ParameterType="System.String" Output="true" />
</ParameterGroup>
<Task>
<Using Namespace="System" />
<Using Namespace="System.IO" />
<Using Namespace="System.Linq" />
<Code Type="Fragment" Language="cs">
<![CDATA[
Func<string, string> BuildFilePath = path => path + #"\Bin\Debug\" + Path.GetFileName(path) + ".dll";
var dirs = Directory.GetDirectories(rootFolders).Where(x => File.Exists(BuildFilePath(x)));
files = string.Join("\n", dirs.Select(BuildFilePath));
]]>
</Code>
</Task>
</UsingTask>
</Project>
AFAIK, the thing is Condition is executed and checked for the whole declaration of Items (i.e. <Folders ..> tag).
I think, you need to loop through the collection (e.g. using target/task batching) and check the file to exist in every single folder folder in the collection. Then if the file exists - include it in the new <FoldersFiletered> items collection.
NB: I don't have time to test the code now, but this is the idea roughly:
<Target Name="FilterFolders"
Inputs="#(Folders)"
Outputs="%(FullPath)">
<ItemGroup>
<FoldersFiltered Include="#(Folders->'%(FullPath)')"
Condition="$([System.IO.File]::Exists("#(Folders->'%(FullPath)'\\Bin\\Debug\\YourFile.dll"))" />
</ItemGroup>
</Target>
Related
NLog produces the following log filename MyMachine_MyExe_1.0.0.0.log. It includes the assembly version, but not the git's commit id which can be seen in dll's Product version property below.
Is there a way, either via NLog.config or programmatically to include the git's commit id in the log's filename?
NLog.config
<variable name="callsite" value="${callsite:includeNamespace=false:className=true:methodName=true}"/>
<variable name="baseLogDir" value="logs" />
<variable name="baseLogFilename" value="${machinename}_${processname}_${assembly-version}" />
<variable name="debugTraceLayout" value="${longdate}|${level:uppercase=true}|${callsite}|${message}" />
<targets>
<target
xsi:type="Console"
name="console"
layout="${longdate}|${level:uppercase=true}|${message}" />
<target xsi:type="File"
name="fileInfo"
fileName="${baseLogDir}/${baseLogFilename}.log"
layout="${longdate}|${level:uppercase=true}|${message}"
archiveFileName="${baseLogDir}/archive/${baseLogFilename}_{#}.log"
archiveNumbering="Date"
archiveOldFileOnStartup="true"
archiveDateFormat="yyyyMMdd_HHmmss" />
MyProject.csproj
<Project Sdk="Microsoft.NET.Sdk">
<Target Name="SetSourceRevisionId" BeforeTargets="InitializeSourceControlInformation">
<Exec Command="git describe --long --always --dirty --exclude=* --abbrev=8" ConsoleToMSBuild="True" IgnoreExitCode="False">
<Output PropertyName="SourceRevisionId" TaskParameter="ConsoleOutput" />
</Exec>
</Target>
</Project>
MyLibrary.dll Properties
I would define additional assembly attributes in your msbuild project;
<Project Sdk="Microsoft.NET.Sdk">
<Target Name="SetSourceRevisionId" BeforeTargets="InitializeSourceControlInformation">
<Exec ...></Exec>
<ItemGroup>
<AssemblyMetadata Include="SourceRevisionId" Value="$(SourceRevisionId)" />
</ItemGroup>
</Target>
</Project>
Which I believe you can use to define NLog's Global Diagnostic Context (GDC)
GlobalDiagnosticsContext.Set(
"SourceRevisionId",
typeof(Program).Assembly
.GetCustomAttributes<AssemblyMetadataAttribute>()
.Where(a => a.Key == "SourceRevisionId")
.Single()
.Value
);
And define the output filename;
fileName="${baseLogDir}/${gdc:item=SourceRevisionId}.log"
I am working with a client to deploy a WPF application using Blazor Desktop. We have a couple of resources the application needs in order to run. I have them specified in an item group like so:
<ItemGroup>
<Content Update="wwwroot\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
It works fine when running the WPF directly in debug mode, but if I run through my MSIX installer I get a directory not found exception because it is looking for the folder that contains those resources inside of C:\Windows\System32. I feel like I am missing something in the appxmanifest, which is below
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity
Name="0f515ea1-7f17-43cd-949f-2ddde5e8176a"
Publisher="CN=SampleCo"
Version="1.0.0.0" />
<Properties>
<DisplayName>CompanyPortal.Installer</DisplayName>
<PublisherDisplayName>SampleCo</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="My App"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png" Description="Admin Portal for the TallyIO System">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" />
<uap:SplashScreen Image="Images\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>
Also here is my csproj for the msix project
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '15.0'">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x86">
<Configuration>Debug</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x86">
<Configuration>Release</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|AnyCPU">
<Configuration>Debug</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|AnyCPU">
<Configuration>Release</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup>
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
</PropertyGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
<PropertyGroup>
<ProjectGuid>0d34caa9-b40d-4e58-9045-11d2bcfb4e9d</ProjectGuid>
<TargetPlatformVersion>10.0.22000.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.14393.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>
<AppxPackageSigningEnabled>True</AppxPackageSigningEnabled>
<NoWarn>$(NoWarn);NU1702</NoWarn>
<EntryPointProjectUniqueName>..\CompanyPortal.Desktop\CompanyPortal.Desktop.csproj</EntryPointProjectUniqueName>
<PackageCertificateThumbprint>66AD090A86AB81268A60B29B3FE0455B5E09446A</PackageCertificateThumbprint>
<PackageCertificateKeyFile>CompanyPortal.Installer_TemporaryKey.pfx</PackageCertificateKeyFile>
</PropertyGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<None Include="CompanyPortal.Installer_TemporaryKey.pfx" />
<Content Include="Images\SplashScreen.scale-200.png" />
<Content Include="Images\LockScreenLogo.scale-200.png" />
<Content Include="Images\Square150x150Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Images\StoreLogo.png" />
<Content Include="Images\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.194" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CompanyPortal.Desktop\CompanyPortal.Desktop.csproj" />
</ItemGroup>
</Project>
Is there something I am missing or is it possible to deploy a Blazor Desktop Application using MSIX?
Thank You,
I suspect this is happening because that folder is not virtualized by the OS, when packaged inside the MSIX.
As I explain in this article, only a certain list of system folders are virtualized by the MSIX container, the list provided by Microsoft is included in the article.
Any other folder must be either copied from the install location to the real location at first launch, or (if you need read-only access) you use PSF to redirect the API calls and serve it from your install path.
What I recommend to you:
launch a CMD inside the MSIX container context and run a dir on the install folder (ProgramFiles\WindowsApps\yourapp) to see if the files are actually installed on the machine
if they are there, copy them manually in the IIS wwwroot folder and try running the application again. If this works, it means you need to automate this copy at first launch of your app.
If not, then you need to use the PSF to redirect API calls (read-only) to load the resources from the install location (WindowsApps folder).
I want to verify that the version being used when packing some nuget-packages using dotnet build /p:VERSION=1.2.3 and GeneratePackageOnBuild. My regex expressen is working in LINQPad 6 using C#:
Regex.Match("1.2.3", #"^\d{1,3}\.\d{1,3}\.\d{1,6}(-(beta|rc)(\d{1,1})?)?$")
However in my default.props that is being imported by all csproj-files (which are using the new sdk-style, if that is relevant) I have this and it is not working at all:
<Target Name="ValidateVersion" BeforeTargets="BeforeBuild">
<PropertyGroup>
<VersionRegex>^\d{1,3}\.\d{1,3}\.\d{1,6}(-(beta|rc)(\d{1,1})?)?$</VersionRegex>
<VersionTest>1.2.3</VersionTest> <!-- Just to make it easier during testing -->
</PropertyGroup>
<Error
Text="Version is not following the correct format: $(VersionRegex)"
Condition=" $([System.Text.RegularExpressions.Regex]::IsMatch('$(VersionTest)', `$(VersionRegex)`)) " />
</Target>
It does not matter if I inline VersionRegex and VersionTest, it is still not working. Any ideas why it is working in C# but not in MSBuild?
From your original example, you should be able to put the content of the VersionRegex property within CDATA:
<Target Name="ValidateVersion" BeforeTargets="BeforeBuild">
<PropertyGroup>
<VersionRegex><![CDATA[^\d{1,3}\.\d{1,3}\.\d{1,6}(-(beta|rc)(\d{1,1})?)?$]]></VersionRegex>
<VersionTest>1.2.3</VersionTest>
</PropertyGroup>
<Error
Text="Version is not following the correct format: $(VersionRegex)"
Condition="!$([System.Text.RegularExpressions.Regex]::IsMatch('$(VersionTest)', '$(VersionRegex)'))" />
</Target>
Workaround
I haven't found the actual issue but a workaround is, as #Viet Hoang mentioned in the comments, to use CDATA:
Targets/ValidateVersioning.targets:
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<UsingTask
TaskName="ValidateVersion"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll" >
<ParameterGroup>
<Version ParameterType="System.String" Required="true" />
</ParameterGroup>
<Task>
<Using Namespace="System"/>
<Using Namespace="System.IO"/>
<Using Namespace="System.Text.RegularExpressions"/>
<Code Type="Fragment" Language="cs">
<![CDATA[
if (!Regex.Match(Version, #"^\d{1,3}\.\d{1,3}\.\d{1,6}(-(beta|rc)(\d{1,1})?)?$").Success)
{
Log.LogError("Version has wrong format: {0}", Version);
return false;
}
]]>
</Code>
</Task>
</UsingTask>
</Project>
default.props:
<Project>
...
<Import Project="Targets\ValidateVersioning.targets" />
<Target Condition="$(VERSION) != ''" Name="ValidateVersion" BeforeTargets="BeforeBuild">
<ValidateVersion Version="$(VERSION)" />
</Target>
...
</Project>
> dotnet build --no-restore -p:Version=1.3.4 will work but
> dotnet build --no-restore -p:Version=1.3 will not build
I'm upgrading a project from AspNet Mvc 4 to AspNet Core Mvc 2.2; I am attempting to migrate the msbuild build.proj file to set the version and other attributes for the projects that create dll's; everything is working except the GenerateAssemblyInfo task. Is there a new way to do this in netcoreapp2.2?
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="GetRevisionInfo" BeforeTargets="Build">
<GitPendingChanges ContinueOnError="WarnAndContinue">
<Output TaskParameter="HasPendingChanges" PropertyName="HasPendingChanges" />
</GitPendingChanges>
<!--This will throw git Error 128 if there are no Tags -->
<GitDescribe SoftErrorMode="true" Lightweight="true" ContinueOnError="WarnAndContinue">
<Output TaskParameter="Tag" PropertyName="Tag" />
<Output TaskParameter="CommitCount" PropertyName="CommitCount" />
<Output TaskParameter="CommitHash" PropertyName="CommitHash" />
</GitDescribe>
<GitBranch ContinueOnError="WarnAndContinue">
<Output TaskParameter="Branch" PropertyName="Branch" />
</GitBranch>
<PropertyGroup>
<ShortCommitHash Condition="'$(CommitHash)' != ''">$(CommitHash.Substring(0,6))</ShortCommitHash>
<ReleaseType Condition="'$(CommitCount)' != '' AND '$(CommitCount)' != '0'">Beta</ReleaseType>
<ReleaseType Condition="'$(Branch)' != '' AND '$(Branch)' != 'master'">Alpha</ReleaseType>
</PropertyGroup>
</Target>
<!-- Error out if this is a release and our working copy has uncommitted changes -->
<Target Name="CheckRelease" AfterTargets="GetRevisionInfo" Condition="'$(Configuration)' == 'Release'">
<Error Text="Cannot build a Release Version when there are uncommitted changes, commit or revert all changes." Condition="'$(CommitHash)' != '' AND '$(HasPendingChanges)' == 'True'" />
</Target>
<!-- Generates AssemblyInfo file using Git Describe -->
<Target Name="GenerateAssemblyInfo" AfterTargets="CheckRelease" Condition="'$(CommitHash)' != ''">
<Time>
<Output TaskParameter="Year" PropertyName="Year" />
</Time>
<AssemblyInfo
CodeLanguage="CS"
OutputFile="$(MSBuildProjectDirectory)\Properties\AssemblyInfo.cs"
AssemblyProduct="$(MSBuildProjectName) $(ReleaseType)"
AssemblyCompany="xxx xxx xxx, LLC"
AssemblyCopyright="Copyright © $(Year) xxx xxx xxx, LLC. All rights reserved."
AssemblyConfiguration="$(Configuration)-$(Platform)"
AssemblyVersion="$(Tag).$(CommitCount)"
AssemblyFileVersion="$(Tag).$(CommitCount)"
AssemblyInformationalVersion ="$(Tag)-$(CommitCount)-$(ShortCommitHash) $(ReleaseType)"
AssemblyTitle="$(Tag)-$(CommitCount)-$(CommitHash)"/>
</Target>
<!-- copy framework files to libraries -->
<Target Name="CopyLibraries" Condition="'$(MSBuildProjectName)' == 'BaseApplication'" AfterTargets="Build">
<CreateItem Include="$(TargetDir)xxx.*">
<Output TaskParameter="Include" PropertyName="CopyFiles" />
</CreateItem>
<Copy SourceFiles="$(CopyFiles)" DestinationFolder="$(MSBuildProjectDirectory)\..\libraries\xxx\$(Configuration)"/>
</Target>
<Target Name="CopyKendoUI" AfterTargets="AfterBuild">
<ItemGroup>
<KendoFiles Include="
$(TargetDir)kendo.mvc.*;
$(TargetDir)\**\Kendo.Mvc.resources.*;" />
</ItemGroup>
<Copy SourceFiles="#(KendoFiles)" DestinationFolder="$(MSBuildProjectDirectory)\..\libraries\kendoui\$(Configuration)\%(RecursiveDir)"/>
</Target>
</Project>
There were a few things preventing this from working in Visual Studio 2019 using .Net Core;
The name of the target cannot be "GenerateAssemblyInfo", if this is the name of the target, it just gets ignored, no error, warning, or message, the target just doesn't run...
In the csproj file for the project that the msbuild project is imported in, you need to add false, I added this right below the
You have to manually create the Properties folder if you set the OutputFile to be in that folder.
Below is the working build.proj file
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name="GetRevisionInfo" BeforeTargets="Build">
<GitPendingChanges ContinueOnError="WarnAndContinue">
<Output TaskParameter="HasPendingChanges" PropertyName="HasPendingChanges" />
</GitPendingChanges>
<!--This will throw git Error 128 if there are no Tags -->
<GitDescribe SoftErrorMode="true" Lightweight="true" ContinueOnError="WarnAndContinue">
<Output TaskParameter="Tag" PropertyName="Tag" />
<Output TaskParameter="CommitCount" PropertyName="CommitCount" />
<Output TaskParameter="CommitHash" PropertyName="CommitHash" />
</GitDescribe>
<GitBranch ContinueOnError="WarnAndContinue">
<Output TaskParameter="Branch" PropertyName="Branch" />
</GitBranch>
<PropertyGroup>
<ShortCommitHash Condition="'$(CommitHash)' != ''">$(CommitHash.Substring(0,6))</ShortCommitHash>
<ReleaseType Condition="'$(CommitCount)' != '' AND '$(CommitCount)' != '0'">Beta</ReleaseType>
<ReleaseType Condition="'$(Branch)' != '' AND '$(Branch)' != 'master'">Alpha</ReleaseType>
</PropertyGroup>
</Target>
<!-- Error out if this is a release and our working copy has uncommitted changes -->
<Target Name="CheckRelease" AfterTargets="GetRevisionInfo" Condition="'$(Configuration)' == 'Release'">
<Error Text="Cannot build a Release Version when there are uncommitted changes, commit or revert all changes." Condition="'$(CommitHash)' != '' AND '$(HasPendingChanges)' == 'True'" />
</Target>
<!-- Generates AssemblyInfo file using Git Describe -->
<Target Name="GenerateAssemblyInfo" AfterTargets="CheckRelease" Condition="'$(CommitHash)' != ''">
<Time>
<Output TaskParameter="Year" PropertyName="Year" />
</Time>
<AssemblyInfo
CodeLanguage="CS"
OutputFile="$(MSBuildProjectDirectory)\Properties\AssemblyInfo.cs"
AssemblyProduct="$(MSBuildProjectName) $(ReleaseType)"
AssemblyCompany="xxx xxx xxx, LLC"
AssemblyCopyright="Copyright © $(Year) xxx xxx xxx, LLC. All rights reserved."
AssemblyConfiguration="$(Configuration)-$(Platform)"
AssemblyVersion="$(Tag).$(CommitCount)"
AssemblyFileVersion="$(Tag).$(CommitCount)"
AssemblyInformationalVersion ="$(Tag)-$(CommitCount)-$(ShortCommitHash) $(ReleaseType)"
AssemblyTitle="$(Tag)-$(CommitCount)-$(CommitHash)"/>
</Target>
<!-- copy framework files to libraries -->
<Target Name="CopyLibraries" Condition="'$(MSBuildProjectName)' == 'BaseApplication'" AfterTargets="Build">
<CreateItem Include="$(TargetDir)xxx.*">
<Output TaskParameter="Include" PropertyName="CopyFiles" />
</CreateItem>
<Copy SourceFiles="$(CopyFiles)" DestinationFolder="$(MSBuildProjectDirectory)\..\libraries\xxx\$(Configuration)"/>
</Target>
<Target Name="CopyKendoUI" AfterTargets="AfterBuild">
<ItemGroup>
<KendoFiles Include="
$(TargetDir)kendo.mvc.*;
$(TargetDir)\**\Kendo.Mvc.resources.*;" />
</ItemGroup>
<Copy SourceFiles="#(KendoFiles)" DestinationFolder="$(MSBuildProjectDirectory)\..\libraries\kendoui\$(Configuration)\%(RecursiveDir)"/>
</Target>
</Project>
And the MyProject.csproj file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MSBuildTasks" Version="1.5.0.235">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.AspNetCore.Http.Abstractions">
<HintPath>C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.aspnetcore.http.abstractions\2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Abstractions.dll</HintPath>
</Reference>
</ItemGroup>
<Import Project="../.build/build.proj" />
</Project
I am trying to create a simple tool to parse an xml file and if/when a certain element is found it gets the value and then executes code using that value and then the executed code outputs a new value and then it is replaced and a new XML file is saved. It has proven to be alot more difficult then it seems to be worth.
Right now I am using a combination of XML reader and XML writer. It is very verbose and I seem to be having small issues, that are way to difficult to fix. You can see an example of my previous approach and it's code here.
I am wondering if someone can help me figure out how to use Linq to XML to do this job. I need to sift through the XML of the original document looking for "ClInclude" and "ClCompile" and when they are found I need to execute code and replace those attributes string with a new value. For a better example of what I am accomplishing, you can check the post prior to the last.
I have made many attempts and decided to ditch the reader/writer for good. Can anyone help me accomplish this? Here is an attempt I have made at the Linq to XML:
string baseDir = (textBox2.Text + "\\" + safeFileName);
string vcName = Path.GetFileName(textBox1.Text);
string vcProj = Path.Combine(baseDir, vcName);
XDocument xmlDoc = XDocument.Load(textBox1.Text);
var items = from item in xmlDoc.Elements()
select item;
foreach (XElement itemElement in items)
{
if (itemElement.Name == "ClInclude")
{
// itemElement.SetElementValue("Include", "include/");
textBox3.AppendText(itemElement.Value);
}
}
xmlDoc.Save(vcProj);
Right now I am just appending them to a textbox, just to test it. I cannot seem to bring back any elements with Clinclude or ClCompile. Here is an example of the lines I am trying to get the value of and replace:
<ClCompile Include="..\..\lib\projx\conf.c" />
<ClCompile Include="..\..\lib\projx\hash.c" />
<ClCompile Include="..\..\lib\projx\init.c" />
Here is a full example of the XML I am parsing:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{57900E99-A405-49F4-83B2-0254117D041B}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>libprojx</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
<PlatformToolset>v110</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<PreprocessorDefinitions>WIN32;projx_EXPORTS;_DEBUG;_WINDOWS;_USRDLL;LIBprojx_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\Win32;..\..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>..\..\..\..\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libdirect.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;projx_EXPORTS;NDEBUG;_WINDOWS;_USRDLL;LIBprojx_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>..\..\Win32;..\..\lib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalLibraryDirectories>..\..\..\..\Debug;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>libdirect.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\..\lib\projx\conf.c" />
<ClCompile Include="..\..\lib\projx\hash.c" />
<ClCompile Include="..\..\lib\projx\init.c" />
<ClCompile Include="..\..\lib\projx\shmalloc.c" />
<ClCompile Include="..\..\lib\projx\shm\fake.c" />
<ClCompile Include="..\..\lib\projx\vector.c" />
<ClCompile Include="dllmain.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\lib\projx\conf.h" />
<ClInclude Include="..\..\lib\projx\hash.h" />
<ClInclude Include="..\..\lib\projx\shmalloc.h" />
<ClInclude Include="..\..\lib\projx\types.h" />
<ClInclude Include="..\..\lib\projx\vector.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
First you need to find your ClInclude, as I understood: var includs = xdoc.Descendants("ClInclude") will give you all ClInclude. If you need specific ClInclude with some special Include attribute value you do it like that:
var specificInclude = xdoc.Descendants("ClInclude")
.Where(inc => inc.Attribute("Include").Value == yourValue).FirstOrDefault();
Next you need to replace Include attribute value with new one like this:
specificInclude.Attribute("Include").Value = newValue;
Full sample for console app:
string xml = #"<root><ItemGroup><ClInclude id=""1""></ClInclude><ClInclude id=""2""></ClInclude></ItemGroup></root>";
var newxDoc = XDocument.Parse(xml);
Console.WriteLine("Before");
Console.WriteLine(newxDoc.ToString());
var s = newxDoc.Descendants("ClInclude").Where(b => b.Attribute("id").Value == "2").FirstOrDefault();
s.Attribute("id").Value = "3";
Console.WriteLine("After");
Console.WriteLine(newxDoc.ToString());
Console.ReadLine();
Hope that helps!