1

Test.csproj 引用System.XML并指定 TargetFrameworkVersion v4.0。 System.Xml.XmlReaderSettings已获得DtdProcessing属性,同时已弃用ProhibitDtd。要求是从一个项目构建,同时支持两个程序集。

使用 MSBuild 3.5 (c:\Windows\Microsoft.NET\Framework\v3.5\MSBuild) 构建它最终会引用 C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll (运行时版本 v2 .0.50727,版本 2.0.0.0)

使用 MSBuild 4.0 (c:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild) 构建它最终会引用 C:\Program Files\Reference Assemblies\Microsoft\Framework.NETFramework\v4.0\System.Xml.dll (运行时版本 v4.0.30319,版本 4.0.0.0)。

我尝试的解决方法是根据 TargetFrameworkVersion 在 .csproj 文件中定义一个常量。但是,TargetFrameworkVersion 不能指示将链接哪个程序集。

所以,这不起作用:

<PropertyGroup Condition=" '$(TargetFrameworkVersion)' != 'v2.0' And '$(TargetFrameworkVersion)' != 'v3.5' And '$(TargetFrameworkVersion)' != '' ">
  <DefineConstants Condition=" '$(DefineConstants)' != '' ">$(DefineConstants);</DefineConstants>
  <DefineConstants>$(DefineConstants)XMLDTDPROCESSING</DefineConstants>
</PropertyGroup>

使用此 CSharp 代码:

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);
        }
    }

阅读C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Common.targetsAssemblySearchPaths属性的评论是:

<!--
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>

我的猜测是这与GetFrameworkPaths定义为:

<!--
============================================================
                                    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>

那么,有没有一种更简单的方法可以根据System.XML正在使用的程序集来更改 CSharp 代码?如果这种方法是正确的,我应该使用什么条件来定义我的XMLDTDPROCESSING常量?

4

1 回答 1

0

这就是我最终做的事情。解析 System.XML 程序集,然后专门检查版本 2.0.0.0。

请注意,假设 System.XML 程序集路径以 System.XML 结尾。似乎没有办法将 ReferencePath 绑定回相应的 Reference。

<!-- System.XML.XmlReaderSettings changed after version 2.0.0.0.
     Define a constant to recognised that.
 -->
<Target Name="SetupXMLDtdProcessing">
  <GetAssemblyIdentity AssemblyFiles="%(ReferencePath.Identity)"
                       Condition=" '%(ReferencePath.Filename)' == 'System.XML' "
  >
    <Output TaskParameter="Assemblies" ItemName="_SystemXMLAssemblyIdentityItem" />
  </GetAssemblyIdentity>

  <PropertyGroup>
    <_SystemXMLAssemblyIdentity>%(_SystemXMLAssemblyIdentityItem.Identity)</_SystemXMLAssemblyIdentity>
  </PropertyGroup>

  <PropertyGroup Condition=" '$(_SystemXMLAssemblyIdentity)' != 'System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
                           "
  >
    <DefineConstants Condition=" '$(DefineConstants)' != '' ">$(DefineConstants);</DefineConstants>
    <DefineConstants>$(DefineConstants)XMLDTDPROCESSING</DefineConstants>
  </PropertyGroup>
</Target>

<PropertyGroup>
  <CompileDependsOn>
    SetupXMLDtdProcessing;
    $(CompileDependsOn)
  </CompileDependsOn>
</PropertyGroup>
于 2012-11-09T12:38:34.937 回答