Using Linq to XML instead of XML Reader/Writer - c#

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!

Related

WPF Desktop App using MSIX installer - Directory Not Found

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

Regex that is working in C# is not working in MSBuild

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

Condition using File::Exists not working

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>

How to add a linked file to a csproj file with MSBuild. (3.5 Framework)

I'm trying to us MSBuild to add a linked file to my .csproj file.
This is .Net Framework 3.5 (and not 4.0). I mention that because I'm seen some 4.0 specific stuff trying to manipulate the XML.
Here is what I'm starting with:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MySuperCoolClass.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
This is what I'm trying to get:
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MySuperCoolClass.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="..\..\SomeFunFolder\MyLinkFile.ext">
<Link>MyLinkFile.ext</Link>
</Content>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
I have:
MSBuild.Community.Tasks.dll
and
MSBuild.ExtensionPack.dll
available.
Any concrete help?
One liner comments like use 'MSBuild.ExtensionPack.Xml.XmlFile' won't be helpful.
But I appreciate any pointers or coded examples immensely.
Well, I opened up the code for "MSBuild.ExtensionPack.Xml.XmlFile(.cs)" and looked around.
Thank goodness for open source.
I figured out..you gotta "build it up".
And I had to add a little voodoo trick (with the "MyUniqueKeyHelper123" seen below).
I'll post here.
If you're having trouble with "MSBuild.ExtensionPack.Xml.XmlFile(.cs)", get the source code and look at it. You can figure out how to set the properties by looking at the method.
It was a little tricky at first, but figure-out-able.
<PropertyGroup>
<MSBuildExtensionPackPath Condition="'$(MSBuildExtensionPackPath)' == ''">.\ExtensionPackFiles</MSBuildExtensionPackPath>
<MSBuildExtensionPackLib>$(MSBuildExtensionPackPath)\MSBuild.ExtensionPack.dll</MSBuildExtensionPackLib>
</PropertyGroup>
<UsingTask AssemblyFile="$(MSBuildExtensionPackLib)" TaskName="MSBuild.ExtensionPack.Xml.XmlFile" />
<Target Name="XmlTest01Target">
<Message Text="MSBuildExtensionPackLib = $(MSBuildExtensionPackLib)" />
<!--
The goal is:
<ItemGroup>
<Content Include="..\..\SomeFunFolder\MyLinkFile.ext">
<Link>MyLinkFile.ext</Link>
</Content>
</ItemGroup>
-->
<!-- Define a custom namespace. I used "peanut" just to show it is any name you give it -->
<ItemGroup>
<Namespaces Include="Mynamespace">
<Prefix>peanut</Prefix>
<Uri>http://schemas.microsoft.com/developer/msbuild/2003</Uri>
</Namespaces>
</ItemGroup>
<!--
Add the <ItemGroup> (new) Element. HOWEVER, since there will probably be multiple <ItemGroup> nodes, tag it with some unique identifier. Will Clean up later.
-->
<XmlFile
TaskAction="AddElement"
Namespaces="#(Namespaces)"
File=".\MyCSharpProjectFile.csproj"
Element="ItemGroup"
Key="MyUniqueKeyHelper123"
Value ="MyUniqueValueHelper123"
XPath="//peanut:Project"
/>
<!--
Add the <Content> (new) Element. With Attribute Value.
-->
<XmlFile
TaskAction="AddElement"
File=".\MyCSharpProjectFile.csproj"
Element="Content"
Key="Include"
Value ="..\..\SomeFunFolder\MyLinkFile.ext"
Namespaces="#(Namespaces)"
XPath="//peanut:Project/peanut:ItemGroup[#MyUniqueKeyHelper123='MyUniqueValueHelper123']"
/>
<!--
Add the <Content> (new) Element. With Element Value Value.
-->
<XmlFile
TaskAction="AddElement"
File=".\MyCSharpProjectFile.csproj"
Element="Link"
InnerText ="MyLinkFile.ext"
Namespaces="#(Namespaces)"
XPath="//peanut:Project/peanut:ItemGroup[#MyUniqueKeyHelper123='MyUniqueValueHelper123']"
/>
<!--
Clean up the "unique" attribute to leave clean xml.
-->
<XmlFile
TaskAction="RemoveAttribute"
File=".\MyCSharpProjectFile.csproj"
Element="Link"
Key="MyUniqueKeyHelper123"
Namespaces="#(Namespaces)"
XPath="//peanut:Project/peanut:ItemGroup[#MyUniqueKeyHelper123='MyUniqueValueHelper123']"
/>
</Target>
Is it feasible for you to use the following?
using System;
using System.Text;
using Microsoft.Build.BuildEngine;
namespace ConsoleApplication11
{
class Program
{
static void Main(string[] args)
{
var fullPathName = #"PathToProjectFile\Project.csproj";
Project project = new Project();
project.Load(fullPathName);
var itemGroup = project.AddNewItemGroup();
var buildItem = itemGroup.AddNewItem("Content", #"..\..\SomeFunFolder\MyLinkFile.ext");
buildItem.SetMetadata("Link", "MyLinkFile.ext");
project.Save(fullPathName, Encoding.UTF8);
}
}
}

MSBuild solution with many web projects output to same directory

I'd like to build many web projects and output them to a directory such as ./output/Project1 ./output/Project2 etc. Each of these folders would contain essentially what's output to _PublishedWebsites. I've tried this:
msbuild support.sln /p:configuration=Release;DeployOnBuild=true;DeployTarget=Package;_PackageTempDir=c:/ws/code/supportsite/output/ /t:package
but it seems to overwrite the contents of the output directory with each project that's built.
Why not make target file.
XCopyWebDeploy.targets
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
<XCopyDeployWebPackage Condition=" '$(XCopyDeployWebPackage)' == '' ">false</XCopyDeployWebPackage>
</PropertyGroup>
<ItemGroup>
<ProjectFileItem Include="$(ProjectPath)"/>
</ItemGroup>
<PropertyGroup>
<!-- Make the build depend on web deploy packages -->
<BuildDependsOn Condition="$(XCopyDeployWebPackage) == 'true'">
$(BuildDependsOn);
Package;
XCopyDeployWebPackage;
</BuildDependsOn>
</PropertyGroup>
<Target Name="XCopyDeployWebPackage">
<CreateItem Include="$(ProjectDir)obj\$(Configuration)\Package\PackageTmp\**\*.*">
<Output ItemName="XCopyWebDeployPackageOutputFiles" TaskParameter="Include"/>
</CreateItem>
<CreateProperty Value="c:\ws\code\supportsite\output\%(ProjectFileItem.Filename)">
<Output PropertyName="XCopyWebDeployOutput" TaskParameter="Value"/>
</CreateProperty>
<Copy
SourceFiles="#(XCopyWebDeployPackageOutputFiles)"
DestinationFiles="#(XCopyWebDeployPackageOutputFiles->'$(XCopyWebDeployOutput)\%(RecursiveDir)%(Filename)%(Extension)')"/>
</Target>
</Project>
And import in web project(s) file.
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>
</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{BF6B6392-1398-42D3-AA90-ED87D02D351A}</ProjectGuid>
<ProjectTypeGuids>{E3E379DF-F4C6-4180-9B81-6769533ABE47};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>MvcApplication1</RootNamespace>
<AssemblyName>MvcApplication1</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<MvcBuildViews>false</MvcBuildViews>
<UseIISExpress>true</UseIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />
<IISExpressWindowsAuthentication />
<IISExpressUseClassicPipelineMode />
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
<RestorePackages>true</RestorePackages>
<!--!!!-->
<XCopyDeployWebPackage>true</XCopyDeployWebPackage>
<!--!!!-->
</PropertyGroup>
<!-- Some lines omitted -->
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<!--!!!-->
<Import Project="$(SolutionDir)\XCopyWebDeploy.targets" />
<!--!!!-->
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target> -->
</Project>

Categories