Test.csproj references System.XML
and specifies TargetFrameworkVersion v4.0.
System.Xml.XmlReaderSettings
has gained a DtdProcessing
Property, and deprecated ProhibitDtd
in the meantime.
The requirement is to build from one project, supporting both assemblies.
Building with MSBuild 3.5 (c:\Windows\Microsoft.NET\Framework\v3.5\MSBuild) it ends up referencing C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll (Runtime Version v2.0.50727, Version 2.0.0.0)
Building with MSBuild 4.0 (c:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild) it ends up referencing C:\Program Files\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Xml.dll (Runtime Version v4.0.30319, Version 4.0.0.0).
My attempted fix was to define a constant in the .csproj file based on the TargetFrameworkVersion.
However, TargetFrameworkVersion is no indicator of which assembly will be linked.
So, this doesn't work:
<PropertyGroup Condition=" '$(TargetFrameworkVersion)' != 'v2.0' And '$(TargetFrameworkVersion)' != 'v3.5' And '$(TargetFrameworkVersion)' != '' ">
<DefineConstants Condition=" '$(DefineConstants)' != '' ">$(DefineConstants);</DefineConstants>
<DefineConstants>$(DefineConstants)XMLDTDPROCESSING</DefineConstants>
</PropertyGroup>
With this CSharp code:
namespace TestVSMSBuild
{
class Program
{
static void Main(string[] args)
{
System.Xml.XmlReaderSettings readerSettings = new System.Xml.XmlReaderSettings();
#if XMLDTDPROCESSING
readerSettings.DtdProcessing = System.Xml.DtdProcessing.Ignore;
#else // !XMLDTDPROCESSING
readerSettings.ProhibitDtd = false;
#endif // XMLDTDPROCESSING
System.Console.WriteLine("Reader: '{0}'", readerSettings);
}
}
Reading C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets
the comment for the AssemblySearchPaths
property is:
<!--
The SearchPaths property is set to find assemblies in the following order:
(1) Files from current project - indicated by {CandidateAssemblyFiles}
(2) $(ReferencePath) - the reference path property, which comes from the .USER file.
(3) The hintpath from the referenced item itself, indicated by {HintPathFromItem}.
(4) The directory of MSBuild's "target" runtime from GetFrameworkPath.
The "target" runtime folder is the folder of the runtime that MSBuild is a part of.
(5) Registered assembly folders, indicated by {Registry:*,*,*}
(6) Legacy registered assembly folders, indicated by {AssemblyFolders}
(7) Look in the application's output folder (like bin\debug)
(8) Resolve to the GAC.
(9) Treat the reference's Include as if it were a real file name.
-->
<AssemblySearchPaths Condition=" '$(AssemblySearchPaths)' == '' ">
{CandidateAssemblyFiles};
$(ReferencePath);
{HintPathFromItem};
{TargetFrameworkDirectory};
{Registry:$(FrameworkRegistryBase),$(TargetFrameworkVersion),$(AssemblyFoldersSuffix)$(AssemblyFoldersExConditions)};
{AssemblyFolders};
{GAC};
{RawFileName};
$(OutDir)
</AssemblySearchPaths>
My guess is this has something to do with GetFrameworkPaths
which is defined as:
<!--
============================================================
GetFrameworkPaths
Get the paths for the .NET Framework installation directory, and the .NET Framework
SDK installation directory.
These paths are not used directly by this .targets file but are available for pre and
post build steps.
============================================================
-->
<PropertyGroup>
<Framework35Dir>@(_TargetFramework35DirectoryItem)</Framework35Dir>
<Framework30Dir>@(_TargetFramework30DirectoryItem)</Framework30Dir>
<Framework20Dir>@(_TargetFramework20DirectoryItem)</Framework20Dir>
<FrameworkDir>@(_TargetFramework20DirectoryItem)</FrameworkDir>
<FrameworkSDKDir>@(_TargetFrameworkSDKDirectoryItem)</FrameworkSDKDir>
<GetFrameworkPathsDependsOn></GetFrameworkPathsDependsOn>
</PropertyGroup>
<Target
Name="GetFrameworkPaths"
DependsOnTargets="$(GetFrameworkPathsDependsOn)">
<!-- Get the paths to all of the target .NET framework directories. -->
<GetFrameworkPath>
<Output Condition=" '$(TargetFrameworkVersion)' == 'v3.5' " TaskParameter="FrameworkVersion35Path" ItemName="_CombinedTargetFrameworkDirectoriesItem" />
<Output Condition=" '$(TargetFrameworkVersion)' == 'v3.0' or '$(TargetFrameworkVersion)' == 'v3.5' " TaskParameter="FrameworkVersion30Path" ItemName="_CombinedTargetFrameworkDirectoriesItem" />
<Output Condition=" '$(TargetFrameworkVersion)' == 'v2.0' or '$(TargetFrameworkVersion)' == 'v3.0' or '$(TargetFrameworkVersion)' == 'v3.5'" TaskParameter="FrameworkVersion20Path" ItemName="_CombinedTargetFrameworkDirectoriesItem" />
<Output TaskParameter="FrameworkVersion35Path" ItemName="_TargetFramework35DirectoryItem" />
<Output TaskParameter="FrameworkVersion30Path" ItemName="_TargetFramework30DirectoryItem" />
<Output TaskParameter="FrameworkVersion20Path" ItemName="_TargetFramework20DirectoryItem" />
</GetFrameworkPath>
<PropertyGroup>
<TargetFrameworkDirectory>@(_CombinedTargetFrameworkDirectoriesItem)</TargetFrameworkDirectory>
</PropertyGroup>
<!-- Get the path to the target .NET framework SDK directory. -->
<GetFrameworkSdkPath>
<Output TaskParameter="FrameworkSdkVersion35Path" PropertyName="TargetFrameworkSDKDirectory"/>
<Output TaskParameter="FrameworkSdkVersion35Path" ItemName="_TargetFrameworkSDKDirectoryItem"/>
</GetFrameworkSdkPath>
</Target>
So, is there an easier way to alter the CSharp code based on the System.XML
assembly being used ?
If this approach is correct, what condition should I use to define my XMLDTDPROCESSING
constant ?