Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 81 additions & 20 deletions src/MSBuild/ValidateMSBuildPackageDependencyVersions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace MSBuild
public class ValidateMSBuildPackageDependencyVersions : Task
{
[Required]
public string AppConfig { get; set; }
public ITaskItem AppConfig { get; set; }
[Required]
public string AssemblyPath { get; set; }

Expand All @@ -24,40 +24,101 @@ public class ValidateMSBuildPackageDependencyVersions : Task

public override bool Execute()
{
XmlDocument doc = new XmlDocument();
doc.Load(AppConfig);
XmlNamespaceManager namespaceManager = new(doc.NameTable);
namespaceManager.AddNamespace("asm", "urn:schemas-microsoft-com:asm.v1");
bool foundSystemValueTuple = false;
foreach (XmlElement dependentAssemblyElement in doc.DocumentElement.SelectNodes("/configuration/runtime/asm:assemblyBinding/asm:dependentAssembly[asm:assemblyIdentity][asm:bindingRedirect]", namespaceManager))

var settings = new XmlReaderSettings
{
IgnoreWhitespace = false,
IgnoreComments = false,
IgnoreProcessingInstructions = false
};

string appConfigPath = Path.GetFullPath(AppConfig.GetMetadata("OriginalItemSpec"));

using var fileStream = new FileStream(appConfigPath, FileMode.Open, FileAccess.Read);
using var reader = XmlReader.Create(fileStream, settings);
var li = (IXmlLineInfo)reader;

while (reader.Read())
{
string name = (dependentAssemblyElement.SelectSingleNode("asm:assemblyIdentity", namespaceManager) as XmlElement).GetAttribute("name");
string version = (dependentAssemblyElement.SelectSingleNode("asm:bindingRedirect", namespaceManager) as XmlElement).GetAttribute("newVersion");
if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(version) && !assembliesToIgnore.Contains(name, StringComparer.OrdinalIgnoreCase))
if (reader.NodeType == XmlNodeType.Element &&
reader.LocalName == "dependentAssembly" &&
reader.NamespaceURI == "urn:schemas-microsoft-com:asm.v1")
{
string path = Path.Combine(AssemblyPath, name + ".dll");
string assemblyVersion = AssemblyName.GetAssemblyName(path).Version.ToString();
if (!version.Equals(assemblyVersion))
string name = null;
string version = null;
int bindingRedirectLineNumber = 0;

// Parse through this dependentAssembly subtree to find assemblyIdentity and bindingRedirect
while (reader.Read())
{
// Ensure that the binding redirect is to the GAC version, but
// we still ship the version we explicitly reference to let
// API consumers bind to it at runtime.
// See https://github.com/dotnet/msbuild/issues/6976.
if (String.Equals(name, "System.ValueTuple", StringComparison.OrdinalIgnoreCase) && String.Equals(version, "4.0.0.0") && String.Equals(assemblyVersion, "4.0.3.0"))
if (reader.NodeType == XmlNodeType.EndElement &&
reader.LocalName == "dependentAssembly")
{
foundSystemValueTuple = true;
break;
}
else

if (reader.NodeType == XmlNodeType.Element)
{
Log.LogError($"Binding redirect for '{name}' redirects to a different version ({version}) than MSBuild ships ({assemblyVersion}).");
if (reader.LocalName == "assemblyIdentity")
{
name = reader.GetAttribute("name");
}
else if (reader.LocalName == "bindingRedirect")
{
reader.MoveToAttribute("newVersion");
version = reader.Value;
bindingRedirectLineNumber = li.LineNumber;

reader.MoveToElement();
}

if (name != null && version != null)
{
break;
}
}
}

if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(version) &&
!assembliesToIgnore.Contains(name, StringComparer.OrdinalIgnoreCase))
{
string path = Path.Combine(AssemblyPath, name + ".dll");
string assemblyVersion = AssemblyName.GetAssemblyName(path).Version.ToString();
if (!version.Equals(assemblyVersion))
{
// Ensure that the binding redirect is to the GAC version, but
// we still ship the version we explicitly reference to let
// API consumers bind to it at runtime.
// See https://github.com/dotnet/msbuild/issues/6976.
if (String.Equals(name, "System.ValueTuple", StringComparison.OrdinalIgnoreCase) &&
String.Equals(version, "4.0.0.0") && String.Equals(assemblyVersion, "4.0.3.0"))
{
foundSystemValueTuple = true;
}
else
{
Log.LogError(
subcategory: null,
errorCode: null,
helpKeyword: null,
file: appConfigPath,
lineNumber: bindingRedirectLineNumber,
columnNumber: 0,
endLineNumber: 0,
endColumnNumber: 0,
message: $"Binding redirect for '{name}' redirects to a different version ({version}) than MSBuild ships ({assemblyVersion}).");
}
}
}
}
}

if (!foundSystemValueTuple)
{
Log.LogError("Binding redirect for 'System.ValueTuple' missing.");
}

return !Log.HasLoggedErrors;
}
}
Expand Down